none
_debugEvents.OnEnterBreakMode is not firing

    Question

  • I am developing an Extension (VSPackage).. I am subsribing to all the Debugger events inside one of the classes (MyDebugger class)

    I am subscribing to following events inside the constructor

     

    public class MyDebugger
        {
            private readonly DTE _dte;
            private readonly EnvDTE.DebuggerEvents _debugEvents;
            public event _dispDebuggerEvents_OnEnterBreakModeEventHandler OnEnterBreakMode;
    
            public MyDebugger()
            {
                _dte = (DTE)Package.GetGlobalService(typeof(DTE));
                _debugEvents = _dte.Events.DebuggerEvents;
                _debugEvents.OnEnterBreakMode += new _dispDebuggerEvents_OnEnterBreakModeEventHandler(_debugEvents_OnEnterBreakMode);
                _debugEvents.OnEnterRunMode += new _dispDebuggerEvents_OnEnterRunModeEventHandler(_debugEvents_OnEnterRunMode);
                _debugEvents.OnContextChanged += new _dispDebuggerEvents_OnContextChangedEventHandler(_debugEvents_OnContextChanged);
                _debugEvents.OnEnterDesignMode += new _dispDebuggerEvents_OnEnterDesignModeEventHandler(_debugEvents_OnEnterDesignMode);
            }
    }
    

     

    Looks like none of the event handlers except onContextChanged get  called....

    I am creating an instance of this class from a WPF Usercontrol which is hosted by toolwindow.

    If I move all my event subscription to this usercontrol class , It works ..

    Can some one tell me what is the reason for this?

    Thanks

    JO

     


    • Edited by jo.kply Thursday, January 26, 2012 7:19 AM
    Thursday, January 26, 2012 7:17 AM

