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?
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?
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.
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);
}
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.