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

    Question

  • 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));<br/>
    _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 (the subscription itself, the callback doesn't work as described above) USUALLY but after a while running the subscription line, e.g:

    _dte.Events.DebuggerEvents.OnEnterBreakMode -= DebuggerEvents_OnEnterBreakMode;<br/>
    
    

    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.

    Further details:
    .NET version: 4
    Visual studio 2010
    Windows 7 Ultimate

    Thanks,
    Vitaly
    Tuesday, October 05, 2010 9:31 PM

Answers

  • 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.

    Ryan

    • Marked as answer by CodeValue Ltd Sunday, October 10, 2010 9:36 AM
    Friday, October 08, 2010 3:20 PM
    Moderator

All replies

  • 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.

    Ryan

    • Marked as answer by CodeValue Ltd Sunday, October 10, 2010 9:36 AM
    Friday, October 08, 2010 3:20 PM
    Moderator
  • Hey Ryan,

    Thanks for the answer, it was indeed the issue!

    I did suspect GC has something to do with it, but didn't realize that can GC can act as quickly. And it was good to learn that about COM objects.

    Thanks!
    Vitaly

    Sunday, October 10, 2010 9:38 AM
  • I have don't alot of research on this which is worth sharing for others having the same issue. I had a different issue, where I boxed and unboxed the DTE object which caused events to stop working:

    http://social.msdn.microsoft.com/Forums/en-US/vsx/thread/eb1e8fd1-32ad-498c-98e9-25ee3da71004

    http://stackoverflow.com/questions/8775111/dteevents-onstartupcomplete-event-not-working-for-vspackage-vssdk2010/14180361#14180361

    http://stackoverflow.com/questions/5405167/dte2-events-dont-fire/14180383#14180383

    http://stackoverflow.com/questions/4816801/visual-studio-2010-extension-events-not-called/14180414#14180414

    Sunday, January 06, 2013 8:13 AM
  • Boxed/unboxed is likely the wrong term here as it has specific meaning in managed code which does not apply here.

    Looking at your links you claim it is reproducible, but as you see from my previous posts it is in fact not, at least not for me. When this happens it means you need to supply a FULL repro, not just one or two lines of code that you think are causing the problem.

    The connect bug will be very unlikely to have anyone look into it because you just provide a bunch of links to places that have small code snippets. You would need to provide a link to a complete repro (preferably a project that someone could just load into VS to debug). I am highly dubious that GetService vs. GetGlobalService is in play, unless GetGobalService was returning null, which is quite possible but various people have said that is not happening to them. The reason for this is that GetGlobalService and GetService both go through the same code path to retrieve DTE, though GetGlobalService relies on at least one MPF package havig been loaded whereas your package GetService will work anytime after Initialize has been called (i.e. your package has been sited).
    Sunday, January 06, 2013 4:56 PM
    Moderator