How to get notification when a successful build has finished?
Asked Answered
T

3

11

I'm writing an VS add-in and I need to run a certain method after a successful build. I've tried using dte.Events.BuildEvents.OnBuildDone but that event happens even if the build failed.

Is there a property or some other event I should use?

Turpitude answered 10/5, 2010 at 10:44 Comment(0)
G
13

The OnBuildDone event cannot tell you what happened. Some projects in the solution might have built properly, some didn't. You'll need OnBuildProjConfigDone instead. Fires for each project, the Success argument tells you if it worked.

Gassy answered 10/5, 2010 at 12:40 Comment(3)
In my case the OnBuildDone never fired, but the OnBuildProjConfigDone worked okKanchenjunga
@DinisCruz Sometimes OnBuildDone doesn't fire if you don't hold reference to dte.Events.BuildEventsHercegovina
There is a full code sample of how to do this here: github.com/edsykes/VisualStudioBuildEventsRhea
F
7

Typically, you need to handle multiple projects being built. This could be a solution build, or building a project that is dependent on another project.

So, to figure out when a successful build has finished, you need to use a combination of the two build events:

OnBuildProjConfigDone and OnBuildDone.

You will also need a member variable to track the overall build status.

Your OnBuildProjConfigDone handler will get called for each project that gets built, and it gets passed a bool to tell you whether that project build was successful. Assign this result to your member variable to keep track of the overall status.

Finally, your OnBuildDone handler will get called. In here, you can look at your member variable to see if any project build failed.

Here is some example code from an extension I wrote for VS2012. The extension provides a "custom build" command that builds the active project and launches the debugger if the build was successful.

private bool _overallBuildSuccess;
private bool _customBuildInProgress;

private void CustomBuild_MenuItemCallback(object sender, EventArgs e)
{
    // Listen to the necessary build events.
    DTE2 dte = (DTE2)GetGlobalService(typeof(SDTE));
    dte.Events.BuildEvents.OnBuildDone += BuildEvents_OnBuildDone;
    dte.Events.BuildEvents.OnBuildProjConfigDone += BuildEvents_OnBuildProjConfigDone;

    try
    {
        // Build the active project.
        _customBuildInProgress = true;
        dte.ExecuteCommand("Build.BuildSelection");
    }
    catch (COMException)
    {
        _customBuildInProgress = false;
        WriteToOutputWindow("Build", "Could not determine project to build from selection");
    }
}

private void BuildEvents_OnBuildProjConfigDone(string project, string projectConfig, string platform, string solutionConfig, bool success)
{
    // Ignore this build event if we didn't start it.
    if (!_customBuildInProgress)
    {
        return;
    }

    // Keep track of the overall build success.
    _overallBuildSuccess = success;
}

private void BuildEvents_OnBuildDone(EnvDTE.vsBuildScope scope, EnvDTE.vsBuildAction action)
{
    // Ignore this build event if we didn't start it.
    if (!_customBuildInProgress)
    {
        return;
    }

    _customBuildInProgress = false;

    if (_overallBuildSuccess)
    {
        // Launch the debugger.
        DTE2 dte = (DTE2)GetGlobalService(typeof(SDTE));
        dte.ExecuteCommand("Debug.Start");
    }
    else
    {
        WriteToOutputWindow("Build", "Custom build failed.");
    }
}

private void WriteToOutputWindow(string paneName, string message)
{
    DTE2 dte = (DTE2)GetGlobalService(typeof(SDTE));

    Window window = dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);
    OutputWindow outputWindow = (OutputWindow)window.Object;

    OutputWindowPane targetPane = outputWindow.OutputWindowPanes.Cast<OutputWindowPane>()
        .FirstOrDefault(x => x.Name.ToLower() == paneName.ToLower());

    if (targetPane == null)
    {
        targetPane = outputWindow.OutputWindowPanes.Add(paneName);
    }

    targetPane.Activate();
    outputWindow.ActivePane.OutputString(message);
    outputWindow.ActivePane.OutputString(Environment.NewLine);
}
Farflung answered 22/11, 2012 at 14:43 Comment(2)
What is the "GetGlobalService" ? I am on VS2010, maybe a 2012 specific item?Welladvised
GetGlobalService is a method on Microsoft.VisualStudio.Shell.Package, which my extension subclasses.Farflung
W
2

For future readers, check out this article.

http://blogs.msdn.com/b/alexpetr/archive/2012/08/14/visual-studio-2012-and-buildevents-in-addins.aspx

and/or

http://support.microsoft.com/kb/555102/en-us

Basically, there could be a bug. The work-around is to set a member variable of the ".BuildEvents" on Connect.

Example:

private _BuildEvents _buildEvents;

public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
              {
                _buildEvents = _applicationObject.Events.BuildEvents;
              }

Then wire up the event handlers to

this._buildEvents

and not

_applicationObject.Events.BuildEvents

where _applicationObject = (EnvDTE.DTE)application;

It's worth a try at least, IMHO.

Welladvised answered 11/9, 2013 at 19:38 Comment(1)
Shoot. Now that I wrote the above, I found a very good SOF response. #14166385Welladvised

© 2022 - 2024 — McMap. All rights reserved.