1

In a Visual Studio 2013 automation project (ie Visual Studio Package project), how can I have an event handler run when the debugged process exits, and how can I find out what the exit code of the debugged process was?

I'm starting the debugger like this (C#):

var dte = ...;
foreach (EnvDTE.Project proj in dte.Solution.Projects)
{
    if (proj.Name == "blahblah")
    {
        dte.Solution.Properties.Item("StartupProject").Value = proj.Name;
        dte.Debugger.Go(false);
        break;
    }
}

I want some more code to run when the debugged process exits, and that code needs to know the exit status of the debugged process. Can it be done?

Tom
  • 7,269
  • 1
  • 42
  • 69
  • Yes it can be done. You need to subscribe to the appropriate event in `dte.Debugger.Events` (or `dte.DebugEvents`?), and keep a reference to the DTE events object so that it doesn't get garbage collected before the actual event is fired. Also, your loop over the projects is possibly broken -- it skips all projects within solution folders, and considers solution folders as projects... Honestly, if you can do what you want *without* the ugly EnvDTE interface (i.e. via the real COM interfaces), you're probably better off, but it *will* be more code/work. – Cameron Aug 19 '15 at 10:16
  • Thanks for the pointer about solution folders etc. What I've got will do for my purposes, but I'll look in to fixing it properly. – Tom Aug 19 '15 at 10:18
  • I guess `dte.Events.DebugEvents.OnEnterDesignMode` is the event you're thinking of? But then how can I get the exit code of the debugged process? – Tom Aug 19 '15 at 10:19
  • Weird, I couldn't find a way to access the exit code via EnvDTE. It's possible directly through the VS interfaces, though -- see my answer. – Cameron Aug 19 '15 at 13:50

1 Answers1

2

You can accomplish this through the COM interfaces (bypassing the EnvDTE automation layer, which is mostly just a fancy wrapper).

class ExitEventListener : IDebugEventCallback2
{
    private IVsDebugger _debugger;

    public ExitEventListener()
    {
        _debugger = Package.GetGlobalService(typeof(SVsShellDebugger)) as IVsDebugger;
        if (_debugger != null)
            _debugger.AdviseDebugEventCallback(this);
    }

    public int Event(IDebugEngine2 pEngine, IDebugProcess2 pProcess, IDebugProgram2 pProgram, IDebugThread2 pThread, IDebugEvent2 pEvent, ref Guid riidEvent, uint dwAttrib)
    {
        if (pEvent is IDebugProgramDestroyEvent2)
        {
            // The process has exited

            uint exitCode;
            if (((IDebugProgramDestroyEvent2)pEvent).GetExitCode(out exitCode) == VSConstants.S_OK)
            {
                // We got the exit code!
            }

            // Stop listening for future exit events
            _debugger.UnadviseDebugEventCallback(this);
            _debugger = null;
        }
        return VSConstants.S_OK;
    }
}
Cameron
  • 96,106
  • 25
  • 196
  • 225
  • 1
    If you have time, could you please further explain your "EnvDTE is mostly just a fancy wrapper" comment? Regards. – Sabuncu Jun 24 '20 at 19:22
  • 1
    @Sabuncu: The VS internals are a mix of C++ (bulk of the legacy code like the debugger subsystem) and C# (good chunk of the "modern" code like the editor subsystem) that expose COM interfaces. These COM interfaces are used both internally and for extensibility (in the case of the public ones). EnvDTE is a legacy automation interface originally provided to allow extending the IDE more easily, primarily through the VB6 macro system (but also early extensions). Modern extensions can still use the EnvDTE interface, but it only wraps a subset of available COM interfaces. – Cameron Jun 24 '20 at 21:04
  • 1
    @Sabuncu So EnvDTE covers only a subset of the available extensibility points, and the COM interfaces provide the actual, lower-level implementations. Since EnvDTE can be cumbersome, particularly with respect to typing and error handling, there's no reason to prefer it over the COM interfaces even for the features they expose in common. Finally, newer extensibility features (particularly related to the editor) are often provided via MEF, which is not related to COM nor EnvDTE, and exposes further extensibility features not covered by the existing EnvDTE/COM interfaces. – Cameron Jun 24 '20 at 21:11
  • This was very helpful, thank you. EnvDTE and VSPackage are very confusing. These seem not to be mutually exclusive, and I haven't found clear guidance on how to proceed. I also have a recently posted, unanswered question, again if you have time: https://stackoverflow.com/questions/62555122/how-can-i-programmatically-examine-the-stack-in-my-visual-studio-extension Thank you once again. – Sabuncu Jun 25 '20 at 10:55
  • 1
    VSPackage is again something else entirely. The VS extensibility is based on "packages" that hook into the extension points and/or expose MEF components that are picked up by other parts of the IDE. – Cameron Jun 25 '20 at 15:06
  • Thank you Cameron. – Sabuncu Jun 25 '20 at 16:02
  • @Cameron On a separate topic, Is there an event that gets called before calling Debug Stop? I saw there is IVsDebugProcessNotify.BeforeStopDebuggingProcess() but I don't know how to use it...Actually I asked a separate question for this. Would appreciate anyone who could help ...https://stackoverflow.com/questions/68467805/visual-studio-extension-capturing-event-before-stopping-the-debug-process-ivsd – remondo Jul 21 '21 at 10:37