1

I'd like my VSIX does something different in my BuildEvents.OnBuildDone handler, if the build has been triggered because the user wants to start a Debug session.

I've tried...

private void m_BuildEvents_OnBuildDone(vsBuildScope scope, vsBuildAction action) {
   if (m_DTE.Mode == vsIDEMode.vsIDEModeDebug) {
      //...
   }
}

...but unfortunately at that point m_DTE.Mode is not yet equal to vsIDEMode.vsIDEModeDebug.

I could start a one or two seconds timer and then check if (m_DTE.Mode == vsIDEMode.vsIDEModeDebug) but this is not a clean and reliable solution.

Can I know from querying the VSIX API somehow, either in BuildEvents.OnBuildBegin or BuildEvents.OnBuildDone handler, that a successful build will be followed by a Debug session?

Patrick from NDepend team
  • 13,237
  • 6
  • 61
  • 92
  • 1
    You could determine that the debugger changes mode using IVsDebugger.AdviseDebuggerEvents that will be followed by a call to your implementation of IVsDebuggerEvents.OnModeChange() (with DBGMODE_Run) but this will happen *after* the build is done, so it's just a bit cleaner than a wait... – Simon Mourier Nov 25 '15 at 23:13

1 Answers1

5

You can monitor Debug.Start command invocation with EnvDTE.CommandEvents. See the following sample C# extension for Visual Commander:

public class E : VisualCommanderExt.IExtension
{
    public void SetSite(EnvDTE80.DTE2 DTE, Microsoft.VisualStudio.Shell.Package package)
    {
        events = DTE.Events;
        commandEvents = events.get_CommandEvents(null, 0);
        buildEvents = events.BuildEvents;
        commands = DTE.Commands as EnvDTE80.Commands2;

        commandEvents.BeforeExecute += OnBeforeExecute;
        commandEvents.AfterExecute += OnAfterExecute;

        buildEvents.OnBuildDone += OnBuildDone;
        buildEvents.OnBuildBegin += OnBuildBegin;
    }

    public void Close()
    {
        commandEvents.BeforeExecute -= OnBeforeExecute;
        commandEvents.AfterExecute -= OnAfterExecute;

        buildEvents.OnBuildDone -= OnBuildDone;
        buildEvents.OnBuildBegin -= OnBuildBegin;
    }

    private void OnBeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
    {
        string name = GetCommandName(Guid, ID);
        if (name == "Debug.Start")
        {
            System.Windows.MessageBox.Show("OnBeforeExecute Debug.Start");
        }
    }

    private void OnAfterExecute(string Guid, int ID, object CustomIn, object CustomOut)
    {
        string name = GetCommandName(Guid, ID);
        if (name == "Debug.Start")
        {
            System.Windows.MessageBox.Show("OnAfterExecute Debug.Start " + System.DateTime.Now.Second + "." + System.DateTime.Now.Millisecond);
        }
    }

    private void OnBuildDone(EnvDTE.vsBuildScope scope, EnvDTE.vsBuildAction action)
    {
        System.Windows.MessageBox.Show("OnBuildDone " + System.DateTime.Now.Second + "." + System.DateTime.Now.Millisecond);
    }

    private void OnBuildBegin(EnvDTE.vsBuildScope scope, EnvDTE.vsBuildAction action)
    {
        System.Windows.MessageBox.Show("OnBuildBegin " + System.DateTime.Now.Second + "." + System.DateTime.Now.Millisecond);
    }

    // throw()
    private string GetCommandName(string Guid, int ID)
    {
        if (Guid == null)
            return "null";

        string result = "";
        if (commands != null)
        {
            try
            {
                return commands.Item(Guid, ID).Name;
            }
            catch (System.Exception)
            {
            }
        }
        return result;
    }

    private EnvDTE.Events events;
    private EnvDTE.CommandEvents commandEvents;
    private EnvDTE.BuildEvents buildEvents;
    private EnvDTE80.Commands2 commands;
}

On my machine the sequence of events is following:

  1. OnBeforeExecute Debug.Start
  2. OnBuildBegin
  3. OnAfterExecute Debug.Start
  4. OnBuildDone

So, if you see this sequence, it will be followed by a Debug session.


To complete the Serge answer. Actually I observe this order:

  1. OnBeforeExecute Debug.Start
  2. OnAfterExecute Debug.Start
  3. OnBuildBegin
  4. OnBuildDone

Moreover OnBuildBegin is skipped if VisualStudio estimates it has nothing to build before debugging.

OnBuildBegin or (if skipped) OnBuildDone is always executed just after OnAfterExecute Debug.Start (tested on VS2010/2012/2013/2015).

Spying others command, I can see two commands Build.SolutionConfigurations (and sometime also one or several Debug.StartupProject) are ran in between before/after execute Debug.Start (I observed this behavior only in in VS2013/2015).

  1. OnBeforeExecute Debug.Start
  2. OnBeforeExecute Build.SolutionConfigurations
  3. OnAfterExecute Build.SolutionConfigurations
  4. OnBeforeExecute Build.SolutionConfigurations
  5. OnAfterExecute Build.SolutionConfigurations
  6. OnBeforeExecute Debug.StartupProjects
  7. OnAfterExecute Debug.StartupProjects
  8. OnAfterExecute Debug.Start
  9. OnBuildBegin
  10. OnBuildDone

Hence we can infer that a successful build will be followed by a Debug session happens when one of these two events occurs:

  • when a Build.SolutionConfigurations or a Debug.StartupProjects command is triggered in between before/after Debug.Start command.
  • when there is less than a second between the last OnAfterExecute Debug.Start and the current OnBuildBegin or OnBuildDone.

As a side note the command Debug.StartWithoutDebugging plays the same role as Debug.Start when the user asks to start without debugging. Hence we can also infer a successful build will be followed by a run (with no debug) session

Patrick from NDepend team
  • 13,237
  • 6
  • 61
  • 92
Sergey Vlasov
  • 26,641
  • 3
  • 64
  • 66