/*************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. This code is licensed under the Visual Studio SDK license terms. THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. ***************************************************************************/ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using Microsoft.VisualStudio; using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.Win32; using VSRegistry = Microsoft.VisualStudio.Shell.VSRegistry; namespace Microsoft.VisualStudio.Project { /// /// Provides implementation IVsSingleFileGeneratorFactory for /// public class SingleFileGeneratorFactory : IVsSingleFileGeneratorFactory { #region nested types private class GeneratorMetaData { #region fields private Guid generatorClsid = Guid.Empty; private int generatesDesignTimeSource = -1; private int generatesSharedDesignTimeSource = -1; private int useDesignTimeCompilationFlag = -1; object generator; #endregion #region ctor /// /// Constructor /// public GeneratorMetaData() { } #endregion #region Public Properties /// /// Generator instance /// public Object Generator { get { return generator; } set { generator = value; } } /// /// GeneratesDesignTimeSource reg value name under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\[VsVer]\Generators\[ProjFacGuid]\[GeneratorProgId] /// public int GeneratesDesignTimeSource { get { return generatesDesignTimeSource; } set { generatesDesignTimeSource = value; } } /// /// GeneratesSharedDesignTimeSource reg value name under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\[VsVer]\Generators\[ProjFacGuid]\[GeneratorProgId] /// public int GeneratesSharedDesignTimeSource { get { return generatesSharedDesignTimeSource; } set { generatesSharedDesignTimeSource = value; } } /// /// UseDesignTimeCompilationFlag reg value name under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\[VsVer]\Generators\[ProjFacGuid]\[GeneratorProgId] /// public int UseDesignTimeCompilationFlag { get { return useDesignTimeCompilationFlag; } set { useDesignTimeCompilationFlag = value; } } /// /// Generator Class ID. /// public Guid GeneratorClsid { get { return generatorClsid; } set { generatorClsid = value; } } #endregion } #endregion #region fields /// /// Base generator registry key for MPF based project /// private RegistryKey baseGeneratorRegistryKey; /// /// CLSID reg value name under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\[VsVer]\Generators\[ProjFacGuid]\[GeneratorProgId] /// private string GeneratorClsid = "CLSID"; /// /// GeneratesDesignTimeSource reg value name under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\[VsVer]\Generators\[ProjFacGuid]\[GeneratorProgId] /// private string GeneratesDesignTimeSource = "GeneratesDesignTimeSource"; /// /// GeneratesSharedDesignTimeSource reg value name under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\[VsVer]\Generators\[ProjFacGuid]\[GeneratorProgId] /// private string GeneratesSharedDesignTimeSource = "GeneratesSharedDesignTimeSource"; /// /// UseDesignTimeCompilationFlag reg value name under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\[VsVer]\Generators\[ProjFacGuid]\[GeneratorProgId] /// private string UseDesignTimeCompilationFlag = "UseDesignTimeCompilationFlag"; /// /// Caches all the generators registered for the project type. /// private Dictionary generatorsMap = new Dictionary(); /// /// The project type guid of the associated project. /// private Guid projectType; /// /// A service provider /// private System.IServiceProvider serviceProvider; #endregion #region ctors /// /// Constructor for SingleFileGeneratorFactory /// /// The project type guid of the associated project. /// A service provider. public SingleFileGeneratorFactory(Guid projectType, System.IServiceProvider serviceProvider) { this.projectType = projectType; this.serviceProvider = serviceProvider; } #endregion #region properties /// /// Defines the project type guid of the associated project. /// public Guid ProjectGuid { get { return this.projectType; } set { this.projectType = value; } } /// /// Defines an associated service provider. /// public System.IServiceProvider ServiceProvider { get { return this.serviceProvider; } set { this.serviceProvider = value; } } #endregion #region IVsSingleFileGeneratorFactory Helpers /// /// Returns the project generator key under [VS-ConfigurationRoot]]\Generators /// private RegistryKey BaseGeneratorsKey { get { if(this.baseGeneratorRegistryKey == null) { using(RegistryKey root = VSRegistry.RegistryRoot(__VsLocalRegistryType.RegType_Configuration)) { if(null != root) { string regPath = "Generators\\" + this.ProjectGuid.ToString("B"); baseGeneratorRegistryKey = root.OpenSubKey(regPath); } } } return this.baseGeneratorRegistryKey; } } /// /// Returns the local registry instance /// private ILocalRegistry LocalRegistry { get { return this.serviceProvider.GetService(typeof(SLocalRegistry)) as ILocalRegistry; } } #endregion #region IVsSingleFileGeneratorFactory Members /// /// Creates an instance of the single file generator requested /// /// prog id of the generator to be created. For e.g HKLM\SOFTWARE\Microsoft\VisualStudio\9.0Exp\Generators\[prjfacguid]\[wszProgId] /// GeneratesDesignTimeSource key value /// GeneratesSharedDesignTimeSource key value /// UseDesignTimeCompilationFlag key value /// IVsSingleFileGenerator interface /// S_OK if succesful public virtual int CreateGeneratorInstance(string progId, out int generatesDesignTimeSource, out int generatesSharedDesignTimeSource, out int useTempPEFlag, out IVsSingleFileGenerator generate) { Guid genGuid; ErrorHandler.ThrowOnFailure(this.GetGeneratorInformation(progId, out generatesDesignTimeSource, out generatesSharedDesignTimeSource, out useTempPEFlag, out genGuid)); //Create the single file generator and pass it out. Check to see if it is in the cache if(!this.generatorsMap.ContainsKey(progId) || ((this.generatorsMap[progId]).Generator == null)) { Guid riid = VSConstants.IID_IUnknown; uint dwClsCtx = (uint)CLSCTX.CLSCTX_INPROC_SERVER; IntPtr genIUnknown = IntPtr.Zero; //create a new one. ErrorHandler.ThrowOnFailure(this.LocalRegistry.CreateInstance(genGuid, null, ref riid, dwClsCtx, out genIUnknown)); if(genIUnknown != IntPtr.Zero) { try { object generator = Marshal.GetObjectForIUnknown(genIUnknown); //Build the generator meta data object and cache it. GeneratorMetaData genData = new GeneratorMetaData(); genData.GeneratesDesignTimeSource = generatesDesignTimeSource; genData.GeneratesSharedDesignTimeSource = generatesSharedDesignTimeSource; genData.UseDesignTimeCompilationFlag = useTempPEFlag; genData.GeneratorClsid = genGuid; genData.Generator = generator; this.generatorsMap[progId] = genData; } finally { Marshal.Release(genIUnknown); } } } generate = (this.generatorsMap[progId]).Generator as IVsSingleFileGenerator; return VSConstants.S_OK; } /// /// Gets the default generator based on the file extension. HKLM\Software\Microsoft\VS\9.0\Generators\[prjfacguid]\.extension /// /// File name with extension /// The generator prog ID /// S_OK if successful public virtual int GetDefaultGenerator(string filename, out string progID) { progID = ""; return VSConstants.E_NOTIMPL; } /// /// Gets the generator information. /// /// prog id of the generator to be created. For e.g HKLM\SOFTWARE\Microsoft\VisualStudio\9.0Exp\Generators\[prjfacguid]\[wszProgId] /// GeneratesDesignTimeSource key value /// GeneratesSharedDesignTimeSource key value /// UseDesignTimeCompilationFlag key value /// CLSID key value /// S_OK if succesful public virtual int GetGeneratorInformation(string progId, out int generatesDesignTimeSource, out int generatesSharedDesignTimeSource, out int useTempPEFlag, out Guid guidGenerator) { RegistryKey genKey; generatesDesignTimeSource = -1; generatesSharedDesignTimeSource = -1; useTempPEFlag = -1; guidGenerator = Guid.Empty; if(string.IsNullOrEmpty(progId)) return VSConstants.S_FALSE; //Create the single file generator and pass it out. if(!this.generatorsMap.ContainsKey(progId)) { // We have to check whether the BaseGeneratorkey returns null. RegistryKey tempBaseGeneratorKey = this.BaseGeneratorsKey; if(tempBaseGeneratorKey == null || (genKey = tempBaseGeneratorKey.OpenSubKey(progId)) == null) { return VSConstants.S_FALSE; } //Get the CLSID string guid = (string)genKey.GetValue(GeneratorClsid, ""); if(string.IsNullOrEmpty(guid)) return VSConstants.S_FALSE; GeneratorMetaData genData = new GeneratorMetaData(); genData.GeneratorClsid = guidGenerator = new Guid(guid); //Get the GeneratesDesignTimeSource flag. Assume 0 if not present. genData.GeneratesDesignTimeSource = generatesDesignTimeSource = (int)genKey.GetValue(this.GeneratesDesignTimeSource, 0); //Get the GeneratesSharedDesignTimeSource flag. Assume 0 if not present. genData.GeneratesSharedDesignTimeSource = generatesSharedDesignTimeSource = (int)genKey.GetValue(GeneratesSharedDesignTimeSource, 0); //Get the UseDesignTimeCompilationFlag flag. Assume 0 if not present. genData.UseDesignTimeCompilationFlag = useTempPEFlag = (int)genKey.GetValue(UseDesignTimeCompilationFlag, 0); this.generatorsMap.Add(progId, genData); } else { GeneratorMetaData genData = this.generatorsMap[progId]; generatesDesignTimeSource = genData.GeneratesDesignTimeSource; //Get the GeneratesSharedDesignTimeSource flag. Assume 0 if not present. generatesSharedDesignTimeSource = genData.GeneratesSharedDesignTimeSource; //Get the UseDesignTimeCompilationFlag flag. Assume 0 if not present. useTempPEFlag = genData.UseDesignTimeCompilationFlag; //Get the CLSID guidGenerator = genData.GeneratorClsid; } return VSConstants.S_OK; } #endregion } }