Search code examples
c#visual-studiobuildvisual-studio-extensionsenvdte

Current type of the build action from Visual Studio - Microsoft.VisualStudio.Shell.Interop


In some extension we implement the IVsUpdateSolutionEvents2 and IVsSolutionBuildManager2 used for registering caller with the AdviseUpdateSolutionEvents

For example, this called before any build actions have begun:

public int UpdateSolution_Begin(ref int pfCancelUpdate)
{
    ...
}

However, also need getting the status or type of the current build action, for example: build/rebuild/clean/deploy

Available & known variants:

BuildEvents

With the Events.BuildEvents i can subscribe to OnBuildBegin, for example:

_buildEvents.OnBuildBegin += new _dispBuildEvents_OnBuildBeginEventHandler((vsBuildScope Scope, vsBuildAction Action) => {
    buildType = (BuildType)Action;
});

and use the buildType in any places, because the vsBuildAction provides all the necessary information

but the UpdateSolution_Begin / UpdateSolution_StartUpdate called first as priority with advising method, and as result the buildType sets too late..

also we can use this OnBuildBegin instead of UpdateProjectCfg_Begin / UpdateSolution_StartUpdate, but our handling is also needed as soon as possible with priority caller

IVsUpdateSolutionEvents4

The IVsUpdateSolutionEvents4.UpdateSolution_BeginUpdateAction provides the dwAction and fired before every update action begins during solution build - before the first UpdateProjectCfg_Begin

it's exactly what i need! because dwAction i can check with the VSSOLNBUILDUPDATEFLAGS

However :( it appeared in VS2012, our extension supports the VS2010 and higher... so need also variant for 2010 version

UpdateProjectCfg_Begin

The IVsUpdateSolutionEvents2.UpdateProjectCfg_Begin also provides the dwAction (see also VSSOLNBUILDUPDATEFLAGS) and available for 2010 version, however it's the same as first BuildEvents variant - it's too late for handling (and not quite suitable for our task)

Question

I can't find documentation for this, however the VSSOLNBUILDUPDATEFLAGS available for VS2010, so i think should be variant for getting this as current state of the build action, e.g as with __VSHPROPID and GetProperty for IVsHierarchy etc...

is it possible ? or i can only with OnBuildBegin subscription o_O


upd1:

__VSHPROPID4

found with \VisualStudioIntegration\Common\Inc\vsshell100.h:

enum __VSHPROPID4
    {   VSHPROPID_TargetFrameworkMoniker    = -2102,
    VSHPROPID_ExternalItem  = -2103,
    VSHPROPID_SupportsAspNetIntegration = -2104,
    VSHPROPID_DesignTimeDependencies    = -2105,
    VSHPROPID_BuildDependencies = -2106,
    VSHPROPID_BuildAction   = -2107,
    VSHPROPID_DescriptiveName   = -2108,
    VSHPROPID_AlwaysBuildOnDebugLaunch  = -2109,
    VSHPROPID_FIRST4    = -2109
    } ;
typedef /* [public] */ DWORD VSHPROPID4;

so, looked doc. - BSTR __VSHPROPID4.VSHPROPID_BuildAction - retrieves the build action for an item

ok, good news, next step... try to get, for example:

object type;
hr.GetProperty((uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID4.VSHPROPID_BuildAction, out type);

where hr is a, for example:

IVsSolutionBuildManager2 sbm = (IVsSolutionBuildManager2)ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager));

IVsHierarchy hr = null;
sbm.get_StartupProject(out hr);

However, the type always is null... it may be problem with notifying(has not occurred), but also similar result if used the pHierProj from UpdateProjectCfg_Begin / UpdateProjectCfg_Done:

int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel)
int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel)

which already provides the dwAction...

and., how to use VSHPROPID_BuildAction -_- problem with IVsHierarchy ?


Solution

  • finished :)

    Solution 1

    CommandEvents

    With the EnvDTE.CommandEvents, we can work before processing IVsUpdateSolutionEvents2 and listen all incoming commands, sample:

    ...

    GUID: {5EFC7975-14BC-11CF-9B2B-00AA00573819} (ID: 882) :: Build.BuildSolution
    GUID: {5EFC7975-14BC-11CF-9B2B-00AA00573819} (ID: 883) :: Build.RebuildSolution
    GUID: {5EFC7975-14BC-11CF-9B2B-00AA00573819} (ID: 884) :: Build.DeploySolution
    GUID: {5EFC7975-14BC-11CF-9B2B-00AA00573819} (ID: 885) :: Build.CleanSolution
    GUID: {1496A755-94DE-11D0-8C3F-00C04FC2AAE2} (ID: 2005) :: Build.PublishSelection
    GUID: {1496A755-94DE-11D0-8C3F-00C04FC2AAE2} (ID: 353) :: Build.Link    
    ...
    

    for example:

    _cmdEvents.BeforeExecute += new _dispCommandEvents_BeforeExecuteEventHandler((string guid, int id, object customIn, object customOut, ref bool cancelDefault) => {
    
            if(GuidList.VSStd97CmdID == guid || GuidList.VSStd2KCmdID == guid) {
                _c.updateContext((BuildType)id);
            }
    
    });
    

    Now we can work with type of action in UpdateSolution_Begin, for example:

    if(evt.BuildType != BuildType.Common && evt.BuildType != buildType) {
        //...
    }
    

    ...

    if(buildType == BuildType.Clean || buildType == BuildType.LinkOnly){
       //...
    }
    

    etc.

    full example you can see in sources (see comment where). Also, i think it’s not best variant, however it's variant for VS2010 and higher versions (also should work on very older 2005 & 2008, i think)…

    For VS2012 and newer i recommend the IVsUpdateSolutionEvents4

    So, my problem solved.

    Other best variants ?