/Releases/1.2/Source/DslPackage/CustomCode/CodeGeneration/VsMultipleFileGenerator.cs
C# | 309 lines | 228 code | 42 blank | 39 comment | 36 complexity | 6221974c4ddde3c48c1c02d8e02cdead MD5 | raw file
- using System;
- using System.Collections.Generic;
- using System.Text;
- using Microsoft.VisualStudio.TextTemplating.VSHost;
- using Microsoft.VisualStudio.OLE.Interop;
- using Microsoft.VisualStudio.Shell;
- using System.Runtime.InteropServices;
- using System.IO;
- using System.ComponentModel;
- using System.Linq;
- using Microsoft.VisualStudio;
- using Microsoft.VisualStudio.Shell.Interop;
-
- /*
- * Based on the code found here:
- * http://www.codeproject.com/KB/cs/VsMultipleFileGenerator.aspx
- */
-
- namespace Microsoft.Samples.DslTools.ConfigurationSectionDesigner
- {
- public abstract class VsMultipleFileGenerator<IterativeElementType> : IEnumerable<IterativeElementType>, Microsoft.VisualStudio.TextTemplating.VSHost.IVsSingleFileGenerator, IObjectWithSite
- {
- #region Visual Studio Specific Fields
- private object site;
- private ServiceProvider serviceProvider = null;
- #endregion
-
- #region Our Fields
- private string bstrInputFileContents;
- private string wszInputFilePath;
- private EnvDTE.Project project;
-
- private List<string> newFileNames;
- #endregion
-
- [CLSCompliant(false)]
- protected EnvDTE.Project Project
- {
- get
- {
- return project;
- }
- }
-
- protected string InputFileContents
- {
- get
- {
- return bstrInputFileContents;
- }
- }
-
- protected string InputFilePath
- {
- get
- {
- return wszInputFilePath;
- }
- }
-
- protected object Site
- {
- get { return site; }
- }
-
- [CLSCompliant(false)]
- protected ServiceProvider SiteServiceProvider
- {
- get
- {
- if( serviceProvider == null )
- {
- Microsoft.VisualStudio.OLE.Interop.IServiceProvider oleServiceProvider = site as Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
- serviceProvider = new ServiceProvider( oleServiceProvider );
- }
- return serviceProvider;
- }
- }
-
- private Microsoft.VisualStudio.TextTemplating.VSHost.IVsGeneratorProgress _generatorProgress;
- protected Microsoft.VisualStudio.TextTemplating.VSHost.IVsGeneratorProgress GeneratorProgress
- {
- get
- {
- return _generatorProgress;
- }
- }
-
- public VsMultipleFileGenerator()
- {
- EnvDTE.DTE dte = (EnvDTE.DTE)Package.GetGlobalService( typeof( EnvDTE.DTE ) );
- Array ary = (Array)dte.ActiveSolutionProjects;
- if( ary.Length > 0 )
- {
- project = (EnvDTE.Project)ary.GetValue( 0 );
-
- }
- newFileNames = new List<string>();
- }
- public abstract IEnumerator<IterativeElementType> GetEnumerator();
-
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- protected abstract string GetFileName( IterativeElementType element );
- public abstract byte[] GenerateContent( IterativeElementType element );
- public abstract string GetDefaultExtension();
-
-
- public abstract byte[] GenerateDefaultContent();
-
- public void Generate( string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, out IntPtr rgbOutputFileContents, out int pcbOutput, Microsoft.VisualStudio.TextTemplating.VSHost.IVsGeneratorProgress pGenerateProgress )
- {
- this.bstrInputFileContents = bstrInputFileContents;
- this.wszInputFilePath = wszInputFilePath;
- this._generatorProgress = pGenerateProgress;
- this.newFileNames.Clear();
-
- int iFound = 0;
- uint itemId = 0;
- EnvDTE.ProjectItem item;
- Microsoft.VisualStudio.Shell.Interop.VSDOCUMENTPRIORITY[] pdwPriority = new Microsoft.VisualStudio.Shell.Interop.VSDOCUMENTPRIORITY[1];
-
- // obtain a reference to the current project as an IVsProject type
- Microsoft.VisualStudio.Shell.Interop.IVsProject VsProject = VsHelper.ToVsProject( project );
- // this locates, and returns a handle to our source file, as a ProjectItem
- VsProject.IsDocumentInProject( InputFilePath, out iFound, pdwPriority, out itemId );
-
- // if our source file was found in the project (which it should have been)
- if( iFound != 0 && itemId != 0 )
- {
- Microsoft.VisualStudio.OLE.Interop.IServiceProvider oleSp = null;
- VsProject.GetItemContext( itemId, out oleSp );
- if( oleSp != null )
- {
- ServiceProvider sp = new ServiceProvider( oleSp );
- // convert our handle to a ProjectItem
- item = sp.GetService( typeof( EnvDTE.ProjectItem ) ) as EnvDTE.ProjectItem;
- }
- else
- throw new ApplicationException( "Unable to retrieve Visual Studio ProjectItem" );
- }
- else
- throw new ApplicationException( "Unable to retrieve Visual Studio ProjectItem" );
-
- // now we can start our work, iterate across all the 'elements' in our source file
- foreach( IterativeElementType element in this )
- {
- try
- {
- // obtain a name for this target file
- string fileName = GetFileName( element );
- // add it to the tracking cache
- newFileNames.Add( fileName );
- // fully qualify the file on the filesystem
- string strFile = Path.Combine( wszInputFilePath.Substring( 0, wszInputFilePath.LastIndexOf( Path.DirectorySeparatorChar ) ), fileName );
-
- FileStream fs = null;
- try
- {
- // generate our target file content
- byte[] data = GenerateContent( element );
-
- // if data is null, it means to ignore the contents of the generated file
- if( data == null ) continue;
-
- if( File.Exists( strFile ) )
- {
- // If the file already exists, only save the data
- // if the generated file is different than the
- // existing file.
- byte[] oldData = File.ReadAllBytes( strFile );
-
- bool equal = true;
- if( oldData.Length == data.Length )
- {
- for( int i = 0; i < oldData.Length; i++ )
- if( oldData[i] != data[i] )
- {
- equal = false;
- break;
- }
- }
- else
- equal = false;
-
- if( !equal )
- fs = File.Open( strFile, FileMode.Truncate );
- }
- else
- {
- // create the file
- fs = File.Create( strFile );
- }
-
- if( fs != null )
- {
- // write it out to the stream
- fs.Write( data, 0, data.Length );
- }
-
- // add the newly generated file to the solution, as a child of the source file
- if( item.ProjectItems.Cast<EnvDTE.ProjectItem>()
- .Where( pi => pi.Name == fileName ).Count() == 0 )
- {
- EnvDTE.ProjectItem itm = item.ProjectItems.AddFromFile( strFile );
- /*
- * Here you may wish to perform some addition logic
- * such as, setting a custom tool for the target file if it
- * is intented to perform its own generation process.
- * Or, set the target file as an 'Embedded Resource' so that
- * it is embedded into the final Assembly.
-
- EnvDTE.Property prop = itm.Properties.Item("CustomTool");
- //// set to embedded resource
- itm.Properties.Item("BuildAction").Value = 3;
- if (String.IsNullOrEmpty((string)prop.Value) || !String.Equals((string)prop.Value, typeof(AnotherCustomTool).Name))
- {
- prop.Value = typeof(AnotherCustomTool).Name;
- }
- */
- }
- }
- catch( Exception )
- {
- if( File.Exists( strFile ) )
- File.Delete( strFile );
- }
- finally
- {
- if( fs != null )
- fs.Close();
- }
- }
- catch( Exception ex )
- {
- throw ex;
- }
- }
-
- // perform some clean-up, making sure we delete any old (stale) target-files
- foreach( EnvDTE.ProjectItem childItem in item.ProjectItems )
- {
- if( !(childItem.Name.EndsWith( GetDefaultExtension() ) || newFileNames.Contains( childItem.Name )) )
- // then delete it
- childItem.Delete();
- }
-
- // generate our default content for our 'single' file
- byte[] defaultData = GenerateDefaultContent();
-
- if( defaultData == null )
- {
- rgbOutputFileContents = IntPtr.Zero;
-
- pcbOutput = 0;
- }
- else
- {
- // return our default data, so that Visual Studio may write it to disk.
- rgbOutputFileContents = Marshal.AllocCoTaskMem( defaultData.Length );
-
- Marshal.Copy( defaultData, 0, rgbOutputFileContents, defaultData.Length );
-
- pcbOutput = defaultData.Length;
- }
- }
-
- #region IObjectWithSite Members
-
- public void GetSite( ref Guid riid, out IntPtr ppvSite )
- {
- if( this.site == null )
- {
- throw new Win32Exception( -2147467259 );
- }
-
- IntPtr objectPointer = Marshal.GetIUnknownForObject( this.site );
-
- try
- {
- Marshal.QueryInterface( objectPointer, ref riid, out ppvSite );
- if( ppvSite == IntPtr.Zero )
- {
- throw new Win32Exception( -2147467262 );
- }
- }
- finally
- {
- if( objectPointer != IntPtr.Zero )
- {
- Marshal.Release( objectPointer );
- objectPointer = IntPtr.Zero;
- }
- }
- }
-
- public void SetSite( object pUnkSite )
- {
- this.site = pUnkSite;
- }
-
- #endregion
-
- }
- }
-