Project Subtypes Design


The new home for Visual Studio documentation is Visual Studio 2017 Documentation on

The latest version of this topic can be found at Project Subtypes Design.

Project subtypes let VSPackages extend projects based on the Microsoft Build Engine (MSBuild). The use of aggregation lets you reuse the bulk of the core managed project system implemented in Visual Studio yet still customize the behavior for a particular scenario.

The following topics detail the basic design and implementation of project subtypes:

  • Project Subtype Design.

  • Multi-level Aggregation.

  • Supporting Interfaces.

The initialization of a project subtype is achieved by aggregating the main IVsHierarchy and IVsProject objects. This aggregation enables a project subtype to override or enhance most of the capabilities of the base project. Project subtypes get the first chance to handle properties using IVsHierarchy, commands using IOleCommandTarget and IVsUIHierarchy, and project item management using IVsProject3. Project subtypes can also extend:

  • Project configuration objects.

  • Configuration-dependent objects.

  • Configuration-independent browse objects.

  • Project automation objects.

  • Project automation property collections.

For more information on extensibility by project subtypes, see Properties and Methods Extended by Project Subtypes.

Policy Files

The Visual Studio environment provides an example of extending the base project system with a project subtype in its implementation of policy files. A policy file allows the shaping of the Visual Studio environment by managing features that include the Solution Explorer, Add Project dialog box, Add New Item dialog box and the Properties dialog box. The policy subtype overrides and enhances these features through IVsFilterAddProjectItemDlg, IOleCommandTarget and IVsUIHierarchy implementations.

Aggregation Mechanism

The environment's project subtype aggregation mechanism supports multiple levels of aggregation, thus allowing an advanced subtype to be implemented by further flavoring a flavored project. Also, the supporting objects of a project subtype, such as IVsProjectFlavorCfg, are designed to allow multiple levels of layering. In keeping with the constraints of COM and COM aggregation rules, project subtypes and base projects need to be programmed cooperatively to enable the inner subtype or the base project to properly participate in delegating method calls and managing reference counts. That is, the project about to be aggregated has to be programmed to support aggregation.

The following illustration shows a schematic representation of a multi-level project subtype aggregation.

Visual Studio multilevel projectflavor graphic
Multilevel Project Subtype

A multi-level project subtype aggregation consists of three levels, a base project, which is aggregated by a project subtype, then further aggregated by an advanced project subtype. The figure focuses on some of the supporting interfaces that are provided as a part of the Visual Studio project subtype architecture.

Deployment Mechanisms

Among many of the base project system functionalities enhanced by a project subtype are deployment mechanisms. A project subtype influences deployment mechanisms by implementing configuration interfaces (such as IVsDeployableProjectCfg and IVsBuildableProjectCfg) that are retrieved by calling QueryInterface on IVsProjectCfgProvider. In a scenario where both the project subtype and the advanced project subtype add different configuration implementations, the base project calls QueryInterface on the advanced project subtype's IUnknown. If the inner project subtype contains the configuration implementation that the base project is asking for, the advanced project subtype delegates to the implementation provided by the inner project subtype. As a mechanism to persist state from one aggregation level to another, all the levels of project subtypes implement IPersistXMLFragment to persist non-build related XML data into the project files. For more information, see Persisting Data in the MSBuild Project File. IInternalExtenderProvider is implemented as a mechanism to retrieve automation extenders from the project subtypes.

The following illustration focuses on the automation extender implementation, the project configuration browse object in particular, used by project subtypes to extend the base project system.

VS Project Flavor Auto Extender graphic
Project Subtype Automation Extender.

Project subtypes can further extend the base project system by extending the automation object model. These are defined as a part of the DTE automation object and are used to extend the Project object, the ProjectItem object and the Configuration object. For more information see, Extending the Object Model of the Base Project.

A project subtype implementation that wraps a lower level project subtype needs to be programmed cooperatively to allow the inner project subtype to function properly. A list of programming responsibilities includes:

  • The IPersistXMLFragment implementation of the project subtype that is wrapping the inner subtype must delegate to the IPersistXMLFragment implementation of the inner project subtype for both Load and Save methods.

  • The IInternalExtenderProvider implementation of the wrapper project subtype must delegate to that of its inner project subtype. In particular, the implementation of GetExtenderNames needs to get the string of names from the inner project subtype and then concatenate the strings it wants to add as extenders.

  • The IVsProjectCfgProvider implementation of a wrapper project subtype must instantiate the IVsProjectFlavorCfg object of its inner project subtype and hold it as a private delegate, since only the base project's project configuration object directly knows that the wrapper project subtype configuration object exists. The outer project subtype can initially choose configuration interfaces it wants to handle directly, and then delegate the rest to the inner project subtype's implementation of get_CfgType.

The base project delegates calls to supporting interfaces added by a project subtype, to extend various aspects of its implementation. This includes extending project configuration objects and various property browser objects. These interfaces are retrieved by calling QueryInterface on punkOuter (a pointer to the IUnknown) of the outermost project subtype aggregator.

InterfaceProject Subtype
IVsProjectFlavorCfgAllows the project subtype to:

- Provide an implementation of IVsDeployableProjectCfg.
- Control the launch of the debugger by allowing the project subtype to provide its own implementation of IVsDebuggableProjectCfg.
- Disable design-time expression evaluation by appropriately handling the DBGLAUNCH_DesignTimeExprEval case in its implementation of QueryDebugLaunch.
IInternalExtenderProviderAllows the project subtype to:

- Extend the VSHPROPID_BrowseObject of the project to add or remove configuration independent properties of the project.
- Extend the project automation object (VSHPROPID_ExtObject) of the project.

Property values above are taken from __VSHPROPID2 enumeration.
IVsCfgBrowseObjectAllows the project subtype to map back to the IVsCfg object given the project configuration browse object.
IVsBrowseObjectAllows the project subtype to map back to the IVsHierarchy or the VSITEMID object, given the project configuration browse object.
IPersistXMLFragmentAllows the project subtype to persist arbitrary XML structured data to the project file (.vbproj or .csproj). This data is not visible to MSBuild.
IVsBuildPropertyStorageAllows the project subtype to:

- Add new MSBuild properties to be persisted.
- Remove unnecessary properties from MSBuild.
- Query for a current value of an MSBuild property.
- Change the current value of an MSBuild property.