Code is included in the link...
<#@ template language="C#" hostspecific="True" debug="True" #> <#@ output extension="cs" #> <#@ assembly name="System.Core" #> <#@ assembly name="System.Xml" #> <#@ assembly name="Microsoft.VisualStudio.Shell.Interop.8.0" #> <#@ assembly name="EnvDTE" #> <#@ assembly name="EnvDTE80" #> <#@ import namespace="System.Collections.Generic" #> <#@ import namespace="System.IO" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Text.RegularExpressions" #> <#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #> <#@ import namespace="EnvDTE" #> <#@ import namespace="EnvDTE80" #> <# var serviceProvider = Host as IServiceProvider; if (serviceProvider != null) { Dte = serviceProvider.GetService(typeof(SDTE)) as DTE; } // Fail if we couldn't get the DTE. This can happen when trying to run in TextTransform.exe if (Dte == null) { throw new Exception("T4Generator can only execute through the Visual Studio host"); } foreach(var project in Dte.Solution.Projects.Cast<Project>() .Where(p=> p.CodeModel!=null && p.Name!="Solution Items")) { //var appRoot= Path.GetDirectoryName(project.FullName) + '\\'; var rootNamespace = project.Properties.Item("RootNamespace").Value.ToString(); WriteLine("//Project:"+project.Name); #><# WriteLine(string.Empty);#>namespace <#= rootNamespace #>.T4Helper{ <# WriteLine("#region "+project.Name+ " properties"); WriteLine(string.Empty); foreach(var prop in project.Properties.Cast<EnvDTE.Property>()) { Write("//"+prop.Name+" : "); try { WriteLine(prop.Value.ToString()); } catch (Exception ex) { WriteLine("Exception : "+ex.Message); } } WriteLine("#endregion"); WriteLine(string.Empty); ProcessFileCodeModel(project); WriteLine(string.Empty); WriteLine("}"); } #> <#+ //const string Kind_PhysicalFolder = "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}"; bool AlwaysKeepTemplateDirty = true; static DTE Dte; void ProcessFileCodeModel(Project project) { foreach(var item in project.ProjectItems.Cast<ProjectItem>()) { WriteLine("//Found item:"+item.Name); if(item.FileCodeModel!=null ) { WriteLine("//Found CodeModel:"+item.FileCodeModel.GetType().FullName); RecurseFindElements(item.FileCodeModel.CodeElements); } } } void WriteMapping(CodeClass codeClass) { WriteLine("///"+codeClass.FullName); WriteLine("public static class "+MakeIntoValidIdentifier(codeClass.Name)+"{"); PushIndent("\t"); WriteLine("public static string MetaName{get{return \""+codeClass.Name+"\";}}"); RecurseFindElements(codeClass.Children); PopIndent(); WriteLine("}"); WriteLine(string.Empty); } void WriteMapping(CodeProperty codeProperty) { WriteLine("///"+codeProperty.FullName); WriteLine("public static string Meta"+MakeIntoValidIdentifier(codeProperty.Name)+"{ get{ return \""+ codeProperty.Name+"\";}}"); //WriteLine("public static string MetaBinding"+MakeIntoValidIdentifier(codeProperty.Name)+"{ get{ return \"" //+codeProperty.Parent.Name+"."+codeProperty.Name+"\";}}"); } void WriteMapping(CodeFunction codeFunction) { WriteLine("///"+codeFunction.FullName); WriteLine("public static string Meta"+codeFunction.Name+"{ get{ return \""+ codeFunction.Name+"\";}}"); } private void RecurseFindElements(CodeElements codeElements) { var q=codeElements.Cast<CodeElement>( ) //.Where(x =>x is CodeInterface||x is CodeClass || x is CodeNamespace) //&& ((CodeInterface)x).Attributes.Count>0) //.Where(x => x.Name.StartsWith("System")==false) //.Where(x => x.Name.StartsWith("Infragistics")==false) //.Where(x => x.Name.StartsWith("Microsoft")==false) //.Where(x => x.Name.StartsWith("ICSharpCode")==false) ; var functions=new List<string>(); foreach (var element in q) { if (element is CodeFunction && functions.Contains(element.Name)==false) { WriteMapping(element as CodeFunction); functions.Add(element.Name); } if(element is CodeProperty) { WriteMapping(element as CodeProperty); } if (element is CodeInterface) { var c = (CodeInterface)element; RecurseFindElements(c.Members); } if (element is CodeClass) { var c = (CodeClass)element; //verify element is a project element not an external if (c.InfoLocation==vsCMInfoLocation.vsCMInfoLocationProject) { WriteMapping(c); } } if (element is CodeNamespace) { var ns=(CodeNamespace)element; RecurseFindElements(ns.Members); } } } string MakeIntoValidIdentifier(string arbitraryString) { var validIdentifier = Regex.Replace(arbitraryString, @"[^A-Za-z0-9-._]", " "); validIdentifier = ConvertToPascalCase(validIdentifier); if (Regex.IsMatch(validIdentifier, @"^\d")) validIdentifier = "_" + validIdentifier; return validIdentifier; } string ConvertToPascalCase(string phrase) { string[] splittedPhrase = phrase.Split(' ', '-', '.'); var sb = new StringBuilder(); sb = new StringBuilder(); foreach (String s in splittedPhrase) { char[] splittedPhraseChars = s.ToCharArray(); if (splittedPhraseChars.Length > 0) { splittedPhraseChars[0] = ((new String(splittedPhraseChars[0], 1)).ToUpper().ToCharArray())[0]; } sb.Append(new String(splittedPhraseChars)); } return sb.ToString(); } void EmitNamesInnerClass(List<string> names) { if(names.Any()) { WriteLine("\r\n\t\tpublic static class Names"); WriteLine("\t\t{"); foreach(var name in names) WriteLine(string.Format("\t\t\tpublic const string {0} = \"{0}\";", name)); WriteLine("\t\t}"); names.Clear(); } } Project GetProjectContainingT4File(DTE dte) { // Find the .tt file's ProjectItem ProjectItem projectItem = dte.Solution.FindProjectItem(Host.TemplateFile); // If the .tt file is not opened, open it if (projectItem.Document == null) projectItem.Open(Constants.vsViewKindCode); if (AlwaysKeepTemplateDirty) { // Mark the .tt file as unsaved. This way it will be saved and update itself next time the // project is built. Basically, it keeps marking itself as unsaved to make the next build work. // Note: this is certainly hacky, but is the best I could come up with so far. projectItem.Document.Saved = false; } return projectItem.ContainingProject; } #>



hi,
ReplyDeletethanks for the post is is very useful like example to combine t4 and envdte.
only one question
in the line
"Dte = serviceProvider.GetService(typeof(SDTE)) as DTE;
"
what is it "SDTE" could be substituted by EnvDTE.DTE
thanks again
This should be Microsoft.VisualStudio.Shell.Interop.SDTE
ReplyDeletehttp://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.sdte.aspx
thanks again
ReplyDeleteI'm not able to find it
sorry for my english, I mean "I wasn't able" until your explanation.
ReplyDeleteand thanks for the post.