代码之家  ›  专栏  ›  技术社区  ›  Aen Sidhe

如何部署Visual Studio自定义工具?

  •  6
  • Aen Sidhe  · 技术社区  · 16 年前

    我有自己的Visual Studio 2008 SP1自定义工具。它由5个程序集组成:3个程序集,其中包含在我的其他项目中大量使用的代码,1个VS2008 SDK以上的程序集包装器,以及一个使用该工具的程序集。

    如果要从Visual Studio调试工具,请使用带有命令行“c:\program files(x86)\Microsoft Visual Studio 9.0\common7\ide\devenv.exe”和参数“/ranu/rootsuffix exp”的“运行外部程序”选项,所有这些都可以正常工作。

    在那之后,我尝试将它部署到我的工作vs拷贝,而不是实验蜂巢,做: gacutil /i Asm1.dll 为了我所有的集会和做 RegAsm Asm1.dll 仅用于使用自定义工具进行装配。两个实用程序都不打印任何错误,所有工作都按计划进行,甚至出现注册表项。但我的工具无法工作(出现错误“在此系统上找不到自定义工具”transportGeneratotool“,即使在PC重新启动之后)。我做错了什么?

    包装看起来是这样的:

    [ComVisible(true)]
    public abstract class CustomToolBase : IVsSingleFileGenerator, IObjectWithSite
    {
        #region IVsSingleFileGenerator Members
        int IVsSingleFileGenerator.DefaultExtension(out string pbstrDefaultExtension)
        {
            pbstrDefaultExtension = ".cs";
            return 0;
        }
    
        int IVsSingleFileGenerator.Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, IntPtr[] rgbOutputFileContents, out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
        {
            GenerationEventArgs gea = new GenerationEventArgs(
                bstrInputFileContents,
                wszInputFilePath,
                wszDefaultNamespace,
                new ServiceProvider(Site as Microsoft.VisualStudio.OLE.Interop.IServiceProvider)
                    .GetService(typeof(ProjectItem)) as ProjectItem,
                new GenerationProgressFacade(pGenerateProgress)
                    );
    
            if (OnGenerateCode != null)
            {
                OnGenerateCode(this, gea);
            }
    
            byte[] bytes = gea.GetOutputCodeBytes();
    
            int outputLength = bytes.Length;
            rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(outputLength);
            Marshal.Copy(bytes, 0, rgbOutputFileContents[0], outputLength);
            pcbOutput = (uint)outputLength;
            return VSConstants.S_OK;
        }
        #endregion
    
        #region IObjectWithSite Members
        void IObjectWithSite.GetSite(ref Guid riid, out IntPtr ppvSite)
        {
            IntPtr pUnk = Marshal.GetIUnknownForObject(Site);
            IntPtr intPointer = IntPtr.Zero;
            Marshal.QueryInterface(pUnk, ref riid, out intPointer);
            ppvSite = intPointer;
        }
    
        void IObjectWithSite.SetSite(object pUnkSite)
        {
            Site = pUnkSite;
        }
        #endregion
    
        #region Public Members
        public object Site { get; private set; }
    
        public event EventHandler<GenerationEventArgs> OnGenerateCode;
    
        [ComRegisterFunction]
        public static void Register(Type type)
        {
            using (var parent = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\VisualStudio\9.0", true))
                foreach (CustomToolRegistrationAttribute ourData in type.GetCustomAttributes(typeof(CustomToolRegistrationAttribute), false))
                    ourData.Register(x => parent.CreateSubKey(x), (x, name, value) => x.SetValue(name, value));
        }
    
        [ComUnregisterFunction]
        public static void Unregister(Type type)
        {
            using (var parent = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\VisualStudio\9.0", true))
                foreach (CustomToolRegistrationAttribute ourData in type.GetCustomAttributes(typeof(CustomToolRegistrationAttribute), false))
                    ourData.Unregister(x => parent.DeleteSubKey(x, false));
        }
    
        #endregion
    }
    

    我的工具代码:

    [ComVisible(true)]
    [Guid("55A6C192-D29F-4e22-84DA-DBAF314ED5C3")]
    [CustomToolRegistration(ToolName, typeof(TransportGeneratorTool))]
    [ProvideObject(typeof(TransportGeneratorTool))]
    public class TransportGeneratorTool : CustomToolBase
    {
        private const string ToolName = "TransportGeneratorTool";
    
        public TransportGeneratorTool()
        {
            OnGenerateCode += GenerateCode;
        }
    
        private static void GenerateCode(object s, GenerationEventArgs e)
        {
            try
            {
                var serializer = new XmlSerializer(typeof (Parser.System));
                using (var reader = new StringReader(e.InputText))
                using (var writer = new StringWriter(e.OutputCode))
                {
                    Generator.System = (Parser.System) serializer.Deserialize(reader);
                    Generator.System.Namespace = e.Namespace;
                    Generator.GenerateSource(writer);
                }
            }
            catch (Exception ex)
            {
                e.Progress.GenerateError(ex.ToString());
            }
        }
    }
    

    生成的注册表项:

    Windows Registry Editor Version 5.00
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators\{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators\{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}\TransportGeneratorTool]
    @="TransportGeneratorTool"
    "CLSID"="{55a6c192-d29f-4e22-84da-dbaf314ed5c3}"
    "GeneratesDesignTimeSource"=dword:00000001
    "GeneratesSharedDesignTimeSource"=dword:00000001
    

    以下是我的自定义属性的代码(它在包装程序集中):

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
    public class CustomToolRegistrationAttribute : RegistrationAttribute
    {
        public CustomToolRegistrationAttribute(string name, Type customToolType)
        {
            Name = name;
            CustomToolType = customToolType;
        }
    
        /// <summary>
        /// The type that implements the custom tool.  This starts 
        /// as MyCustomTool by default in the template.
        /// </summary>
        public Type CustomToolType { get; set; }
    
        public string Name { get; set; }
    
        #region RegistrationAttribute abstract member implementations
        public override void Register(RegistrationContext context)
        {
            Register(x => context.CreateKey(x), (x, key, value) => x.SetValue(key, value));
        }
    
        public void Register<T>(Func<string, T> keyCreator, Action<T, string, object> valueCreator)
        {
            var keyName = CreateKeyName(Name);
            var key = keyCreator(keyName);
    
            valueCreator(key, string.Empty, Name);
            valueCreator(key, "CLSID", CustomToolType.GUID.ToString("B"));
            valueCreator(key, "GeneratesDesignTimeSource", 1);
            valueCreator(key, "GeneratesSharedDesignTimeSource", 1);
    
            var disposable = key as IDisposable;
            if (disposable != null)
                disposable.Dispose();
        }
    
        private static string CreateKeyName(string name)
        {
            return string.Format(@"Generators\{0}\{1}", vsContextGuids.vsContextGuidVCSProject, name);
        }
    
        public override void Unregister(RegistrationContext context)
        {
            Unregister(context.RemoveKey);
        }
    
        public void Unregister(Action<string> keyRemover)
        {
            keyRemover(CreateKeyName(Name));
        }
    
        #endregion
    }
    
    2 回复  |  直到 9 年前
        1
  •  6
  •   ErvinS    16 年前

    我的解决方案是做一个安装项目。我通过将以下内容添加到包的csproj文件中,从pkgdef文件获取注册表设置:

    <Target Name="GeneratePackageRegistryFiles">
      <Exec Command="&quot;$(VSSDK90Install)VisualStudioIntegration\Tools\Bin\RegPkg.exe&quot; /root:Software\Microsoft\VisualStudio\9.0 /codebase &quot;$(TargetPath)&quot; /regfile:&quot;$(OutDir)$(TargetName).reg&quot;" />
    </Target>
    <PropertyGroup> 
      <BuildDependsOn>$(BuildDependsOn);GeneratePackageRegistryFiles;</BuildDependsOn>
    </PropertyGroup>
    

    在输出目录中构建look时,您应该找到一个.reg文件,可以在安装项目中导入该文件。

    显然,如果修改项目不是一个选项,那么可以从命令行运行regpkg.exe。

        2
  •  4
  •   Athari    13 年前

    这是我最后一次尝试注册自定义工具时遇到的问题。 我希望这个说明足够详细,涵盖所有内容,这样你就不会花太多时间去和它作斗争。以下的msdn文章用作起点。 http://msdn.microsoft.com/en-US/library/bb166527(v=vs.80).aspx 不幸的是你不能单独使用它。你真正需要做的是:

    1. 确保程序集已签名。为什么?因为否则你将无法在下面的第6步将它放入GAC。 要签署程序集,请执行以下步骤:

      1.1。去 性质 项目的屏幕。

      1.2。一旦到了 签署 标签。

      1.3。一旦到了那里,检查 在大会上签字 复选框。

    2. 确保您知道程序集的版本号。您需要这个号码来指定 程序集版本 稍后参数。 为了得到这个号码,打开 汇编语言 文件中 性质 项目的文件夹并查找以[程序集:程序集版本]开头的行(

    3. 确保您知道生成器类的guid。您需要它来指定 发电机控制器 稍后参数。 为了得到这个guid,打开带有generator类的文件并查找 GUID 装饰这个类的类属性,类似于:[guid(“17799e85-421b-4684-b59e-650e34ecc718”)]

    4. 建立项目

    5. 获取程序集的公钥。为此,您必须运行以下命令:

      NEX-EX-T 汇编文件

      你以后什么时候需要这个信息 公钥 . 这个 S.EXE 文件可在 C:\Program Files\Microsoft SDK\Windows\V8.0A\bin\sn.exe 注意上面文件路径中框架(V8.0A)的版本号。它需要与用于编译项目的框架版本一致。

    6. 使用以下命令将程序集放入GAC:

      刺槐提取物 汇编文件 f

      在GAC中注册需要管理权限。 这个 刺槐 文件可在 C:\Program Files\Microsoft SDK\Windows\V8.0A\bin\NetFx 4.0工具\Gacutil.exe 注意上面文件路径中框架(V8.0A)的版本号。它需要与用于编译项目的框架版本一致。

    7. 对.reg文件进行以下更改(请参见下文)。 请注意:生成器_-guid和项目_-type_-guid都需要提供大括号:XXXXXXXX-XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

      7.1。使用Visual Studio的修复版本号(例如:10.0或9.0): Vs_版本

      7.2。修复生成器的GUID: 发电机控制器

      7.3。修复程序集的命名空间: 命名空间名

      7.4.修复生成器类名: 发电机类型名称

      7.5。为了注册生成器,Visual Studio需要知道该生成器可以应用于哪些项目类型。因此,您需要获得适当项目类型(C_、vb.net等)的guid。 要确定项目类型的GUID,需要在文本编辑器中打开Visual Studio项目文件(*.csproj),然后在 项目类型guid XML元素。 对于这些guid中的每一个,重复.reg文件中最后3个条目的块,替换 项目\类型\ GUID 找到了一个GUID。

      7.6。修复与自定义工具关联的文件扩展名: 文件扩展

    8. 运行.reg文件。您可能需要具有管理权限才能执行此操作。

    Reg文件:

    Windows Registry Editor Version 5.00
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\CLSID\GENERATOR_GUID]
    @="COM+ class: NAMESPACE_NAME.GENERATOR_TYPE_NAME"
    "InprocServer32"="C:\\WINDOWS\\system32\\mscoree.dll"
    "ThreadingModel"="Both"
    "Class"="NAMESPACE_NAME.GENERATOR_TYPE_NAME"
    "Assembly"="NAMESPACE_NAME, Version=ASSEMBLY_VERSION, Culture=Neutral, PublicKeyToken=PUBLIC_TOKEN_KEY"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\Generators]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\Generators\PROJECT_TYPE_GUID]
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\Generators\PROJECT_TYPE_GUID\\.FILE_EXTENSTION]
    @="GENERATOR_TYPE_NAME"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\Generators\PROJECT_TYPE_GUID\GENERATOR_TYPE_NAME]
    @="Code generator for whatever you like"
    "CLSID"="GENERATOR_GUID"
    "GeneratesDesignTimeSource"=dword:00000001
    

    PS。 很抱歉,无法区分注册表文件中的占位符,但StackOverflow使用的文本编辑器无法区分其标记元素和内容。