Introduction
This article is an example of creating a new thread and passing arguments to a
LongRunningProcess
while updating a progress bar on the main thread.
Background
This article is a follow up to an article by this title published 4 May 2011. The original article was an attempt to find a solution. The current article is a final solution that has been tested for about six months.
Using the code
The code is slightly abstracted but should run when modified for the parameters of a specific process. In this example the process encrypts file1
to file2 and requires three additional parameters as inputs. The process returns 0 if there are no errors and a nonzero value if there is an error. The example code provides
for a cancel button. This code is applicable for very large files and when a process does not provide for intermediate returns to update a progress bar. The code is divided
into two classes: a main thread class and a thread wrapper which provides for starting a new thread and returning a completion value. An additional class includes a thread
wrapper for getting the hash of a file. This is included to demonstrate returning data instead of an integer completion value.
Option Strict Off
Option Explicit On
Imports VB = Microsoft.VisualBasic
Imports CryptoSysAPI
Imports System
Imports System.IO
Imports System.Threading
Public Delegate Sub CallbackToEnc(ByVal var1 As Integer)
Public Delegate Sub CallbackToHash(ByVal fileHash As String)
Public Class Protect
Public rtnBlfResult As Integer
Public Shared Sub ResultCallback(ByVal var1 As Integer)
CProtect.rtnBlfResult = var1
End Sub
Public Function Encrypter(ByVal file1 As String, _
ByVal file2 As String, _
ByVal param1 As String, _
ByVal param2 As Integer, _
ByVal param3 As String) As Short
Dim iAbortLock As Boolean = False
Dim time1 As Single = 0
Dim time2 As Single = 0
CProtect.rtnBlfResult = -2
Dim tw1 As New TWrapEnc(file1, _
file2, _
param1, _
param2, _
param3, _
New CallbackToEnc(AddressOf ResultCallback))
tw1.start()
T1: time2 = VB.Timer
If cancelBttnSequence = 3 Then
If iAbortLock = False Then
tw1.thread.Abort()
iAbortLock = True
time1 = VB.Timer
End If
If tw1.thread.ThreadState = System.Threading.ThreadState.Stopped _
Then GoTo T2
If time1 > 0 And (VB.Timer - time1) > 5 Then GoTo T2a
If (VB.Timer - time1) < 0 Then time1 = VB.Timer
End If
If (VB.Timer - time2) < 0 Then time2 = VB.Timer
While (VB.Timer - time2) < 1
SyncLock tw1.rtnLockEnc
If CProtect.rtnBlfResult = -1 Then GoTo T2
End SyncLock
End While
UpdatePgrBar()
GoTo T1
T2: tw1.join()
T2a: tw1 = Nothing
rtnBlfResult = CProtect.rtnBlfResult
If rtnBlfResult = 0 Then
Encrypter = -1
ElseIf iAbortLock = True Then
Encrypter = -2
Else
Encrypter = 0
End If
End Function
Public Shared Sub UpdatePgrBar()
End Sub
End Class
Public Class TWrapEnc
Private fileX1 As String
Private fileX2 As String
Private paramX1 As String
Private paramX2 As Integer
Private paramX3 As String
Private blfRtnParam As Integer = -1
Private callBack As CallbackToEnc
Public rtnLockEnc As New Object
Public thread As System.Threading.Thread
Public Sub New(ByVal file1 As String, _
ByVal file2 As String, _
ByVal param1 As String, _
ByVal param2 As Integer, _
ByVal param3 As String, _
ByVal callBackDelegate As CallbackToEnc)
fileX1 = file1
fileX2 = file2
paramX1 = param1
paramX2 = param2
paramX3 = param3
callBack = callBackDelegate
thread = New System.Threading.Thread(AddressOf body)
End Sub
Public Sub start()
Me.thread.Start()
End Sub
Public Sub join()
Me.thread.Join()
End Sub
Public Sub body()
On Error GoTo E1
Me.blfRtnParam = Blowfish.FileEncrypt(Me.fileX1, Me.fileX2, _
Me.paramX1, Me.paramX2, _
Me.paramX3)
E1: SyncLock rtnLockEnc
If Not callBack Is Nothing Then callBack(Me.blfRtnParam)
End SyncLock
Me.fileX1 = ""
Me.fileX2 = ""
Me.paramX1 = ""
End Sub
End Class
Public Class ThreadWrapperHash
Private fileNameParam As String
Private callback As CallbackToHash
Private fileHashRtnParam As String
Public rtnLockHash As New Object
Public thread As System.Threading.Thread
Public Sub New(ByVal fileName As String, _
ByVal callbackDelegate As CallbackToHash)
fileNameParam = fileName
callback = callbackDelegate
thread = New System.Threading.Thread(AddressOf Body)
End Sub
Public Sub start()
Me.thread.Start()
End Sub
Public Sub join()
Me.thread.Join()
End Sub
Public Sub Body()
On Error GoTo CallB
Me.fileHashRtnParam = Sha256.FileHexHash(Me.fileNameParam)
CallB: SyncLock rtnLockHash
If Not callback Is Nothing Then callback(Me.fileHashRtnParam)
End SyncLock
Me.fileNameParam = ""
End Sub
End Class
Points of Interest
Thank you Marcus Kramer and SAKryukov for help on my initial attempts at this problem.
History
- First attempts at a solution published 4 May 2011.
Visual Basic.net application developer on Visual Studio since 2000, California and Pacific Coast.