Following on from my question a little while ago.
I have resolved most of the parts related to that. Detect when a COM Object goes out of Scope
I now face a new problem whilst developers are working on the VB6 code. If they run the project inside the IDE, and then press END, the Dispose nor Finalize are being called. It's like the Debugging part of VB6 just detaches immediately without calling disposes etc.
I have tested this via using the standard application close and Finalize gets called from COM -> .NET component and my thread shuts down, but if the End button is pressed there is no Finalise, no Dispose and my thread just keeps running.
Inside my component I tried this
bool debuggerAttachedatStart = System.Diagnostics.Debugger.IsAttached;
System.Windows.Forms.MessageBox.Show("The Debugger is currently -" + debuggerAttachedatStart);
but when you run it within VB6, it's always False.
I got out Process Explorer and had a look at VB6 and I noticed it creates an Event object upon startup of the Debugging session开发者_运维问答, but it is a unique guid each time you start. (\Sessions\1\BaseNamedObjects{70FAF0B5-A76B-4C6A-92BE-5201B2335871})
Just wondering if there is anything I can do so that I can gracefully detect that the Debugging has stopped (or started) within VB6.
No, there is nothing you can do. Stopping debugging does not give your program a chance to run code.
I believe I may have found a solution and thought I'd share it, incase someone has a better idea for how I can gracefully perform the shutdown of my thread.
In my .NET assembly add another Event definition
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(Manager.EventsId)> _
Public Interface IManagerEvents
'Others Removed
<DispId(4)> Sub HostAlive(ByRef alive As Boolean)
End Interface
and in the Code Definition add Public Delegate Sub HostAliveDelegate(ByRef state As Boolean)
Now in the main area of Code, because we will be talking to VB6 we need to be on the correct thread, so grab a SyncContext. And setup the threads.
public sub New()
Dim operation As ComponentModel.AsyncOperation
operation = AsyncOperationManager.CreateOperation(Nothing)
mSync = AsyncOperationManager.SynchronizationContext
operation.OperationCompleted()
'setup thread work.....
end sub
Private Sub ConnectPipe()
Dim lastAliveCheck As DateTime
lastAliveCheck = DateTime.Now.AddSeconds(2)
While Not mRunningEvent.Wait(0)
'do all the work to prepar and setup the PIPE.
'if we successfully connect
Using NoOpTimer As New Threading.Timer(New Threading.TimerCallback(AddressOf TimerTicks), mPipe, 2000, 2000)
'If we disconnect, this Event gets allowing the exit and reconnect to commence
mConnectedHold.WaitOne()
End Using
'we must have not connected so ensure that we are still inside a running process
PipeLog.Write("Attempting reconnect to named pipe")
mConnectedStopper.Wait(500)
If DateTime.Now > lastAliveCheck Then
lastAliveCheck = DateTime.Now.AddSeconds(2)
Dim e As New HostAliveEventArgs()
OnHostAlive(e)
If Not e.IsAlive Then
'The host did not set the event. Make sure the event is wired up and setting the value to true.
Exit While
End If
End If
End While
DisposePipe
mExitingEvent.Set()
End Sub
Protected Sub OnHostAlive(ByVal e As HostAliveEventArgs)
mSync.Send(AddressOf OnHostAliveContextPost, e)
End Sub
Private Sub OnHostAliveContextPost(ByVal state As Object)
Dim e As HostAliveEventArgs = CType(state, HostAliveEventArgs)
RaiseEvent HostAlive(e.IsAlive)
End Sub
Over inside our VB6 class that utilises this component.
Private WithEvents comm As IPSClient_Intercommunication.Manager
Private Sub Class_Initialize()
Set comm = New IPSClient_Intercommunication.Manager
End Sub
Private Sub comm_HostAlive(ByRef alive As Boolean)
alive = True
End Sub
What I discovered is that even if you use a CustomEvent it is always bound, so you can't just determine that there are no connected event delegates and disconnect. When you raise the event if the host application has been shutdown, then the event doesn't set the alive to true, and you can assume that it's been aborted.
精彩评论