Logo
HOWTO: Get the project flavor (subtype) of a Visual Studio project from an add-in

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio 2005
Date: February 2007   Microsoft Visual Studio 2008
Updated: March 2013   Microsoft Visual Studio 2010
      Microsoft Visual Studio 2012

Introduction

Visual Studio projects have a project type (such as VB.NET project, C# project, etc.) and each project type can have a flavor (or subtype), which is a specialized project based on the project type to customize its behavior without forcing to create a whole new project type. For example, you can have Test projects, which are based on the VB.NET or C# project types, but are specialized to create and run tests. You can learn more about project types and project subtypes in the Visual Studio 2005 SDK, sections Project Types and Project Subtypes.

Project types and subtypes are identified by Guids. The extensibility model for add-ins (EnvDTE.dll) allows you to know the Guid of the project type using the EnvDTE.Project.Kind property, but it does not allow you to get the Guid of the project subtype. This article explains how to get it using a service from the IDE.

More Information

Visual Studio stores in the .vbproj or .csproj file the project type and subtype Guids of a project. For example, if you open with a text editor a Test Project file created with VB.NET, you will find this XML entry:

<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}</ProjectTypeGuids>

The list of Guids for projects types and subtypes supported by your Visual Studio installation is in this registry entry:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Projects

where we see that the Guid {F184B08F-C81C-45F6-A57F-5ABD9991F28F} matches a VB.NET project (the project type) and the Guid {3AC096D0-A1C2-E12C-1390-A8335801FDAB} matches the Test Project subtype. See the article INFO: List of known project type Guids.

The EnvDTE.Project.Kind property returns the project type ({F184B08F-C81C-45F6-A57F-5ABD9991F28F} in this case for the Test Project) and there is no way using the extensibility model to get the project subtype. Fortunately you can use services from the IDE as explained in the article HOWTO: Get a Visual Studio service from an add-in. Specifically, we can use the Microsoft.VisualStudio.Shell.Interop.IVsAggregatableProject interface and its GetAggregateProjectTypeGuids method as shown below (VB.NET code). You will need to add references to the following assemblies (see the article HOWTO: Reference a Visual Studio assembly in the GAC from an add-in):

  • Microsoft.VisualStudio.OLE.Interop
  • Microsoft.VisualStudio.Shell.Interop
  • Microsoft.Visualstudio.Shell.Interop.8.0

Given an EnvDTE.Project, the following function returns a list of project type and subtype Guids separated by ";" that you can then split into individual Guids:

Language: VB.NET   Copy Code Copy Code (IE only)
   Public Function GetProjectTypeGuids(ByVal proj As EnvDTE.Project) As String

      Dim projectTypeGuids As String = ""
      Dim service As Object
      Dim solution As Microsoft.VisualStudio.Shell.Interop.IVsSolution
      Dim hierarchy As Microsoft.VisualStudio.Shell.Interop.IVsHierarchy = Nothing
      Dim aggregatableProject As Microsoft.VisualStudio.Shell.Interop.IVsAggregatableProject
      Dim result As Integer

      service = GetService(proj.DTE, GetType(Microsoft.VisualStudio.Shell.Interop.SVsSolution))
      solution = CType(service, Microsoft.VisualStudio.Shell.Interop.IVsSolution)

      result = solution.GetProjectOfUniqueName(proj.UniqueName, hierarchy)

      If result = 0 Then
         aggregatableProject = CType(hierarchy, Microsoft.VisualStudio.Shell.Interop.IVsAggregatableProject)
         result = aggregatableProject.GetAggregateProjectTypeGuids(projectTypeGuids)
      End If

      Return projectTypeGuids

   End Function

   Public Function GetService(ByVal serviceProvider As Object, ByVal type As System.Type) As Object
      Return GetService(serviceProvider, type.GUID)
   End Function

   Public Function GetService(ByVal serviceProviderObject As Object, ByVal guid As System.Guid) As Object

      Dim service As Object = Nothing
      Dim serviceProvider As Microsoft.VisualStudio.OLE.Interop.IServiceProvider
      Dim serviceIntPtr As IntPtr
      Dim hr As Integer
      Dim SIDGuid As Guid
      Dim IIDGuid As Guid

      SIDGuid = guid
      IIDGuid = SIDGuid
      serviceProvider = CType(serviceProviderObject, Microsoft.VisualStudio.OLE.Interop.IServiceProvider)
      hr = serviceProvider.QueryService(SIDGuid, IIDGuid, serviceIntPtr)

      If hr <> 0 Then
         System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(hr)
      ElseIf Not serviceIntPtr.Equals(IntPtr.Zero) Then
         service = System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(serviceIntPtr)
         System.Runtime.InteropServices.Marshal.Release(serviceIntPtr)
      End If

      Return service

   End Function
Language: C#   Copy Code Copy Code (IE only)
   public string GetProjectTypeGuids(EnvDTE.Project proj)
   {

      string projectTypeGuids = "";
      object service = null;
      Microsoft.VisualStudio.Shell.Interop.IVsSolution solution = null;
      Microsoft.VisualStudio.Shell.Interop.IVsHierarchy hierarchy = null;
      Microsoft.VisualStudio.Shell.Interop.IVsAggregatableProject aggregatableProject = null;
      int result = 0;

      service = GetService(proj.DTE, typeof(Microsoft.VisualStudio.Shell.Interop.IVsSolution));
      solution = (Microsoft.VisualStudio.Shell.Interop.IVsSolution)service;

      result = solution.GetProjectOfUniqueName(proj.UniqueName, hierarchy);

      if (result == 0)
      {
         aggregatableProject = (Microsoft.VisualStudio.Shell.Interop.IVsAggregatableProject) hierarchy;
         result = aggregatableProject.GetAggregateProjectTypeGuids(projectTypeGuids);
      }

      return projectTypeGuids;

   }

   public object GetService(object serviceProvider, System.Type type)
   {
      return GetService(serviceProvider, type.GUID);
   }

   public object GetService(object serviceProviderObject, System.Guid guid)
   {

      object service = null;
      Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider = null;
      IntPtr serviceIntPtr;
      int hr = 0;
      Guid SIDGuid;
      Guid IIDGuid;

      SIDGuid = guid;
      IIDGuid = SIDGuid;
      serviceProvider = (Microsoft.VisualStudio.OLE.Interop.IServiceProvider)serviceProviderObject;
      hr = serviceProvider.QueryService(SIDGuid, IIDGuid, serviceIntPtr);

      if (hr != 0)
      {
         System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(hr);
      }
      else if (!serviceIntPtr.Equals(IntPtr.Zero))
      {
         service = System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(serviceIntPtr);
         System.Runtime.InteropServices.Marshal.Release(serviceIntPtr);
      }

      return service;
   }

Related articles


Go back to the 'Resources for Visual Studio .NET extensibility' section for more articles like this


Top