Click here to Skip to main content
15,886,077 members
Articles / Web Development / HTML

Multithreading Backup Utility

Rate me:
Please Sign up or sign in to vote.
4.89/5 (72 votes)
8 Oct 2019CPOL12 min read 237.5K   14.3K   208  
Multithreading is something we will all have to deal with sooner or later. This relatively simple application shows you how to use two threads to copy files. It is also a very handy Windows backup utility with a mirror feature, a batch mode feature, a log file feature and a help button!
' Author: Taner Riffat
' Date Written: June 2008

Imports System.Threading
Imports System.IO
Imports System.Diagnostics.Process
Imports System.Windows

Public Class Backup

    ' Declare the FileCopy class. This class will create 3 threads to copy, count and mirror files
    ' and raise events for each, so the events must be handled to update the form with status data.
    Dim WithEvents CopyFiles As FileCopy

    ' Declare delegate handlers for the copy, count, mirror and backup events
    Public Delegate Sub CopyHandler(ByVal FilePath As String, ByVal FileSize As Long, ByVal FileCount As Long)
    Public Delegate Sub CountHandler(ByVal FileCount As Long, ByVal FolderCount As Long)
    Public Delegate Sub MirrorHandler(ByVal FilePath As String, ByVal FileCount As Long, ByVal FolderCount As Long)
    Public Delegate Sub MirrorStartedHandler()
    Public Delegate Sub BackupHandler()
    Public Delegate Sub WorkingHandler()

    ' Private variables
    Private _totalFiles As Long = 0
    Private _totalFolders As Long = 0
    Private _copiedFiles As Long = 0
    Private _rootDir As String = ""
    Private _logFile As String
    Private _stopped As Boolean = False
    Private _copyStatus As String = "Status: Copying and Counting. "
    Private _deletedCount As Long = 0
    Private Sub BrowseFrom_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BrowseFrom.Click

        FolderBrowserDialog1.ShowDialog()
        FromPathTextbox.Text = FolderBrowserDialog1.SelectedPath

        If FromPathTextbox.Text <> "" And ToPathTextbox.Text <> "" Then
            StartCopy.Enabled = True
        End If

    End Sub
    Private Sub BrowseTo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BrowseTo.Click

        FolderBrowserDialog1.ShowDialog()
        ToPathTextbox.Text = FolderBrowserDialog1.SelectedPath

        If FromPathTextbox.Text <> "" And ToPathTextbox.Text <> "" Then
            StartCopy.Enabled = True
        End If

    End Sub
    Private Sub StartCopy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartCopy.Click

        ' If mirrorcopy then warn the user.
        If MirrorCopy.Checked Then
            If Not WarnUser() Then Exit Sub
        End If

        ' Reset variables
        _stopped = False

        ' Create the FileCopy class which will initiate the threads
        CopyFiles = New FileCopy

        ' Set parameter properties
        CopyFiles.MirrorCopy = MirrorCopy.CheckState
        CopyFiles.QuietLog = QuietLog.CheckState
        CopyFiles.FromPath = FromPathTextbox.Text
        CopyFiles.ToPath = ToPathTextbox.Text
        CopyFiles.InitialMessage = "*** MODE IS WINFORMS ***"
        If CopyFiles.MirrorCopy Then
            CopyFiles.InitialMessage = "*** MODE IS WINFORMS - MIRROR COPY IS SET ***"
        End If
        If CopyFiles.QuietLog Then
            CopyFiles.InitialMessage += vbCrLf & "Logging is quiet - not verbose."
        Else
            CopyFiles.InitialMessage += vbCrLf & "Logging is not quiet - its verbose."
        End If

        ' Initiate the copy, count and mirror threads from the FileCopy class
        CopyFiles.StartCopy()

        WorkingBar.Minimum = 0
        WorkingBar.Maximum = 100
        WorkingLabel.Visible = True
        WorkingBar.Visible = True

        ' Reset form controls
        StartCopy.Enabled = False
        Panel1.Enabled = False
        StopCopy.Enabled = True
        ViewLog.Enabled = True

    End Sub
    Private Sub StopCopy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StopCopy.Click

        CopyFiles.StopThreads()
        CopyFiles = Nothing

        ProgressBar1.Maximum = 0
        ProgressBar1.Value = 0

        FileStatusTextbox.Text = ""
        CopyStatusLabel.Text = "Status: Not Started"

        StartCopy.Enabled = True
        Panel1.Enabled = True
        StopCopy.Enabled = False

        WorkingLabel.Visible = False
        WorkingBar.Visible = False
        WorkingBar.Value = 0

        _copyStatus = "Status: Copying and Counting. "
        _deletedCount = 0

        ' Stopping threads (using abort) is, on occasion, prone to a time delay so use a flag to ensure
        ' any "leftover" events raised by child threads are ignored by this form (parent thread).
        _stopped = True

    End Sub
    Private Sub CopyStatus(ByVal FilePath As String, ByVal FileSize As Long, ByVal FileCount As Long)

        ' Exit if the copy has been stopped (cancelled) as a child thread may still raise one last event
        ' due to a delay that sometimes occurs when the abort method to stop a child thread is used.
        If _stopped Then Exit Sub

        ' Show current file
        FileStatusTextbox.Text = "Copying: " & FilePath & ". Filesize is " & FileSize.ToString & " megabytes."
        If MirrorCopy.Checked Then
            FileStatusTextbox.Text += vbCrLf & vbCrLf & "WARNING. This is a mirror copy, it will DELETE files from the To Folder."
            FileStatusTextbox.Text += "Press the Cancel Copy button now if you don't want to do a mirror copy!"
        End If

        ' Update progressbar
        If ProgressBar1.Maximum <> 0 Then ProgressBar1.Value = _totalFiles - (_totalFiles - FileCount)

    End Sub
    Private Sub CopyCompleted(ByVal FilePath As String, ByVal FileSize As Long, ByVal FileCount As Long)

        CopyStatusLabel.Text = "Status: Copy Finsihed. Copied " + _totalFiles.ToString + " files in " + _totalFolders.ToString + " folders."
        FileStatusTextbox.Text = "Copy completed successfully."
        ProgressBar1.Value = ProgressBar1.Maximum

    End Sub
    Private Sub CountStatus(ByVal FileCount As Long, ByVal FolderCount As Long)
        ' Exit if the copy has been stopped (cancelled) as a child thread may still raise one last event
        ' due to a delay that sometimes occurs when the abort method to stop a child thread is used.
        If _stopped Then Exit Sub

        ' Display current count
        CopyStatusLabel.Text = _copyStatus & "So far there are " + FileCount.ToString + " files in " + FolderCount.ToString + " folders."

    End Sub
    Private Sub CountCompleted(ByVal FileCount As Long, ByVal FolderCount As Long)

        ' Display current count
        _copyStatus = "Status: Copying. "
        CopyStatusLabel.Text = _copyStatus & "There are " + FileCount.ToString + " files in " + FolderCount.ToString + " folders."

        ' Save totals when finished counting for CopyStatus()
        _totalFiles = FileCount
        _totalFolders = FolderCount

        ProgressBar1.Maximum = _totalFiles
        ProgressBar1.Value = 0

    End Sub
    Private Sub MirrorStarted()

        _copyStatus = "Status: Mirroring. Counting files first."
        FileStatusTextbox.Text = "No files to process just yet, please wait." & vbCrLf & vbCrLf
        FileStatusTextbox.Text += "WARNING: This is a mirror copy and it will DELETE files from the To Folder! "
        FileStatusTextbox.Text += "Check that your From Folder and To Folder is correct. You can prevent files from being "
        FileStatusTextbox.Text += "deleted if you press the Cancel Copy button now!! "
        ProgressBar1.Value = 0

    End Sub
    Private Sub MirrorStatus(ByVal FilePath As String, ByVal FileCount As Long, ByVal FolderCount As Long)

        ' Exit if the copy has been stopped (cancelled) as a child thread may still raise one last event
        ' due to a delay that sometimes occurs when the abort method to stop a child thread is used.
        If _stopped Then Exit Sub

        CopyStatusLabel.Text = "Status: Mirroring. Looking for redundant files and folders. Files left to read " + (_totalFiles - FileCount).ToString

        If FilePath <> "" Then
            FileStatusTextbox.Text = "Mirroring: Found and deleted file " & FilePath.ToString & " from To Folder."
            _deletedCount += 1
        End If

        ' Update progressbar
        If ProgressBar1.Maximum <> 0 Then ProgressBar1.Value = _totalFiles - (_totalFiles - FileCount)

    End Sub
    Private Sub MirrorCompleted(ByVal FilePath As String, ByVal FolderCount As Long, ByVal FileCount As Long)

        ProgressBar1.Value = ProgressBar1.Maximum
        CopyStatusLabel.Text = "Mirror copy completed. Folders read " + FolderCount.ToString + ". Files read " + FileCount.ToString
        FileStatusTextbox.Text = "Mirror copy deleted " & _deletedCount & " files from the " & """" & "To Folder" & """" & "."

    End Sub
    Private Sub BackupCompleted()

        CopyStatusLabel.Text = "Backup copy completed."

        CopyFiles.StopThreads()
        CopyFiles = Nothing

        WorkingLabel.Visible = False
        WorkingBar.Visible = False
        WorkingBar.Value = 0

        StartCopy.Enabled = True
        Panel1.Enabled = True
        StopCopy.Enabled = False

    End Sub
    Private Sub CopyFiles_CopyStatus(ByVal sender As Object, ByVal e As BackupEventArgs) Handles CopyFiles.CopyStatus
        ' BeginInvoke causes asynchronous execution to begin at the address
        ' specified by the delegate. Simply put, it transfers execution of 
        ' this method back to the main thread. Any parameters required by 
        ' the method contained at the delegate are wrapped in an object and 
        ' passed.

        Me.BeginInvoke(New CopyHandler(AddressOf CopyStatus), New Object() {e.FilePath, e.FileSize, e.FileCount})

    End Sub
    Private Sub CopyFiles_CopyCompleted(ByVal sender As Object, ByVal e As BackupEventArgs) Handles CopyFiles.CopyCompleted
        ' BeginInvoke causes asynchronous execution to begin at the address
        ' specified by the delegate. Simply put, it transfers execution of 
        ' this method back to the main thread. Any parameters required by 
        ' the method contained at the delegate are wrapped in an object and 
        ' passed.

        Me.BeginInvoke(New CopyHandler(AddressOf CopyCompleted), New Object() {e.FilePath, e.FileSize, e.FileCount})

    End Sub

    Private Sub CopyFiles_CountStatus(ByVal sender As Object, ByVal e As BackupEventArgs) Handles CopyFiles.CountStatus
        ' BeginInvoke causes asynchronous execution to begin at the address
        ' specified by the delegate. Simply put, it transfers execution of 
        ' this method back to the main thread. Any parameters required by 
        ' the method contained at the delegate are wrapped in an object and 
        ' passed.

        Me.BeginInvoke(New CountHandler(AddressOf CountStatus), New Object() {e.FileCount, e.FolderCount})

    End Sub
    Private Sub CopyFiles_CountCompleted(ByVal sender As Object, ByVal e As BackupEventArgs) Handles CopyFiles.CountCompleted
        ' BeginInvoke causes asynchronous execution to begin at the address
        ' specified by the delegate. Simply put, it transfers execution of 
        ' this method back to the main thread. Any parameters required by 
        ' the method contained at the delegate are wrapped in an object and 
        ' passed.

        Me.BeginInvoke(New CountHandler(AddressOf CountCompleted), New Object() {e.FileCount, e.FolderCount})

    End Sub

    Private Sub CopyFiles_MirrorStarted() Handles CopyFiles.MirrorStarted
        ' BeginInvoke causes asynchronous execution to begin at the address
        ' specified by the delegate. Simply put, it transfers execution of 
        ' this method back to the main thread. Any parameters required by 
        ' the method contained at the delegate are wrapped in an object and 
        ' passed.

        Me.BeginInvoke(New MirrorStartedHandler(AddressOf MirrorStarted))
    End Sub
    Private Sub CopyFiles_MirrorStatus(ByVal sender As Object, ByVal e As BackupEventArgs) Handles CopyFiles.MirrorStatus
        ' BeginInvoke causes asynchronous execution to begin at the address
        ' specified by the delegate. Simply put, it transfers execution of 
        ' this method back to the main thread. Any parameters required by 
        ' the method contained at the delegate are wrapped in an object and 
        ' passed.

        Me.BeginInvoke(New MirrorHandler(AddressOf MirrorStatus), New Object() {e.FilePath, e.FileCount, e.FolderCount})
    End Sub
    Private Sub CopyFiles_MirrorCompleted(ByVal sender As Object, ByVal e As BackupEventArgs) Handles CopyFiles.MirrorCompleted
        ' BeginInvoke causes asynchronous execution to begin at the address
        ' specified by the delegate. Simply put, it transfers execution of 
        ' this method back to the main thread. Any parameters required by 
        ' the method contained at the delegate are wrapped in an object and 
        ' passed.

        Me.BeginInvoke(New MirrorHandler(AddressOf MirrorCompleted), New Object() {e.FilePath, e.FileCount, e.FolderCount})
    End Sub
    Private Sub CopyFiles_BackupCompleted(ByVal sender As Object, ByVal e As BackupEventArgs) Handles CopyFiles.BackupCompleted
        ' BeginInvoke causes asynchronous execution to begin at the address
        ' specified by the delegate. Simply put, it transfers execution of 
        ' this method back to the main thread. Any parameters required by 
        ' the method contained at the delegate are wrapped in an object and 
        ' passed.

        Me.BeginInvoke(New BackupHandler(AddressOf BackupCompleted))
    End Sub
    Private Sub ViewLog_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ViewLog.Click

        Try
            Start(_logFile)
        Catch ex As System.ComponentModel.Win32Exception
            MessageBox.Show("Log file has not been created because there are no errors")
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try

    End Sub
    Private Sub Help_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Help.Click

        Try
            Process.Start("Help.pdf")
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try

    End Sub
    Private Function WarnUser() As Boolean

        ' If the "Dont show this warning message again" has not been checked then MirrorWarning
        ' will be True, so show the mirror warning dialog 
        If My.Settings.MirrorWarning Then
            ' Show the warning dialog
            Dim WarnForm As New MirrorWarning
            WarnForm.ShowDialog()


            If WarnForm.MirrorCopy Then
                ' Means the user clicked "YES" to running the mirror copy
                WarnForm.Close()
                Return True
            Else
                ' Means the user clicked "NO" to running the mirror copy
                WarnForm.Close()
                Return False
            End If
        End If

        ' If the "Dont show this warning message again" has been checked on a previous occassion
        ' then return True to indicate the user has been warned and its okay to start the mirror copy.
        Return True

    End Function

    Private Sub Backup_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Me.CenterToScreen()
    End Sub

    Private Sub CopyFiles_LogFileCreated(ByVal sender As Object, ByVal LogFileName As String) Handles CopyFiles.LogFileCreated
        _logFile = LogFileName
        ViewLog.Enabled = True
    End Sub

    'Private Sub Working_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles Working.Elapsed

    '    'Me.BeginInvoke(New WorkingHandler(AddressOf WorkingStatus))

    'End Sub
    'Private Sub WorkingStatus()

    '    'If WorkingBar.Value < 100 Then
    '    '    WorkingBar.Value += 10
    '    'Else
    '    '    WorkingBar.Value = 0
    '    'End If

    'End Sub
End Class

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Nice people only.
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions