이 스레드는 이전에이 문제가 발생하여 이전에 질문을했기 때문에이 스레드는 중복으로 표시되었습니다. 지금은 일반적으로 그것을 해결하는 방법 (즉, 이름 대신 양식의 인스턴스를 가리키는 변수를 사용하여)을 알고 있습니다. 그러나 이번에는 참조 할 필요가있는 내 기본 시작 양식입니다. 따라서 인스턴스를 저장하는 변수가 없으며 인스턴스가없는 기존 인스턴스를 어떻게 참조 할 수 있는지 알 수 없습니다.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
'frmMain'은 _class_ 형식의 이름입니까, 아니면 변수의 이름입니까? VB.Net에서는 'Dim'을 사용하지 않고 이름 만 참조하여 양식을 열 수 있습니다. 이를 기본 인스턴스라고합니다. VB6 프로그램을 .Net으로 쉽게 마이그레이션 할 수 있도록 추가 된 기능입니다. 그들은 **에 고통을 느끼고 있습니다. –
frmMain은 양식 클래스의 이름입니다. 변수를 사용할 때이 질문을하기 전에이를 해결하는 방법을 알고 있습니다. 따라서이 질문은 중복으로 표시됩니다. 그러나 이번에는 기본 시작 양식이므로 변수에 인스턴스를 만들 수 없습니다 (어쨌든 내 지식에 따라). 따라서 양식의 기존 인스턴스를 어떻게 참조 할 수 있는지 잘 모르겠습니다. – Daniel
클래스 (예 : Program.vb)를 만듭니다. 그 클래스에서'Public Shared Sub Main'을 추가하십시오. 이 메소드에서 메인 폼의 인스턴스를 생성 한 다음'Application.Run (mainFormInstance)'를 호출 할 수있다. 프로젝트 속성에서 시작 객체를 Sub Main으로 설정한다. –