0

该线程被标记为重复,因为我之前遇到过这个问题并且之前曾问过一个问题。我现在通常知道如何解决它(即通过使用指向表单实例而不是其名称的变量)。不过这次是我需要参考的默认启动表单。所以没有变量存储它的实例,我不知道如何在没有变量的情况下引用它的现有实例。

我有 2 个表单(frmMain 和 frmStatus) 我创建了一个 frmStatus 实例并将其存储在 frmMain 上的 statusDialog 变量中。然后我创建一个新线程(用于我的 ADSearcher 类),它触发事件,然后使用委托调用 statusDialog 上的子程序。ADSearcher 线程还创建了多个其他线程(对于我的 ComputerSearcher 线程),这些线程还需要引发事件,这些事件将使用委托在 statusDialog 上调用 subs。

问题出在 ComputerSearcher 线程中。AddHandler 行似乎正在创建一个新的 frmMain 实例,这意味着 statusDialog 为 Nothing/Null。为什么 AddHandler 创建表单的新实例,有没有办法让它使用正确的实例?

我认为它正在创建一个新实例的原因是因为当我单步执行代码时,它会执行第一行 AddHandler ,然后单步执行 frmMain 顶部的变量声明(在任何 subs 之外),此时 statusDialog 变为 Nothing。

起点是 Private Sub mnuSync_ADSync_Click(...)。这将创建第一个线程和类实例。我已经尝试提供足够的代码让您在不发布大量文章的情况下查看正在发生的事情。如果您需要任何其他代码,请询问。

提前致谢,

主界面

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 类

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

计算机搜索类

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
4

1 回答 1

0

替换以下 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 默认表单实例示例。

于 2014-09-25T21:56:51.420 回答