资源:Reference Page
- 添加菜单资源文件
Visual Studio 菜单命令是从 .vsct 文件编译的,这些文件由 VSCT 编译器编译成 DLL 内的嵌入式 .ctmenu 资源。首先,您需要将 .vsct 文件(名称无关紧要)作为
<VSCTCompile> 标记添加到您的项目中。这必须通过直接编辑项目文件来完成。您还需要为 VSCT 编译器添加一个空的 VSPackage.resx 文件,以将编译后的资源嵌入到
工程文件修改(添加到任意<ItemGroup>)如下:xml <VSCTCompile Include="YourName.vsct"> <ResourceName>Menus.ctmenu</ResourceName> </VSCTCompile> <EmbeddedResource Include="VSPackage.resx"> <MergeWithCTO>true</MergeWithCTO> <ManifestResourceName>VSPackage</ManifestResourceName> </EmbeddedResource>
VSCT 的内容应如下所示:
<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<Extern href="stdidcmd.h"/>
<Extern href="vsshlids.h"/>
<Commands package="PackageGuid">
<Buttons>⠀
<Button guid="CommandsGuid" id="MyCommand" priority="0x0101" type="Button">⠀
<Parent guid="guidSHLMainMenu" id="IDG_VS_CODEWIN_NAVIGATETOLOCATION"/> ⠀
<Icon guid="guidObjectBrowserButtons" id="15"/>⠀
<Strings>
<ButtonText>My &Powerful Command</ButtonText>
</Strings>
</Button>
</Buttons>
</Commands>
<Symbols>
<GuidSymbol name="PackageGuid" value="«Package GUID»" />
<GuidSymbol name="CommandsGuid" value="«Command Group GUID»">
<IDSymbol name="MyCommand" value="0" />
</GuidSymbol>
</Symbols>
</CommandTable>
每个命令组 (GUID) 中的命令 ID 值必须是唯一的,因此您无需担心与其他命令发生冲突。
<Parent> 条目指定了命令应该放在的组;您可以在 Program Files\Microsoft Visual Studio 12.0\VSSDK\VisualStudioIntegration\Common\Inc\vsshlids.h 中找到所有标准组。您还可以在同一文件夹中的 stdidcmd.h 中找到所有命令 ID 的列表。
- 为 Visual Studio 定义要加载的 VSPackage
要让 Visual Studio 加载您的菜单命令文件,您需要在插件中定义一个 VSPackage 并将其注册到 VSIX。
首先,添加如下代码文件(类名无所谓):
using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell;
namespace YourAddin.Namespace {
// These GUIDS and command IDs must match the VSCT.
[ProvideMenuResource("Menus.ctmenu", 1)]
[Guid("«Package GUID»")]
[PackageRegistration(UseManagedResourcesOnly = true)]
class YourAddinPackage : Package {
}
[Guid("«Command Group GUID»")]
enum YourAddinCommand {
MyCommand = 0
}
}
包类中的属性告诉 CreatePkgDef.exe(由 VSIX 编译器调用)如何在您的插件中生成一个 .pkgdef 文件,该文件设置适当的注册表项以使用 Visual Studio 注册插件及其菜单资源基于本机 COM 的插件系统。这完全独立于托管插件的 MEF 注册。
枚举及其 [Guid] 属性只是一种方便的跟踪 GUID 和命令 ID 的方法;如果您愿意,可以随意使用不同的方法。
您还需要通过将以下行添加到 source.extension.vsixmanifest 中的 <Content> 元素来告诉 VSIX 包含该包并生成 pkgdef 文件:
<VsPackage>|%CurrentProject%;PkgdefProjectOutputGroup|</VsPackage>
如果您使用设计器(适用于版本 2 VSIX),请转到资产部分,单击新建,选择 Microsoft.VisualStudio.VsPackage,当前解决方案中的项目,然后选择您的项目。⠀
- 修复项目配置⠀
最后,您需要对 csproj 文件进行一些更改才能正确注册插件:⠀
首先,如果存在<GeneratePkgDefFile>false</GeneratePkgDefFile>,请删除它,以告知 VSIX 编译器生成 pkgdef 以注册您的包。纯粹基于 MEF 的插件根本不需要 pkgdef 文件,因此大多数项目模板都会添加它,但是一旦您创建了 VSPackage,您需要一个 pkgdef 来将其注册到 Visual Studio 的本机 COM 插件加载器。
接下来,在根元素的任意位置(不是<ItemGroup>)添加以下标记:xml <PropertyGroup> <UseCodebase>true</UseCodebase> </PropertyGroup>
VSPackages 实际上是在 Visual Studio hive 的配置键中注册并使用常规 COM 实践加载的 COM DLL。托管 VSPackage 使用 COM 互操作加载;它们被注册为 mscoree.dll,然后查找托管程序集以从同一注册表项加载。默认情况下,PkgDef 创建者将发出“Assembly”="YourAssemblyName",mscoree 将尝试使用标准的 .Net 程序集加载器加载它。除非您的 VSPackage DLL 在 GAC 中(它不会),否则这将不起作用,并且 VS 将默默地拒绝加载您的包。在项目文件中设置 <UseCodebase> 将使其发出 "CodeBase"="$PackageFolder$\YourAddin.dll" (在安装 VSIX 时,$PackageFolder$ 会替换实际的 DLL 路径),这会告诉 mscoree 的确切路径加载它。
- 执行命令
完成所有这些操作后,当您在插件中按 F5 时(在 Experimental 实例中运行),您的命令应该会显示出来。但是,您仍然需要实际执行该命令,以便在单击按钮时发生某些事情。
对于全局命令,最简单的方法是覆盖包中的 Initialize() 方法并添加如下代码:
var mcs = (OleMenuCommandService) GetService(typeof(IMenuCommandService));
var commandId = new CommandID(typeof(YourAddinCommand).GUID, (int)YourAddinCommand.MyCommand));
mcs.AddCommand(new MenuCommand(delegate {
MessageBox.Show("You clicked me!");
}, commandId);
对于适用于活动编辑器窗口的命令,我编写了一个类,它向编辑器的命令处理程序链添加了一个拦截器,并公开了一个接受命令枚举中的条目的简单接口。这既可用于实现新命令,也可用于拦截现有命令。您可以在 CommandTargetBase.cs 中找到它,您可以在此处查看示例用法。