In a Visual Studio Extension, how to detect when the debugger Continues
Asked Answered
G

2

9

I need my Visual Studio extension to react to debugging events. I've registered a IDebugEventCallback2 and I'm receiving events, but all I get for each event is an opaque IDebugEvent2 and a Guid, many of which are not only undocumented but don't appear anywhere on the web (or in my registry).

My specific requirement at the moment is to know when the process is Continued - ie. the user has hit Continue, Run to cursor, etc. What Guid should I be looking for?

Or is there some other event family that I should be subscribing to?

(More generally, is there some way I'm missing to find out about the events that are delivered to my IDebugEventCallback2::Event callback, when many of them don't appear in MSDN or anywhere else? Thanks!)

Goose answered 15/6, 2015 at 19:22 Comment(0)
G
6

There is no easy way to do this. Actions such as Continue and Run to cursor are abstractions implemented by Visual Studio and do not correspond to any unique event(s) with respect to the debug engine. The debug engine event reporting interface IDebugEventCallback2 will enable you to get notified only on fine-grained events such as when creating a breakpoint or reaching a breakpoint.

While Visual Studio enables you to perform actions such as Continue and Run to cursor programmatically, it does not provide a direct way to get notified when they are taken.

You can use EnvDTE.DebuggerEvents.OnXxx events to get notified when something is about to happen. In particular, the OnEnterBreakMode event enables you to intercept a breakpoint hit and possibly take an action. You can also inspect all the details of the reached breakpoint(s) using the current EnvDTE.Debugger inside the event handler.

Now with some effort, you can use these constructs to implement events that correspond to all Visual Studio debugging actions including Continue and Run to cursor accurately. If you require additional events not provided by EnvDTE.DebuggerEvents (such as when a breakpoint is inserted), you have no choice but use IDebugEventCallback2.Event. In this case if you have specific events in mind, please mention them explicitly and I might be able to tell you the corresponding IDebugEventCallback2.Event GUIDs.

Grecism answered 1/7, 2015 at 10:20 Comment(13)
Thanks! It seems that the specific case of Continue (or variants like Run to Cursor - I don't need to differentiate) should be covered by DebuggerEvents.OnEnterRunMode - correct? But going back to IDebugEventCallback2, after debugging Visual Studio I found that the event {29e2d4a0-503e-4e17-91ea-ea021570a857} seems to correspond with the same thing (I'm calling it "GUID_ExitBreakModeEvent" based on what I see in the Visual Studio stack). I'm also using {ce6f92d3-4222-4b1e-830d-3ecff112bf22} to detect when the debugger context changes - is that sensible? Is there a better alternative?Goose
The event {29e2d4a0-503e-4e17-91ea-ea021570a857} corresponds to an internal interface Microsoft.VisualStudio.Debugger.Interop.Internal.IDebugExitBreakStateEvent which occur whenever a breakpoint is being exited. This means it will occur on Contine, Run to Cursor and all kinds of steps.Grecism
I'm not sure what you mean by "debugger context changes."Grecism
DebuggerEvents.OnEnterRunMode is just like IDebugExitBreakStateEvent.Grecism
Many thanks - that's very helpful! By "debugger context changes" I mean, for example, switching to a new stack frame by double-clicking in the Call Stack window. A change to to the current statement - where the yellow pointer is in the margin.Goose
You can use Microsoft.VisualStudio.Debugger.Interop.IDebugCurrentThreadChangedEvent100 for that purpose. You can test for GUID like this: if (riidEvent == typeof(IDebugCurrentThreadChangedEvent100).GUID). Then you can use the pThread parameter to determine exactly where the debugger stopped. Don't use {ce6f92d3-4222-4b1e-830d-3ecff112bf22}, it has nothing to do with context changes.Grecism
IDebugCurrentThreadChangedEvent100 sounds very useful. However, {ce6f92d3-4222-4b1e-830d-3ecff112bf22} also fires when (for instance) you change the value of a variable via the Watch window, which makes it perfect for what I want, which is basically "Something in the state of the debugger has changed". Is it valid to use for that purpose? Is there an alternative?Goose
@Goose Exactly. {ce6f92d3-4222-4b1e-830d-3ecff112bf22}corresponds to an internal interface called Microsoft.VisualStudio.Debugger.Interop.Internal.IDebugExpressionsDirtyEvent :)Grecism
I don't think there are any alternatives to IDebugExpressionsDirtyEvent. Be careful when trying to detect this event as it will be raised not only when a variable's value has changed in the Watch and Locals windows but also when variables are first added to these windows and when invalid actions are made there as well.Grecism
Ah - wonderful! You've confirmed that IDebugExpressionsDirtyEvent is just what I need (I'm not worried about it firing in those other cases). One last question if I may - how stable are these GUIDs and the corresponding events? When extension authors like me write code that relies on them, do they then regret it because the Visual Studio guys change things (these are internal details after all, with no guarantees attached). Or are the Visual Studio internals stable enough that something I know works today will continue working tomorrow?Goose
There's no guarantee regarding those events from Microsoft.VisualStudio.Debugger.Interop.Internal. They might get changed or removed which might cause their GUIDs to change. So a newer version of VS might introduce breaking changes in your extension. However, if that happens, probably new events have been introduced and so you should change your code to use them anyway. Regarding those events from Microsoft.VisualStudio.Debugger.Interop, they will remain stable and their GUIDs will not change.Grecism
OK, understood, that makes perfect sense. Many thanks for all your help!Goose
Hi @HadiBrais is it possible to detect the event before Debugging actually Stops? I am looking at BeforeStopDebuggingProcess() inside IVsDebugProcessNotify. However, I don't know how to subscribe to this event. The events inside IDebugEventCallback2 does not seem to be reliably called before the debugging actually stops (4 out of 5 times, I get notified by 2615D9BC-1948-4D21-81EE-7A963F20CF59). I want to be able to be notified consistently before Debugger Stops. Thank you.Ledford
S
2

You probably got off on the wrong foot here, the IDebugXxx interfaces were really intended to create your own debugging engine. Still useful perhaps to see what is going on in the existing engine, you are suppose to use QueryInterface() to discover the specific interface that matches the event. Like IDebugEngineCreateEvent2, IDebugProcessCreateEvent2, IDebugProcessDestroyEvent2, etcetera. There are a bunch of them, they are listed in the VSSDK\VisualStudioIntegration\Common\Inc\msdbg.h header and include their IID.

Best thing to do is peek at this sample, it shows how to crack the event notification into the specific interfaces. The AD7Events.cs source file shows the wrappers. Do keep in mind that this sample was made to show how to create an engine, not how to use the one already built into VS.

But yes, you are not going to get a "continue debug" event out of this. A debugging engine does not need that event since it is already responsible for taking care of that by itself. It already knows when it calls IDebugProgram3::Continue().

Surely what you are looking for is IVsDebugger.AdviseDebuggerEvents(). That's the one that tells you what the built-in debugger is doing. You need to pass an object of a class that implements IVsDebuggerEvents, your OnModeChanged() method will be called with a DBGMODE notification. I don't see a lot of fantastic examples that demonstrate usage, this web page might be helpful.

Shadowgraph answered 26/6, 2015 at 11:45 Comment(1)
Thanks! OnModeChanged() works. Something worth noting: it's subject to a short delay, and doesn't always fire. If you step over a function that takes a long time to run, you'll get a Run event followed by a Break event, but if you step over something quick, you'll only get a Break event.Goose

© 2022 - 2024 — McMap. All rights reserved.