title: VB.NET - Doing work in separate thread to prevent Form from hanging
body: <p>I have a really simple form with a button that fires a Sub I created which gathers data from ActiveDirectory and adds it to an Excel Sheet.</p>
  
  <p>The problem is, when I click this button the whole form hangs. So I figured the operation that gathers the data and adding it to the Excel sheet should be run in it's own thread, so that the form won't hang. Possibly it would be great to add a progressbar as well.
  The progressbar however is located at the Main userform that starts up once the projects is run.</p>
  
  <p>What do I need to do in order to get this the way I want?</p>
  
  <p>Edit: Added some of my code. I've got one MainForm.vb and one CodeFile.vb.
  I want most of the code in the CodeFile.vb so it's tidier.</p>
  
  <p>MainForm.vb</p>
  
  <pre><code>Imports User_edit.CodeFile
  Imports System.ComponentModel
  
  Public Class MainForm
      Private Sub btnImportData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnImportData.Click
          If MyBackgroundWorker.IsBusy &lt;&gt; True Then
              MyBackgroundWorker.RunWorkerAsync()
          End If
      End Sub
  
      Private Sub BackgroundWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles MyBackgroundWorker.DoWork
          ExportADUsers()
      End Sub
  
      Private Sub BackgroundWorker_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles MyBackgroundWorker.ProgressChanged
          statusBarLabel.Text = (e.ProgressPercentage.ToString)
      End Sub
  
      Private Sub BackgroundWorker_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles MyBackgroundWorker.RunWorkerCompleted
          statusBarLabel.Text = "Finished"
      End Sub
  End Class
  </code></pre>
  
  <p>CodeFile.vb</p>
  
  <pre><code>Imports System.DirectoryServices
  Imports System.ComponentModel
  Imports System.Threading
  
  Module CodeFile
      Public Sub ExportADUsers()
          MainForm.MyBackgroundWorker.WorkerReportsProgress = True
          MainForm.MyBackgroundWorker.WorkerSupportsCancellation = True
  
          Dim i As Integer
  
          Dim objRootDSE, strRoot, strfilter, strAttributes, strScope
              objRootDSE = GetObject("LDAP://RootDSE")
              strRoot = objRootDSE.GET("DefaultNamingContext")
              strfilter = "(&amp;(objectCategory=Person)(objectClass=User))"
              strAttributes = "mail,userPrincipalName,givenName,sn," &amp; _
                "initials,displayName,physicalDeliveryOfficeName," &amp; _
                "telephoneNumber,mail,wWWHomePage,profilePath," &amp; _
                "scriptPath,homeDirectory,homeDrive,title,department," &amp; _
                "company,manager,homePhone,pager,mobile," &amp; _
                "facsimileTelephoneNumber,ipphone,info," &amp; _
                "streetAddress,postOfficeBox,l,st,postalCode,c"
              'Scope of the search.  Change to "onelevel" if you didn't want to search child OU's
              MainForm.statusBarLabel.Text = "Collecting data"
          strScope = "subtree"
  
              Dim cn, cmd, rs
              cn = CreateObject("ADODB.Connection")
              cmd = CreateObject("ADODB.Command")
  
              cn.open("Provider=ADsDSOObject;")
              cmd.ActiveConnection = cn
              cmd.commandtext = "&lt;LDAP://" &amp; strRoot &amp; "&gt;;" &amp; strfilter &amp; ";" &amp; _
                                  strAttributes &amp; ";" &amp; strScope
  
              rs = cmd.EXECUTE
  
              Dim objExcel, objWB, objSheet
  
              objExcel = CreateObject("Excel.Application")
              objWB = objExcel.Workbooks.Add
          objSheet = objWB.Worksheets(1)
  
          For i = 0 To rs.Fields.Count - 1
              MainForm.MyBackgroundWorker.ReportProgress(i * 10)
              objSheet.Cells(1, i + 1).Value = rs.Fields(i).Name
              objSheet.Cells(1, i + 1).Font.Bold = True
          Next
  
              Dim strExportFile
              strExportFile = "C:\users\vsando\desktop\export.xls"
  
              objSheet.Range("A2").CopyFromRecordset(rs)
              objSheet.SaveAs(strExportFile)
  
              'Clean up
              rs.Close()
              cn.Close()
              objSheet = Nothing
              objWB = Nothing
              objExcel.Quit()
              objExcel = Nothing
  
      End Sub
  </code></pre>
  
  <p>Notice the <code>ExportFromAD</code> Sub I've got in the <code>CodeFile.vb</code>. This is what is actually doing the work. In the For each loop that adds data to the Excel is where I've put the <code>MainForm.MyBackgroundWorker.ReportProgress(i * 10)</code>. </p>
  
  <p>Problem is, it doesn't actually update the label on the form. Which I find pretty weird because the form isn't really hanging or anything. Is it trying to access a different thread or something? Meaning, the form is run on it's own thread which can't be accessed from my second thread?</p>