Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subscription to DTE events doesn't seem to work - Events don't get called

I've made an extension inside a package and I am calling the following code (occurs when a user presses a button in the toolbar):

DocumentEvents documentEvents = (DTE2)GetService(typeof(DTE));
_dte.Events.DebuggerEvents.OnEnterBreakMode += DebuggerEvents_OnEnterBreakMode;
_dte.Events.DebuggerEvents.OnEnterDesignMode += DebuggerEvents_OnEnterDesignMode;
_dte.Events.DebuggerEvents.OnContextChanged += DebuggerEvents_OnContextChanged;
_dte.Events.DocumentEvents.DocumentSaved += new _dispDocumentEvents_DocumentSavedEventHandler(DocumentEvents_DocumentSaved);
_dte.Events.DocumentEvents.DocumentOpened += new _dispDocumentEvents_DocumentOpenedEventHandler(DocumentEvents_DocumentOpened);
void DocumentEvents_DocumentOpened(Document Document)
{
}

void DocumentEvents_DocumentSaved(Document Document)
{
}

void DebuggerEvents_OnEnterBreakMode(dbgEventReason Reason, ref dbgExecutionAction ExecutionAction)
{
}

void DebuggerEvents_OnContextChanged(Process NewProcess, Program NewProgram, Thread NewThread, StackFrame NewStackFrame)
{
}

private void DebuggerEvents_OnEnterDesignMode(dbgEventReason reason)
{
}

The first and the major problem is that the subscription to the event doesn't work. I've tried:

  • Opening new documents
  • Detaching from debug (thus supposedly triggering OnEnterDesignMode
  • Saving a document

None of these seem to have any effect and the callback functions were never called.

The second issue is that the subscription to the event line works USUALLY (the subscription itself, the callback doesn't work as described above) but after a while running the subscription line, e.g:

_dte.Events.DebuggerEvents.OnEnterBreakMode -= DebuggerEvents_OnEnterBreakMode;

Causes an exception:

Exception occured!
System.Runtime.InteropServices.InvalidComObjectException: COM object that has been separated from its underlying RCW cannot be used.
   at System.StubHelpers.StubHelpers.StubRegisterRCW(Object pThis, IntPtr pThread)
   at System.Runtime.InteropServices.UCOMIConnectionPoint.Unadvise(Int32 dwCookie)
   at EnvDTE._dispDebuggerEvents_EventProvider.remove_OnEnterDesignMode(_dispDebuggerEvents_OnEnterDesignModeEventHandler A_1)

Any ideas will be welcome

Thanks! Vitaly

like image 774
VitalyB Avatar asked Oct 06 '10 15:10

VitalyB


1 Answers

Posting an answer that I got from MSDN forums, by Ryan Molden, in case it helps anyone:

I believe the problem here is how the CLR handles COM endpoints (event sinks). If I recall correctly when you hit the _applicationObject.Events.DebuggerEvents part of your 'chain' the CLR will create a NEW DebuggerEvents object for the property access and WON'T cache it, therefor it comes back to you, you sign up an event handler to it (which creates a strong ref between the TEMPORARY object and your object due to the delegate, but NOT from your object to the temporary object, which would prevent the GC). Then you don't store that object anywhere so it is immediately GC eligible and will eventually be GC'ed.

I changed the code to store DebuggerEvents as a field and it all started to work fine.

like image 129
VitalyB Avatar answered Oct 27 '22 05:10

VitalyB