Get The ProjectItem of a T4 Template From Inside the T4 Template

So you got a T4 template and need access to the ProjectItem of that T4 template or to the parent Project of the T4 template? Here’s how:

1) Set the template’s hostspecific attribute to true and reference the Visual Studio Automation assemblies.

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="envdte" #>
<#@ assembly name="envdte80" #>
<#@ import namespace="EnvDTE" #>

2) Get the Project or ProjectItem using Visual Studio Automation.

// By setting the template's 'hostspecific' property to true, 
// we get access to the text templating engine host 
// which implements IServiceProvider.
var serviceProvider = (IServiceProvider)this.Host;

// Get the automation root object
var dte = (EnvDTE.DTE)serviceProvider.GetService(typeof(EnvDTE.DTE));

// Get the project item
var projectItem = dte.Solution.FindProjectItem(this.Host.TemplateFile);

// Get the project
var project = projectItem.ContainingProject;

Tell if an EnvDTE.Project is a Web Application

A Visual Studio Extension or Add-In might need to know whether or not a project is a web application (in my case, I needed to know whether I’ll expect app.congig or web.config). Due to a bug in Visual Studio, that is not so straight-forward. But thanks to Carlos J. Quintero, I got some code together.

If you need it, suit yourselves.

using System.Linq;
using EnvDTE;

namespace MuniHusseini.Demos
{
        public static bool IsWebProject(this Project project)
        {
            return project.Object is VsWebSite.VSWebSite || project.ProjectHasExtender("WebApplication");
        }

        public static bool ProjectHasExtender(this Project proj, string extenderName)
        {
            // See http://www.mztools.com/articles/2007/mz2007014.aspx for more information.

            try
            {
                // We could use proj.Extender(extenderName) but it causes an exception if not present and 
                // therefore it can cause performance problems if called multiple times. We use instead:

                var extenderNames = (object[])proj.ExtenderNames;

                return extenderNames.Length > 0 && extenderNames.Any(extenderNameObject => extenderNameObject.ToString() == extenderName);
            }
            catch
            {
                // Ignore
            }

            return false;
        }
    }
}

Convert IVsHierarchy to ProjectItem or Project

The title says it all… here you go:

Microsoft.VisualStudio.Shell.Interop.IVsHierarchy hierarchy = // ... get it.

// VSITEMID_ROOT gets the current project. 
// Alternativly, you might have another item id.
var itemid = VSConstants.VSITEMID_ROOT; 

object objProj;
hierarchy.GetProperty(itemid, (int)__VSHPROPID.VSHPROPID_ExtObject, out objProj);

var projectItem = objProj as EnvDTE.ProjectItem;
// ... or ...
var project = objProj as EnvDTE.Project;

Thanks to Ed Dore in the Visual Studio forums.