using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO; using System.Threading; namespace DataBackup ...{ publicpartialclass Backup : Form ...{ public Backup() ...{ InitializeComponent(); m_EventStopThread =new ManualResetEvent(false); m_EventThreadStopped =new ManualResetEvent(false); m_WorkingFinished =new WorkingFinished(this.WorkingThreadFinished); m_UpdateInfo =new UpdateInfoCallback(this.UpdateInfo); } privatevoid btnCancel_Click(object sender, EventArgs e) ...{ this.Close(); } privatevoid btnSrcBrowse_Click(object sender, EventArgs e) ...{ folderBrowserDialog.ShowNewFolderButton =false; folderBrowserDialog.Description ="Please select source folder you want to copy from"; if (folderBrowserDialog.ShowDialog() == DialogResult.OK) ...{ textSource.Text = folderBrowserDialog.SelectedPath; } } privatevoid btnDstBrowse_Click(object sender, EventArgs e) ...{ folderBrowserDialog.ShowNewFolderButton =true; folderBrowserDialog.Description ="Please select destination folder you want to copy to"; if (folderBrowserDialog.ShowDialog() == DialogResult.OK) ...{ textDestination.Text = folderBrowserDialog.SelectedPath; } } privatevoid Backup_Load(object sender, EventArgs e) ...{ pnlSelect.Visible =true; pnlProgress.Visible =false; pnlSelect.Top =0; pnlSelect.Left =0; this.Width = pnlSelect.Width +2* SystemInformation.BorderSize.Width; this.Height = pnlSelect.Height +2* SystemInformation.BorderSize.Height + SystemInformation.CaptionHeight; } privatevoid btnOK_Click(object sender, EventArgs e) ...{ if (!Directory.Exists(textSource.Text)) ...{ textSource.Focus(); return; } if (textDestination.Text.Length <3) ...{ textDestination.Focus(); return; } if (!VerifyParameters(textSource.Text, textDestination.Text)) ...{ textSource.Focus(); return; } pnlSelect.Visible =false; pnlProgress.Visible =true; pnlProgress.Top =0; pnlProgress.Left =0; progressBar.Value =0; this.Width = pnlProgress.Width +2* SystemInformation.BorderSize.Width; this.Height = pnlProgress.Height +2* SystemInformation.BorderSize.Height + SystemInformation.CaptionHeight; //create and reset events //moved to part after InitializeComponent(); //m_EventStopThread = new ManualResetEvent(false); //m_EventThreadStopped = new ManualResetEvent(false); //m_WorkingFinished = new WorkingFinished(this.WorkingThreadFinished); //m_UpdateProgressbar = new UpdateProgressbarCallback(this.UpdateProgressBar); m_EventStopThread.Reset(); m_EventThreadStopped.Reset(); m_EventThreadStopped.Reset(); //Create working thread instance m_WorkingThread =new Thread(new ThreadStart(this.StartWorkingThread)); m_WorkingThread.Name ="Data Backup"; m_WorkingThread.Start(); } privatebool VerifyParameters(string srcFolder, string dstFolder) ...{ //initialize if ((srcFolder =="") | (!Directory.Exists(srcFolder))) returnfalse; if (dstFolder =="") returnfalse; if (!Directory.Exists(dstFolder)) ...{ Directory.CreateDirectory(dstFolder); if (!Directory.Exists(dstFolder)) returnfalse; } returntrue; } privatevoid btnAbort_Click(object sender, EventArgs e) ...{ if (MessageBox.Show("Would you like to cancel data backup?", "Information", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes) ...{ StopThread(); m_WorkingThread =null; this.Close(); } } //delegate used to call mainForm functions from other thread // //This delegate enables asynchronous calls for setting //the propertites of Progressbar Control publicdelegatevoid WorkingFinished(); publicdelegatevoid UpdateInfoCallback(string Filename, int maxNum, int curNum); //private Worker workerObject = null; private Thread m_WorkingThread =null; public WorkingFinished m_WorkingFinished; public UpdateInfoCallback m_UpdateInfo; private ManualResetEvent m_EventStopThread; private ManualResetEvent m_EventThreadStopped; //this function will start after method Thread.Start() is being called; privatevoid StartWorkingThread() ...{ //start another thread to start long process DataBackupThread myDataBackupThread =new DataBackupThread(m_EventStopThread, m_EventThreadStopped, this, this.textSource.Text, this.textDestination.Text); myDataBackupThread.Working(); } //clear variable after Thread finished //called from worker thread using delegate and control.Invoke // privatevoid WorkingThreadFinished() ...{ MessageBox.Show("Data backup finished.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); m_WorkingThread =null; this.Close(); } //called by thread //If the calling thread is the same as the thread that created the control, //the property of control is set directly. // //If the calling thread is different from the thread that created // the control, this method creates a callback and calls itself asynchronously //using the Invoke method privatevoid UpdateInfo(string Filename, int maxNum, int curNum) ...{ this.progressBar.Maximum = maxNum; this.progressBar.Value = curNum; this.lbFile.Text = Path.GetFileName(Filename); } // Stop worker thread if it is running. // Called when user presses Stop button of form is closed. privatevoid StopThread() ...{ if (m_WorkingThread !=null&& m_WorkingThread.IsAlive) // thread is active ...{ // set event "Stop" m_EventStopThread.Set(); // wait when thread will stop or finish while (m_WorkingThread.IsAlive) ...{ // We cannot use here infinite wait because our thread // makes syncronous calls to main form, this will cause deadlock. // Instead of this we wait for event some appropriate time // (and by the way give time to worker thread) and // process events. These events may contain Invoke calls. if (WaitHandle.WaitAll( (new ManualResetEvent[] ...{ m_EventThreadStopped }), 100, true)) ...{ break; } Application.DoEvents(); } } } privatevoid Backup_FormClosing(object sender, FormClosingEventArgs e) ...{ StopThread(); } } /**////<summary> /// Class handle data backup which runs in working thread /// and makes synchronous user UI operations. ///</summary> publicclass DataBackupThread ...{ Members#region Members // Main thread sets this event to stop worker thread: ManualResetEvent m_EventStop; // Worker thread sets this event when it is stopped: ManualResetEvent m_EventStopped; // Reference to main form used to make syncronous user interface calls: Backup m_form; string m_srcFolder; string m_dstFolder; #endregion Constructor#region Constructor public DataBackupThread(ManualResetEvent eventStop, ManualResetEvent eventStopped, Backup form, string srcFolder, string dstFolder) ...{ m_EventStop = eventStop; m_EventStopped = eventStopped; m_form = form; m_srcFolder = srcFolder; m_dstFolder = dstFolder; } #endregion Function Working#region Function Working //function works in working thread and //take a long time to finish publicvoid Working() ...{ string[] files = Directory.GetFiles(m_srcFolder); //iterate work for (int i =0; i < files.Length; i++) ...{ try ...{ string srcFile = files[i]; string dstFile = Path.Combine(m_dstFolder, Path.GetFileName(files[i])); //Make synchronous call to main form //UpdateInfo in mainForm runs in another thread //If we want to make call asynchronously, use BeginInvoke m_form.Invoke(m_form.m_UpdateInfo, new Object[] ...{ srcFile, files.Length, i }); File.Copy(srcFile, dstFile, true); i++; Thread.Sleep(1000); //check is thread is asked to terminated if (m_EventStop.WaitOne(0,true)) ...{ // clean-up operations may be placed here // ... // inform main thread that this thread stopped m_EventStopped.Set(); return; } } catch//() ...{ break; } } // Make asynchronous call to main form // to inform it that thread finished m_form.Invoke(m_form.m_WorkingFinished, null); } #endregion } }