如何注册“自定义工具"使用 Visual Studio 2017 或 Visual Studio 2019 使其工作? [英] How to register "custom tool" with Visual Studio 2017 or Visual Studio 2019 to make it work?

查看:73
本文介绍了如何注册“自定义工具"使用 Visual Studio 2017 或 Visual Studio 2019 使其工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:我们有一个

这很明显,因为自定义工具尚未在 VS 2017 中注册才能工作.

我试图关注 this guy 说将 .bin 文件加载到注册表中,但他还说它无法启动 VS 2017.为了启动 VS,我们必须卸载 hive.研究表明,根据安装的 VS 类型(企业版、专业版等),.bin 文件可以位于不同的位置.

以前有人做过吗?

TIA

解决方案

您可能需要按照不同的方法创建 Visual Studio 扩展 (VSIX),下面我已经详细解释了,希望对您有所帮助.

如何在 Visual Studio 2017 中创建自定义工具或单个文件生成器:

在 VS2017 之前创建自定义工具需要实现接口 IVsSingleFileGenerator 和代码以在系统注册表中注册和取消注册自定义工具,但在 VS2017 中,Microsoft 更改了整个注册表结构.变化是,VS 会将注册表项添加到私有注册表中,这样系统注册表就不会被搞乱.虽然以前注册表项是在系统注册表中创建的,但现在它们是

<块引用>

C:\Users\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xx\privateregistry.bin

Visual Studio 2017 还支持通过从 Visual Studio 本身 (F5) 运行来直接测试您的工具,这会启动另一个名为 Visual Studio 实验实例 的 Visual Studio 实例,您的工具可以在它因为它使注册表项

<块引用>

C:\Users\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xxExp\privateregistry.bin

按照以下步骤在 VS2017 中创建自定义工具:

  1. 我们需要创建一个 VSIX 扩展
  2. 添加新的 Visual Studio 包
  3. 实现IVsSingleFileGenerator
  4. 添加注册表项代码
  5. 通过在 VS2017 中运行来编译和测试该工具
  6. 双击生成的 .VSIX 文件安装该工具

我们将创建一个扩展/自定义工具作为名为CountLines"的示例,它将读取一个文件(将自定义工具属性设置为 CountLines)并生成一个包含文件中行数的 XML 文件.例如1050

1.创建 VSIX 扩展为了创建扩展,您必须安装 Visual Studio 扩展工具,该工具作为 Visual Studio 安装程序中的可选功能包含在内.如果未安装,您也可以通过修改 VS 2017 设置来安装它.通过选择

创建新的 VSIX(Visual Studio 扩展)项目<块引用>

新建项目 -> 可扩展性 -> VSIX 项目

给它起一个像CountLinesVSIX"这样的名字.

2.添加新的 Visual Studio 包创建 VSIX 项目后,通过选择

向其添加新的 Visual Studio 包<块引用>

添加 -> 新项目 -> 扩展性 -> Visual Studio 包

将其命名为CountLines.cs".在 CountLines.cs 中,我们需要删除现有代码并将其替换为我们用于 IVsSingleFileGenerator 实现的代码

3.实现 IVsSingleFileGenerator为接口IVsSingleFileGenerator编写自定义实现,我们的示例代码如下

