VB.NET AddHandler создает новый экземпляр формы. Вызывающий нулевой делегат
Эта тема была помечена как дубликат, потому что я сталкивался с этой проблемой раньше и задавал вопрос раньше. Теперь я обычно знаю, как ее решить (т. Е. Используя переменную, указывающую на экземпляр формы вместо ее имени). Однако на этот раз это моя форма запуска по умолчанию, на которую мне нужно сослаться. Так что нет переменной, хранящей ее экземпляр, и я не знаю, как я могу ссылаться на существующий экземпляр без нее.
У меня есть 2 формы (frmMain и frmStatus), я создаю экземпляр frmStatus и сохраняю его в переменной statusDialog в frmMain. Затем я создаю новый поток (для моего класса ADSearcher), который запускает события, которые затем используют делегат для вызова подпрограмм в statusDialog. Поток ADSearcher также создает несколько других потоков (для моего потока ComputerSearcher), которые также должны вызывать события, которые будут использовать делегат для вызова подпрограмм в statusDialog.
Проблема в темах ComputerSearcher. Строки AddHandler, кажется, создают новый экземпляр frmMain, что означает, что statusDialog имеет значение Nothing/Null. Почему AddHandler создает новый экземпляр формы и есть ли способ заставить его использовать правильный экземпляр?
Причина, по которой я думаю, что это создает новый экземпляр, заключается в том, что когда я выполняю пошаговый код, он выполняет первую строку AddHandler, а затем пошагово проходит через объявления переменных в верхней части frmMain (вне каких-либо подпрограмм), и в этом случае statusDialog становится Nothing.
Отправной точкой является Private Sub mnuSync_ADSync_Click(...). Это создает первый поток и экземпляр класса. Я попытался предоставить достаточно кода, чтобы вы могли увидеть, что происходит, не публикуя огромное эссе. Если вам нужен дополнительный код, пожалуйста, спросите.
Заранее спасибо,
frmMain
Dim statusDialog As frmStatus 'Used to create an instance of the status dialog
Private Sub mnuSync_SyncAD_Click(sender As Object, e As EventArgs) Handles mnuSync_SyncAD.Click
With adSync
.RootPath = "LDAP://domain.com"
.FilterString = "(objectCategory=organizationalUnit)"
'### TO DO: Replace .UserID and .Password values with a stored value
If Not integratedAuth Then
.UserID = "...."
.Password = "...."
End If
.PageSize = 5
.PropertiesToLoad = New String() {"cn", "name", "distinguishedName", "dNSHostName", "objectCategory", "objectGUID"}
'Create the status dialog
statusDialog = New frmStatus
ThreadPool.QueueUserWorkItem(AddressOf .StartSearch)
statusDialog.ShowDialog()
End With
End Sub
'[ADSearcher Events]
Private Delegate Sub displayOUStatus(ByVal ousFound As Integer)
Private Sub adSync_OUResultFound(ByVal ousFound As Integer) Handles adSync.OUResultFound
Dim updateStatus As New displayOUStatus(AddressOf statusDialog.UpdateOUSearcherStatus)
Me.Invoke(updateStatus, New Object() {ousFound})
End Sub
Private Delegate Sub displayResult(ByVal node As TreeNode)
Private Delegate Sub findMACAddresses(ByVal compCollection As ComputerCollection)
Private Sub adSync_SearchCompleted(ByVal ouNodes As TreeNode) Handles adSync.SearchCompleted
Dim display As New displayResult(AddressOf AddOUToTreeView)
Me.Invoke(display, New Object() {ouNodes})
'Check for any computers which are no longer in Active Directory
For Each compComparison As String In compGUIDComparison
Dim query = From comp As Computer In computers Where comp.GUID = compComparison Select comp
'If this computer is no longer in Active Directory remove it
If query.Count > 0 Then
computers.Remove(query(0))
End If
Next
Dim macAddresses As New findMACAddresses(AddressOf GetMacAddresses)
Me.Invoke(macAddresses, New Object() {computers})
End Sub
'[/ADSearcher Events]
'[ComputerSearcher Events]
Private Delegate Sub displayCompStatus(ByVal pcsFound As Integer)
Public Sub adSync_CompResultFound(ByVal pcsFound As Integer)
Dim updateStatus As New displayCompStatus(AddressOf statusDialog.UpdateCompSearcherStatus)
Me.Invoke(updateStatus, New Object() {pcsFound})
End Sub
Private Delegate Sub newComputer(ByVal computer As Computer)
Public Sub adSync_ComputerFound(ByVal name As String, ByVal fqdn As String, ByVal path As String, ByVal guid As String)
Dim computer As New Computer
computer.Name = name
computer.FQDN = fqdn
computer.Path = path
computer.GUID = guid
compGUIDComparison.Add(guid)
Dim query = From comp As Computer In computers Where comp.GUID = computer.GUID Select comp
If query.Count <= 0 Then 'If the computer hasn't already been discovered add it to the collection
If Me.InvokeRequired Then
Dim pc As New newComputer(AddressOf Me.computers.Add)
Me.Invoke(pc, computer)
Else
computers.Add(computer)
End If
End If
End Sub
'[/ComputerSearcher Events]
ADSearcher Class
Sub New()
SearchScope = DirectoryServices.SearchScope.OneLevel
'Create reset events for the ComputerSearcher class threads
For i As Integer = 0 To compSearchThreads.Count - 1
compSearchThreads(i) = New ManualResetEvent(True)
Next
End Sub
<MTAThread()>
Public Sub StartSearch()
#If Not Debug Then
Try
#End If
Dim rootEntry As New DirectoryEntry(RootPath)
Dim rootNode As New TreeNode(rootEntry.Name)
rootNode.Name = rootEntry.Path
If Not IntegratedAuthentication Then
rootEntry.Username = UserID
rootEntry.Password = Password
End If
Dim searcher As New DirectorySearcher(rootEntry)
searcher.PropertiesToLoad.AddRange(PropertiesToLoad)
searcher.SearchScope = SearchScope
searcher.PageSize = PageSize
searcher.ServerTimeLimit = New TimeSpan(0, 10, 0)
searcher.Filter = FilterString
Dim queryResults As SearchResultCollection
queryResults = searcher.FindAll()
Dim result As SearchResult
For Each result In queryResults
Dim freeThread As Integer = WaitHandle.WaitAny(compSearchThreads)
compSearchInstances(freeThread) = New ComputerSearcher(compSearchThreads(freeThread))
With compSearchInstances(freeThread)
.FilterString = "(objectCategory=computer)"
If Not IntegratedAuthentication Then
.UserID = UserID
.Password = Password
End If
.PageSize = PageSize
.SearchScope = SearchScope
.PropertiesToLoad = PropertiesToLoad
End With
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf compSearchInstances(freeThread).FindComputers), result)
Dim childNode As New TreeNode(CStr(result.Properties("name")(0)))
childNode.Name = result.Path
childNode.Tag = result.Properties("objectGUID")(0)
rootNode.Nodes.Add(SearchSub(result, childNode))
ouResultCount += 1
RaiseEvent OUResultFound(ouResultCount)
Next
WaitHandle.WaitAll(compSearchThreads)
RaiseEvent SearchCompleted(rootNode)
ouResultCount = 0 'Reset the result count
#If Not Debug Then
Catch Ex as Exception
MsgBox(ex.Message, MsgBoxStyle.Critical)
End Try
#End If
ComputerSearcher Class
Sub New(ByVal doneEvent As ManualResetEvent)
_doneEvent = doneEvent
'Add Event Handler
AddHandler Me.ComputerFound, AddressOf frmMain.adSync_ComputerFound
AddHandler Me.IncrementCompResult, AddressOf frmMain.adSync_CompResultFound
End Sub
Public Sub FindComputers(ByVal parent As SearchResult)
#If Not Debug Then
Try
#End If
_doneEvent.Reset() 'Signal that the thread is working
Dim subEntry As New DirectoryEntry(parent.Path)
If Not IntegratedAuthentication Then
subEntry.Username = UserID
subEntry.Password = Password
End If
Dim searcher As New DirectorySearcher(subEntry)
searcher.PropertiesToLoad.AddRange(PropertiesToLoad)
searcher.SearchScope = SearchScope
searcher.PageSize = PageSize
searcher.ServerTimeLimit = New TimeSpan(0, 10, 0)
searcher.Filter = FilterString
Dim queryResults As SearchResultCollection
queryResults = searcher.FindAll()
Dim result As SearchResult
For Each result In queryResults
pcResultCount += 1
Dim dNSHostName As String
If result.Properties.Contains("dNSHostName") Then 'If the computer object has a value in dNSHostName (FQDN) store it else store the basic name
dNSHostName = result.Properties("dNSHostName")(0)
Else
dNSHostName = result.Properties("name")(0)
End If
RaiseEvent ComputerFound(result.Properties("name")(0), dNSHostName, result.Path, result.Properties("objectGUID")(0).ToString)
RaiseEvent IncrementCompResult(pcResultCount)
Next
_doneEvent.Set() 'Signal that the thread is finished
#If Not Debug Then
Catch Ex as Exception
MsgBox(ex.Message, MsgBoxStyle.Critical)
End Try
#End If
End Sub
1 ответ
Заменить следующие 2 строки:
AddHandler Me.ComputerFound, AddressOf frmMain.adSync_ComputerFound
AddHandler Me.IncrementCompResult, AddressOf frmMain.adSync_CompResultFound
с:
AddHandler Me.ComputerFound, AddressOf My.Forms.frmMain.adSync_ComputerFound
AddHandler Me.IncrementCompResult, AddressOf My.Forms.frmMain.adSync_CompResultFound
Это еще один пример использования форм VB по умолчанию, стреляющих разработчикам в ногу.