2014-09-25 2 views
0

이 스레드는 이전에이 문제가 발생하여 이전에 질문을했기 때문에이 스레드는 중복으로 표시되었습니다. 지금은 일반적으로 그것을 해결하는 방법 (즉, 이름 대신 양식의 인스턴스를 가리키는 변수를 사용하여)을 알고 있습니다. 그러나 이번에는 참조 할 필요가있는 내 기본 시작 양식입니다. 따라서 인스턴스를 저장하는 변수가 없으며 인스턴스가없는 기존 인스턴스를 어떻게 참조 할 수 있는지 알 수 없습니다.VB.NET AddHandler가 폼의 새 인스턴스를 만듭니다. null delegate 발생

2 개의 폼 (frmMain 및 frmStatus)이 있습니다. frmStatus의 인스턴스를 만들고 frmMain의 statusDialog 변수에 저장합니다. 그런 다음 대리인을 사용하여 statusDialog에 대한 subs을 호출하는 이벤트를 발생시키는 새 스레드 (내 ADSearcher 클래스 용)를 만듭니다. ADSearcher 스레드는 또한 다른 ComputerSearcher 스레드 용 스레드를 생성합니다.이 스레드는 또한 대리자를 사용하여 statusDialog에서 subs를 호출하는 이벤트를 발생시켜야합니다.

문제는 ComputerSearcher 스레드에 있습니다. AddHandler 줄은 frmMain의 새 인스턴스를 만드는 것처럼 보입니다. 즉, statusDialog는 Nothing/Null입니다. AddHandler가 폼의 새로운 인스턴스를 만드는 이유는 무엇입니까? 그리고 올바른 인스턴스를 사용하기 위해 사용할 수있는 방법이 있습니까?

내가 새로운 인스턴스를 만드는 이유는 코드를 단계별로 실행하면 첫 번째 AddHandler 행을 실행 한 다음 statusDialog가 frmMain (임의의 잠수함 바깥 쪽)의 맨 위에있는 변수 선언을 단계별로 따라 가기 때문입니다. 아무것도.

시작 지점은 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 클래스

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 클래스

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 
+0

'frmMain'은 _class_ 형식의 이름입니까, 아니면 변수의 이름입니까? VB.Net에서는 'Dim'을 사용하지 않고 이름 만 참조하여 양식을 열 수 있습니다. 이를 기본 인스턴스라고합니다. VB6 프로그램을 .Net으로 쉽게 마이그레이션 할 수 있도록 추가 된 기능입니다. 그들은 **에 고통을 느끼고 있습니다. –

+0

frmMain은 양식 클래스의 이름입니다. 변수를 사용할 때이 질문을하기 전에이를 해결하는 방법을 알고 있습니다. 따라서이 질문은 중복으로 표시됩니다. 그러나 이번에는 기본 시작 양식이므로 변수에 인스턴스를 만들 수 없습니다 (어쨌든 내 지식에 따라). 따라서 양식의 기존 인스턴스를 어떻게 참조 할 수 있는지 잘 모르겠습니다. – Daniel

+0

클래스 (예 : Program.vb)를 만듭니다. 그 클래스에서'Public Shared Sub Main'을 추가하십시오. 이 메소드에서 메인 폼의 인스턴스를 생성 한 다음'Application.Run (mainFormInstance)'를 호출 할 수있다. 프로젝트 속성에서 시작 객체를 Sub Main으로 설정한다. –

답변

0

교체 다음 2 줄 :

0 와
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 기본 양식 인스턴스의 또 다른 예이다.

+0

답변 해 주셔서 감사합니다. 나는 당신의 제안을 시도했지만 그것은 여전히 ​​폼의 새로운 인스턴스를 생성하고 있습니다. – Daniel