All replies

  • 1)  Where is MyDebugger constructed?  I.e. is this during an AddIn load or Package creation?

    2)  Have you tried also holding a strong ref to the Events object (i.e. dte.Events) and not just DebuggerEvents?

    Ryan

    Thursday, January 26, 2012 11:17 PM
  • Hi jo.kply,

    Have you solved this issue?

    If not, please let us know. And provide more information about this issue.

    If yes, please mark the useful reply as answer.

    Thank you for your understanding!

     

    Best regards,

    Lucy


    Lucy Liu [MSFT]
    MSDN Community Support | Feedback to us
    Monday, January 30, 2012 5:49 AM
  • 1. The Creation of Debugger is in MyControl class

    public partial class MyControl : UserControl
    {
            private readonly MyDebugger _debugger;
          
            public MyControl()
            {
                  _debugger = new MyDebugger();
                _debugger.OnEnterBreakMode += new EnvDTE._dispDebuggerEvents_OnEnterBreakModeEventHandler(debugger_OnEnterBreakMode);
                InitializeComponent();
            }
    

    Mycontrol Class is insatiated inside the constructor of ToolWindowPane derived class

     

        public class MyToolWindow : ToolWindowPane
        {
            /// <summary>
            /// Standard constructor for the tool window.
            /// </summary>
            public MyToolWindow() :
                base(null)
            {
                // Set the window title reading it from the resources.
                this.Caption = Resources.ToolWindowTitle;
                // Set the image that will appear on the tab of the window frame
                // when docked with an other window
                // The resource ID correspond to the one defined in the resx file
                // while the Index is the offset in the bitmap strip. Each image in
                // the strip being 16x16.
                this.BitmapResourceID = 301;
                this.BitmapIndex = 1;
    
                // This is the user control hosted by the tool window; Note that, even if this class implements IDisposable,
                // we are not calling Dispose on this object. This is because ToolWindowPane calls Dispose on 
                // the object returned by the Content property.
                base.Content = new MyControl();
            }
        }
    


    2. Itried with your second suggestion . I changed code to hold a reference to Events. But Interstingly "onContextChanged" also stopped working

    I am pasting code below

     

    public class MyDebugger
        {
            private readonly DTE _dte;
            private readonly EnvDTE.Events _events;
            public event _dispDebuggerEvents_OnEnterBreakModeEventHandler OnEnterBreakMode;
    
            public MyDebugger()
            {
                _dte = (DTE)Package.GetGlobalService(typeof(DTE));
                _events = _dte.Events;
                _events.DebuggerEvents.OnEnterBreakMode += new _dispDebuggerEvents_OnEnterBreakModeEventHandler(_debugEvents_OnEnterBreakMode);
                _events.DebuggerEvents.OnEnterRunMode += new _dispDebuggerEvents_OnEnterRunModeEventHandler(_debugEvents_OnEnterRunMode);
                _events.DebuggerEvents.OnContextChanged += new _dispDebuggerEvents_OnContextChangedEventHandler(_debugEvents_OnContextChanged);
                _events.DebuggerEvents.OnEnterDesignMode += new _dispDebuggerEvents_OnEnterDesignModeEventHandler(_debugEvents_OnEnterDesignMode);
            }
    }
    

    Any suggestion???

     

    Wednesday, February 01, 2012 6:29 PM
  • I can't repro this.  When I suggested you root the Events object I meant the Events object AND the DebuggerEvents object.  DTE is a COM based interface, when you see .NET events appearing in it you should be very suspicous, specifically you should realize you aren't dealing with real .NET events as those don't exist in COM. You are dealing with IConnectionPoint and IConnectionPointContainer, and the CLR does some 'magic' at the interop layer to make these appear like .NET events. An unfortunate piece of this magic is that it spins up 'temporary' objects that expose the events, if you don't root these event exposing objects they will get GCed.

    I took the following impl of your MyDebugger class

        public class MyDebugger
        {
            private readonly DTE _dte;
            private readonly EnvDTE.Events _events;
            private readonly DebuggerEvents _debuggerEvents;
    
            public event _dispDebuggerEvents_OnEnterBreakModeEventHandler OnEnterBreakMode;
    
            public MyDebugger()
            {
                _dte = (DTE)Package.GetGlobalService(typeof(DTE));
                _events = _dte.Events;
                _debuggerEvents = _events.DebuggerEvents;
    
                _debuggerEvents.OnEnterBreakMode += _debugEvents_OnEnterBreakMode;
                _debuggerEvents.OnEnterRunMode += _debugEvents_OnEnterRunMode;
                _debuggerEvents.OnContextChanged += _debugEvents_OnContextChanged;
                _debuggerEvents.OnEnterDesignMode += _debugEvents_OnEnterDesignMode;
            }
    
            private void _debugEvents_OnEnterBreakMode(dbgEventReason Reason, ref dbgExecutionAction ExecutionAction)
            {
                return;
            }
    
            private void _debugEvents_OnEnterRunMode(dbgEventReason Reason) 
            {
                return;
            }
    
            private void _debugEvents_OnContextChanged(Process NewProcess, Program NewProgram, Thread NewThread, StackFrame NewStackFrame)
            {
                return;
            }
    
            private void _debugEvents_OnEnterDesignMode(dbgEventReason Reason)
            {
                return;
            }
        }
    
    


    I instantiated that object from within your UserControl ctor like you said in your original post.  I set breakpoints on all the return calls, loaded up the Experimental Instance, opened your tool window, opened a .csproj, set a breakpoint and hit F5. All the event callbacks were hit.

    Ryan

    Sunday, February 05, 2012 6:33 PM
  • Hi Ryan,

    Thanks for the reply... I tried with MyDebugger class with _events and _debuggerEvents.. But unfortunately it didnt work for me...

    I forgot to mention one thing from the intial post.. I have MyDebugger  class in a sepearte assembly and my usercontrol class in seperate assembly..

    I moved MyDebugger   class to the same assembly where my usercontrol class is  and it works.

    But If i put MyDebugger  class in a sepearte assembly , it doesnt work for me... Any hints????

    Thanks

    JO


    • Edited by jo.kply Tuesday, February 07, 2012 3:25 AM speeling correction
    Tuesday, February 07, 2012 3:24 AM
  • Is your second assembly marked as COMVisible in its AssemblyInfo.cs like the default wizard generated assembly is (I believe)?

    Ryan

    Tuesday, February 07, 2012 7:11 AM
  • Thanks Ryan for replying me...

    All the assemblies including the assembly generated by wizard (VS Extensibilty wizard.. I created a package ) has ComVisible flag set to false.

    I made all the assemblies ComVisible now ..but it doesnt work for me :(

    ( i beleieve  when we want to acess some types in the assembly from COM, we will set this flag true. What is the importance of ComVisible here? please correct me if i am wrong...)

    Thanks for answering my questions

    Jo

    Tuesday, February 07, 2012 5:21 PM
  • Yeah, I think the CLR only uses the ComVisible attribute if you are trying to CoCreate managed classes, so it probably doesn't matter here, it was just a guess.  You have verified that the secondary assembly is deployed with your package and is located at runtime (i.e. the ctor is hit and DTE is non-null and all the event signups happen)?  There are no exceptions being thrown? In general lots of exceptions can be swallowed on these routes as they are COM callbacks and the CLR can't let a managed exception cross a COM boundary.

    Ryan

    Tuesday, February 07, 2012 6:23 PM
  • Have you considered to do something like this? DTE is full of bugs and AFAIK (but dont take my word for it) they are not giving it much love anymore.

        public enum DebugMode
        { 
            Run,
            Break,
            Design
        }
    
        #region Events
    
        public class DebugModeChangedEventArgs : EventArgs
        {
            public readonly DebuggerEventsSink Source;
            public readonly DebugMode Action;
    
            public DebugModeChangedEventArgs(DebuggerEventsSink source, DebugMode action)
            {
                this.Source = source;
                this.Action = action;
            }
        }
    
        #endregion
    
        [Export]
        public sealed class DebuggerEventsSink : DisposableObject, IVsDebuggerEvents
        {
            private IVsDebugger debugger;
            private uint debugEventsCookie = VSConstants.VSCOOKIE_NIL;
    
            private readonly DebugModeChangedEventArgs runEventArgs;
            private readonly DebugModeChangedEventArgs breakEventArgs;
            private readonly DebugModeChangedEventArgs designEventArgs;
            public event EventHandler<DebugModeChangedEventArgs> DebugModeChange = (sender, args) => { };
    
            public DebuggerEventsSink()
            {
                runEventArgs = new DebugModeChangedEventArgs (this, DebugMode.Run);
                breakEventArgs = new DebugModeChangedEventArgs (this, DebugMode.Break);
                designEventArgs = new DebugModeChangedEventArgs (this, DebugMode.Design);
    
                Initialize();
            }
    
            private void Initialize()
            {
                debugger = GlobalServices.GetService<IVsDebugger>();            
    
                ErrorHandler.ThrowOnFailure(debugger.AdviseDebuggerEvents(this, out debugEventsCookie));
            }
    
            protected override void DisposeManagedResources()
            {
                ThreadHelper.Generic.Invoke(() =>
                {
                    if (this.debugEventsCookie != VSConstants.VSCOOKIE_NIL &&
                        this.debugger != null)
                    {
                        ErrorHandler.CallWithCOMConvention(() => this.debugger.UnadviseDebuggerEvents(this.debugEventsCookie));
                        this.debugEventsCookie = VSConstants.VSCOOKIE_NIL;
                    }
                });
    
                base.DisposeManagedResources();
            }
    
            int IVsDebuggerEvents.OnModeChange(DBGMODE dbgmodeNew)
            {
                switch(dbgmodeNew)
                {
                    case DBGMODE.DBGMODE_Run:
                        DebugModeChange(this, runEventArgs);                    
                        break;
                    case DBGMODE.DBGMODE_Break:
                        DebugModeChange(this, breakEventArgs);
                        break;
                    case DBGMODE.DBGMODE_Design:
                        DebugModeChange(this, designEventArgs);
                        break;
                }
    
                return VSConstants.S_OK;
            }
        }

    Regards,

    Federico

    Thursday, February 09, 2012 2:43 PM
  • Hi Ryan,

    Dte is initilized and not null and all the events registration happens. And OnContextChanged is getting called...  but  OnEnterBreakMode and other events are not..  Any idea??

    The same class works if i move that to the same assembly where the subscribers are there but moving to another assembly will hinder  OnEnterBreakMode and other events. But OnContextChanged  will work evn that time...

    Hi Federico,

    I tried the code.. It works.. Thanks.  But problem with Dte stiil reamins..

    Did you experience the same problem with Dte??

    Also i want to use _dte.deugger's  GetExpression for evaluating expressions and Break and Go for breaking and resuming. Is there a way to do this thing with IVsDebugger???

    Thanks

    Jo 



    • Edited by jo.kply Wednesday, February 15, 2012 3:01 AM Added info
    Tuesday, February 14, 2012 4:08 AM
  • Hi Ryan and Jo.

    I am also developing an Extension (VSPackage), I am subsribing to 2 of  the Debugger events in the cunstructor of VSPackage.cs

        public sealed class ComboBoxPackage : Package
    {
    ....
     public ComboBoxPackage()
            {
                Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString()));
                _dte = (DTE)Package.GetGlobalService(typeof(DTE));
                _events = _dte.Events;
                _debuggerEvents = _events.DebuggerEvents;
    
                _debuggerEvents.OnEnterRunMode += _debugEvents_OnEnterRunMode;
                _debuggerEvents.OnContextChanged +=_debuggerEvents_OnContextChanged;      
            }
    
            void _debuggerEvents_OnContextChanged(EnvDTE.Process NewProcess, Program NewProgram, Thread NewThread, EnvDTE.StackFrame NewStackFrame)
            {
                throw new NotImplementedException();
            }
            
    
            private void _debugEvents_OnEnterRunMode(dbgEventReason Reason)
            {
                return;
            }
    
    }

    when I'm running it ( strating run an application ) only _debuggerEvents_OnContextChanged is called, and _debugEvents_OnEnterRunMode is not called.

    if I did the same with Addin project all works fine.

    Can you please help me with that? it's really urgent to us.

    Tuesday, August 14, 2012 12:43 PM
  • I found out another reason for this. It applies to you I think TTTTTTTTTTTTO. You can't box, and unbox the DTE object. If you do that, it will stuff up COM/.NET etc communication. OnContextChanged works, always, OnEnterRunMode requires DTE not be boxed and unboxed. I believe you are unboxing, like I was, by using a service locator like pattern. It is for this reason I believe that the previous posters mentioned having stuff in another assembly wasn't working as they would have used such a pattern to get the DTE object out of the root package.cs

    Your error is here. Try get reference to DTE directly by using: 

    (DTE)Package.GetGlobalService(typeof(DTE));

    instead use:

    var applicationObject = (DTE)GetService(typeof(DTE));

    applicationObject.Events.DebuggerEvents.OnEnterDesignMode += DebuggerEvents_OnEnterDesignMode;

    I have submitted a bug to MS connect here: https://connect.microsoft.com/VisualStudio/feedback/details/775900/vssdk-2008-2010-2012-dte-events-subscription-problem-reproduceable
    • Proposed as answer by Dessus Sunday, January 06, 2013 7:45 AM
    • Edited by Dessus Sunday, January 06, 2013 8:16 AM Added bug report details for Connect
    Sunday, January 06, 2013 7:45 AM