使用系统;使用 System.Runtime.InteropServices;使用 Microsoft.VisualStudio;使用 Microsoft.VisualStudio.Shell;使用 Microsoft.VisualStudio.Shell.Interop;使用 System.Text;命名空间 CountLinesVSIX{[PackageRegistration(UseManagedResourcesOnly = true)][InstalledProductRegistration( "CountLines", "Generate XML with line count", "1.0")][指南("202E7E8B-557E-46CB-8A1D-3024AD68F44A")][ComVisible(true)][ProvideObject(typeof(CountLines))][CodeGeneratorRegistration(typeof(CountLines), "CountLines", "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}", GeneratesDesignTimeSource = true)]公共密封类 CountLines : IVsSingleFileGenerator{#region IVsSingleFileGenerator 成员public int DefaultExtension(输出字符串 pbstrDefaultExtension){pbstrDefaultExtension = ".xml";返回 pbstrDefaultExtension.Length;}public int Generate(string wszInputFilePath, string bstrInputFileContents,字符串 wszDefaultNamespace,IntPtr[] rgbOutputFileContents,out uint pcbOutput, IVsGeneratorProgress pGenerateProgress){尝试{int lineCount = bstrInputFileContents.Split('\n').Length;byte[] bytes = Encoding.UTF8.GetBytes("" + lineCount.ToString() + "" );int length = bytes.Length;rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(length);Marshal.Copy(bytes, 0, rgbOutputFileContents[0], length);pcbOutput = (uint)length;}捕获(异常前){印刷电路板输出 = 0;}返回 VSConstants.S_OK;}#endregion}}

我们需要为我们的扩展程序提供一个唯一的 GUID,例如上面代码中的一个 [Guid("202E7E8B-557E-46CB-8A1D-3024AD68F44A")].通过选择工具 -> 创建 GUID",可以从 VS2017 创建 GUID.选择 GUID 格式作为注册表格式.注意上面代码中提到的GUID是没有花括号的.

[ComVisible(true)] 是 COM Interops 所必需的

[CodeGeneratorRegistration(typeof(CountLines), "CountLines", "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}", GeneratesDesignTimeSource = true)] 是一个类属性,带有用于注册工具.参数是 GeneratorType、GeneratorName 和 C# 语言 GUID

您还可以从支持自定义 TextTemplate 格式的TemplatedCodeGenerator"派生,这可能需要一些额外的代码实现.

4.添加注册表项代码使用以下代码创建新的类文件,将其命名为 CodeGeneratorRegistrationAttribute.cs

使用系统;使用 System.Globalization;使用 Microsoft.VisualStudio.Shell;命名空间 CountLinesVSIX{[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]公共密封类 CodeGeneratorRegistrationAttribute : RegistrationAttribute{私有字符串 _contextGuid;私有类型_generatorType;私人 Guid _generatorGuid;私人字符串_generatorName;私人字符串 _generatorRegKeyName;private bool _generatesDesignTimeSource = false;private bool _generatesSharedDesignTimeSource = false;public CodeGeneratorRegistrationAttribute(Type generatorType, string generatorName, string contextGuid){if (generatorType == null)throw new ArgumentNullException("generatorType");如果(生成器名称 == 空)throw new ArgumentNullException("generatorName");如果(contextGuid == null)throw new ArgumentNullException("contextGuid");_contextGuid = contextGuid;_generatorType = 发电机类型;_generatorName = 发电机名称;_generatorRegKeyName = generatorType.Name;_generatorGuid = generatorType.GUID;}///<总结>///获取生成器类型///</总结>公共类型生成器类型{得到 { 返回 _generatorType;}}///<总结>///获取代表项目类型的 Guid///</总结>公共字符串 ContextGuid{得到 { 返回 _contextGuid;}}///<总结>///获取代表生成器类型的 Guid///</总结>公共指南生成器Guid{得到 { 返回 _generatorGuid;}}///<总结>///获取或设置 GeneratesDesignTimeSource 值///</总结>public bool GeneratesDesignTimeSource{得到 { 返回 _generatesDesignTimeSource;}设置 { _generatesDesignTimeSource = 值;}}///<总结>///获取或设置 GeneratesSharedDesignTimeSource 值///</总结>public bool GeneratesSharedDesignTimeSource{得到 { 返回 _generatesSharedDesignTimeSource;}设置 { _generatesSharedDesignTimeSource = 值;}}///<总结>///获取生成器名称///</总结>公共字符串 GeneratorName{得到 { 返回 _generatorName;}}///<总结>///获取下面的 Generator reg 键名///</总结>公共字符串 GeneratorRegKeyName{得到 { 返回 _generatorRegKeyName;}设置 { _generatorRegKeyName = 值;}}///<总结>///获取生成器基键名称的属性///</总结>私有字符串 GeneratorRegKey{get { return string.Format(CultureInfo.InvariantCulture, @"Generators\{0}\{1}", ContextGuid, GeneratorRegKeyName);}}///<总结>///调用以使用给定的上下文注册此属性.上下文///包含应该放置注册信息的位置.///它还包含其他信息,例如正在注册的类型和路径信息.///</总结>公共覆盖无效注册(注册上下文上下文){使用 (Key childKey = context.CreateKey(GeneratorRegKey)){childKey.SetValue(string.Empty, GeneratorName);childKey.SetValue("CLSID", GeneratorGuid.ToString("B"));如果(生成设计时间源)childKey.SetValue("GeneratesDesignTimeSource", 1);if (GeneratesSharedDesignTimeSource)childKey.SetValue("GeneratesSharedDesignTimeSource", 1);}}///<总结>///取消注册此文件扩展名.///</总结>///<param name="context"></param>公共覆盖无效取消注册(注册上下文上下文){context.RemoveKey(GeneratorRegKey);}}}

以上代码将确保您的条目进入 VS 私有注册表

5.通过在VS2017中运行来编译和测试该工具您可以在source.extension.vsixmanifest"中添加安装目标"以确保您的扩展支持不同的VS2017版本.在 VS 2017 中运行您的工具以测试它是否按预期工作.运行 VSIX 后,Visual Studio 实验实例将安装扩展并将其注册到注册表C:\Users\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xxExp\privateregistry.bin"中.您可以通过选择工具 -> 扩展和更新"来查看已安装的扩展.要测试该工具,我们必须打开一个虚拟项目,在解决方案资源管理器中选择一个文件,转到其属性并将自定义工具属性更新为CountLines".完成后,VS 将在后台运行该工具并生成输出,在我们的示例中,它将在所选文件下生成一个 xml 文件.或者,设置自定义工具属性后,您可以右键单击该文件并选择运行自定义工具"

6.双击生成的 .VSIX 文件安装该工具测试成功后,尝试安装位于projectName/bin/debug"位置的 VSIX.双击文件安装 VSIX,按照安装步骤操作.现在你的工具可以在 VS2017 中使用了.使用工具类似,右键单击要运行自定义工具的文件,然后选择运行自定义工具"

如果您想卸载扩展,请转到工具 -> 扩展和更新 -> 选择您的扩展",然后单击卸载.请注意,在 VS 关闭之前,该工具不会被卸载.关闭后,您将看到一个弹出窗口进行卸载,选择修改"进行卸载.

Background: We have a custom tool which takes the xml input and generates the cs output. A custom tool needs to register with the Visual studio in order to make it work with that version of visual studio.

What we have done: We have done the custom tool registration with the Visual Studio 2015 which is working fine. But now the problem is with Visual Studio 2017.

Problem: So far in my research, I found until Visual Studio 2015, VS had the direct registry entries which were allowing to register the tool but from VS 2017, Microsoft has made changes in the way how registry entries are stored (a good read to understand changes in VS2017).

If I open up the VS 2017 and try to run the custom tool then I get the error

Cannot find custom tool "Tool Name" on this system.

This is obvious because custom tool is not yet registered with VS 2017 to work.

I tried to follow this guy which says to load .bin file in to the registries but he also says that it disables to launch the VS 2017. In order to launch VS, we have to unload hive. Research says, .bin file can be on different location based on type of VS installed (enterprise, pro etc.).

Has anyone done this before?

TIA

解决方案

You may have to follow different approach here by creating a Visual Studio extension (VSIX), below I have explained it in detail, hope it helps.

How to create a Custom Tool or Single File Generator in Visual Studio 2017:

Prior to VS2017 creating a custom tool required implementing Interface IVsSingleFileGenerator and code to register and unregister the custom tool in the system registry, but in VS2017, Microsoft has changed entire registry structure. The change is, VS will make registry entries to a private registry so that system registry is not messed up. While previously the registry entries were made in the system registry, now they are made to

C:\Users\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xx\privateregistry.bin

Visual studio 2017 also supports testing your tool directly by running it from the visual studio itself (F5), which starts another instance of Visual Studio called Visual Studio Experimental Instance and your tool can be tested in it since it makes registry entries to

C:\Users\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xxExp\privateregistry.bin

Follow below steps to create a Custom Tool in VS2017:

  1. We need to create a VSIX extension
  2. Add new Visual Studio Package
  3. Implement IVsSingleFileGenerator
  4. Add the registry entry code
  5. Compile and test the tool by running it in VS2017
  6. Install the tool by double clicking the generated .VSIX file

We will create an extension/custom tool as an example named "CountLines" which will read a file (having Custom Tool property set to CountLines) and generate an XML file containing the number of lines in the file. e.g. <LineCount>1050</LineCount>

1. Create a VSIX extension In order to create an extension you must have installed Visual Studio Extensibility Tools which is included as an optional feature in Visual Studio setup. If it is not installed you can also install it by modifying VS 2017 setup. Create new VSIX (Visual Studio Extension) project by selecting

New Project -> Extensibility -> VSIX Project

give it some name like "CountLinesVSIX".

2. Add new Visual Studio Package Once VSIX project is created, add new Visual Studio Package to it by selecting

Add -> New Item -> Extensibility -> Visual Studio Package

give it name "CountLines.cs". In CountLines.cs we need to delete existing code and replace it with our code for IVsSingleFileGenerator implementation

3. Implement IVsSingleFileGenerator Write your custom implementation for interface IVsSingleFileGenerator, our example code is as below

using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System.Text;

namespace CountLinesVSIX
    {
    [PackageRegistration(UseManagedResourcesOnly = true)]
    [InstalledProductRegistration( "CountLines", "Generate XML with line count", "1.0")] 
    [Guid("202E7E8B-557E-46CB-8A1D-3024AD68F44A")]
    [ComVisible(true)]
    [ProvideObject(typeof(CountLines))]
    [CodeGeneratorRegistration(typeof(CountLines), "CountLines", "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}", GeneratesDesignTimeSource = true)]
    public sealed class CountLines : IVsSingleFileGenerator
    {

        #region IVsSingleFileGenerator Members

        public int DefaultExtension(out string pbstrDefaultExtension)
        {
            pbstrDefaultExtension = ".xml";
            return pbstrDefaultExtension.Length;
        }

        public int Generate(string wszInputFilePath, string bstrInputFileContents,
          string wszDefaultNamespace, IntPtr[] rgbOutputFileContents,
          out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
        {
            try
            {
                int lineCount = bstrInputFileContents.Split('\n').Length;
                byte[] bytes = Encoding.UTF8.GetBytes("<LineCount>" + lineCount.ToString() + "</LineCount>" );
                int length = bytes.Length;
                rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(length);
                Marshal.Copy(bytes, 0, rgbOutputFileContents[0], length);
                pcbOutput = (uint)length;
            }
            catch (Exception ex)
            {
                pcbOutput = 0;
            }
            return VSConstants.S_OK;
        }

        #endregion
    }
}

We need to provide an unique GUID for our extension such as one in above code [Guid("202E7E8B-557E-46CB-8A1D-3024AD68F44A")]. GUID can be created from VS2017 by selecting "Tools -> Create GUID". Select GUID format as Registry format. Note that GUID mentioned above code is without curly braces.

[ComVisible(true)] is required for COM Interops

[CodeGeneratorRegistration(typeof(CountLines), "CountLines", "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}", GeneratesDesignTimeSource = true)] is a class attribute with code to register the tool. Params being GeneratorType, GeneratorName, and C# language GUID

You can also derive from "TemplatedCodeGenerator" which supports custom TextTemplate formatting, which may require some additional code implementation.

4. Add the registry entry code Create new class file with below code, name it CodeGeneratorRegistrationAttribute.cs

using System;
using System.Globalization;
using Microsoft.VisualStudio.Shell;

namespace CountLinesVSIX
{

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
    public sealed class CodeGeneratorRegistrationAttribute : RegistrationAttribute
    {
        private string _contextGuid;
        private Type _generatorType;
        private Guid _generatorGuid;
        private string _generatorName;
        private string _generatorRegKeyName;
        private bool _generatesDesignTimeSource = false;
        private bool _generatesSharedDesignTimeSource = false;

        public CodeGeneratorRegistrationAttribute(Type generatorType, string generatorName, string contextGuid)
        {
            if (generatorType == null)
                throw new ArgumentNullException("generatorType");
            if (generatorName == null)
                throw new ArgumentNullException("generatorName");
            if (contextGuid == null)
                throw new ArgumentNullException("contextGuid");

            _contextGuid = contextGuid;
            _generatorType = generatorType;
            _generatorName = generatorName;
            _generatorRegKeyName = generatorType.Name;
            _generatorGuid = generatorType.GUID;
        }

        /// <summary> 
        /// Get the generator Type 
        /// </summary> 
        public Type GeneratorType
        {
            get { return _generatorType; }
        }

        /// <summary> 
        /// Get the Guid representing the project type 
        /// </summary> 
        public string ContextGuid
        {
            get { return _contextGuid; }
        }

        /// <summary> 
        /// Get the Guid representing the generator type 
        /// </summary> 
        public Guid GeneratorGuid
        {
            get { return _generatorGuid; }
        }

        /// <summary> 
        /// Get or Set the GeneratesDesignTimeSource value 
        /// </summary> 
        public bool GeneratesDesignTimeSource
        {
            get { return _generatesDesignTimeSource; }
            set { _generatesDesignTimeSource = value; }
        }

        /// <summary> 
        /// Get or Set the GeneratesSharedDesignTimeSource value 
        /// </summary> 
        public bool GeneratesSharedDesignTimeSource
        {
            get { return _generatesSharedDesignTimeSource; }
            set { _generatesSharedDesignTimeSource = value; }
        }


        /// <summary> 
        /// Gets the Generator name  
        /// </summary> 
        public string GeneratorName
        {
            get { return _generatorName; }
        }

        /// <summary> 
        /// Gets the Generator reg key name under  
        /// </summary> 
        public string GeneratorRegKeyName
        {
            get { return _generatorRegKeyName; }
            set { _generatorRegKeyName = value; }
        }

        /// <summary> 
        /// Property that gets the generator base key name 
        /// </summary> 
        private string GeneratorRegKey
        {
            get { return string.Format(CultureInfo.InvariantCulture, @"Generators\{0}\{1}", ContextGuid, GeneratorRegKeyName); }
        }
        /// <summary> 
        ///     Called to register this attribute with the given context.  The context 
        ///     contains the location where the registration inforomation should be placed. 
        ///     It also contains other information such as the type being registered and path information. 
        /// </summary> 
        public override void Register(RegistrationContext context)
        {
            using (Key childKey = context.CreateKey(GeneratorRegKey))
            {
                childKey.SetValue(string.Empty, GeneratorName);
                childKey.SetValue("CLSID", GeneratorGuid.ToString("B"));

                if (GeneratesDesignTimeSource)
                    childKey.SetValue("GeneratesDesignTimeSource", 1);

                if (GeneratesSharedDesignTimeSource)
                    childKey.SetValue("GeneratesSharedDesignTimeSource", 1);

            }
        }

        /// <summary> 
        /// Unregister this file extension. 
        /// </summary> 
        /// <param name="context"></param> 
        public override void Unregister(RegistrationContext context)
        {
            context.RemoveKey(GeneratorRegKey);
        }
    }
}

Above code will make sure your entries are made to VS private registry

5. Compile and test the tool by running it in VS2017 You may add "Install targets" in "source.extension.vsixmanifest" to ensure different VS2017 editions are supported by your extesion. Run your tool in VS 2017 to test if it is working as expected. Once you Run the VSIX, the Visual Studio Experimental Instance will install the extension and register it in registry "C:\Users\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xxExp\privateregistry.bin". You can see the installed extension by selecting "Tools -> Extensions and updates". To test the tool we will have to open a dummy project, select a file in solution explorer, go to its properties and update Custom Tool property to "CountLines". Once this is done VS will run the tool in background and generate the output, in our example it will generate a xml file under the selected file. Alternatively, once Custom Tool property is set, your can right click the file and select "Run Custom Tool"

6. Install the tool by double clicking the generated .VSIX file Once tested successfully, try installing the VSIX which can be found at location "projectName/bin/debug". Install the VSIX by double clicking the file, follow the installation steps. Now your tool will be available for use in VS2017. Using tool is similar, right click the file on which you want to run the custom tool and select "Run Custom Tool"

In case you want to uninstall the extention, go to "Tools -> Extensions and updates -> select your extension" and click uninstall. Note that tool will not get uninstalled until VS is closed. Once closeed you will get a popup window to uninstall, select "Modify" to uninstall.

这篇关于如何注册“自定义工具"使用 Visual Studio 2017 或 Visual Studio 2019 使其工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