手动新建一个vs插件程序需要什么步骤?
1. 给命令创建一个ID,名字和显示的文本。
![](https://i-blog.csdnimg.cn/blog_migrate/0ba473c30bb462c241c95b4605192bfc.jpeg)
一般为了让别人调用我们的插件,我们会提供一个上下文菜单供他们选择,,如上图所示的“New Test”。所以我们也需要提供这么一个菜单让人家调用(那种随VS启动运行的插件不一定需要菜单项)。这样的菜单项都有一个对应的ID关联。以后的vsct和代码中我们都需要使用这个ID来代表“New Test”这个命令。
![](https://i-blog.csdnimg.cn/blog_migrate/1cc6bdb757f321237f373ac88b98bb99.png)
2. 新建一个vsct文件
vsct简单来说就是一个xml,里面描述了命令的文字,图标,显示的位置等等信息。
![](https://i-blog.csdnimg.cn/blog_migrate/b024db9a1b6120ca2bceeb1037f80516.png)
可以看到vsct总体分为三部分。一部分由extern标签组成,一部分由commands标签包围,最后一部分由symbols包围。
- extern是指引入外部的一些变量。比如当我们需要在Tool菜单下添加菜单时,我们需要使用到“IDM_VS_MENU_TOOLS” 这个变量。此变量不是我们声明的,它是由VS在外部声明好了,然后我们通过extern引入进来的。那些xxxx.h的文件你可以在"{sdk安装目录}\VisualStudioIntegration\Common\Inc"下面找到。我们试着打开vsshlids.h文件,看看里面到底有什么。
![](https://i-blog.csdnimg.cn/blog_migrate/81f071b763a755aec1b9a79c3fbd1b49.png)
在这个文件中我们找到了“IDM_VS_MENU_TOOLS”的定义。所以,如果以后你不知道其他菜单的命令可以到这个文件当中多寻找寻找。
- commands中定义了一系列的菜单元素,包括按钮,图标,命令分组等信息。
![](https://i-blog.csdnimg.cn/blog_migrate/ce3057e1b910ed69a4b0bd8d022456aa.png)
所谓分组,实际上就是将一系列的按钮放在一起并使用分割线和其他的按钮加以区别。
这里需要注意的是按钮必须放入到分组中才能正确显示,如果只声明了按钮,并指定按钮的parent为IDM_VS_MENU_TOOLS是没有用的。buttons标签中定义了一个一个的菜单项,包括他们的名字,ID等等信息。Bitmap中则定义了一些菜单显示的图标资源。
![](https://i-blog.csdnimg.cn/blog_migrate/6365a1a6d63984131fcc4ddc48767e74.png)
- symbols
在前面的Groups和Buttons标签中,我们可以看到许多的guid属性,里面的所有的字符串其实都是在这里声明的。这样我们就不必写一长串的xxxx-xxxxx-xxxx-xxxxx的guid了。就像c#我们先声明了一个int型的变量i,然后再其他地方直接使用这个i就能获得值一样。
![](https://i-blog.csdnimg.cn/blog_migrate/eca5b7ef5d5680d59e434c8754ff05dd.png)
3. 在继承package的类上面声明provideMenuResource标签
声明这个标签的目的是为了告诉vs我们这个插件是支持菜单的,这样vs加载插件的时候就会去读取vsct资源,从而显示相应的标签。
![](https://i-blog.csdnimg.cn/blog_migrate/93a2ffc1fc880251934d4a20d8d7569e.png)
4.在代码中绑定按钮事件
如果你做完上面的步骤,那么你现在按F5运行的时候应该已经能够在Tool菜单下看见我们定义的菜单了,但是你点了没反应。这里需要提到的一点就是vs插件是按需加载的。所谓的按需加载是指只有在你点击了菜单的时候,你的插件才会开始被加载进入内存并执行相应的方法。(验证这一点的方法是在继承package类的Initialize方法上设置一个断点,你会看见当你按下对应的菜单后,才会执行到断点那里。)这也是为什么我们需要将菜单的格式写在vsct里面的原因,vs在加载插件的时候只要去加载vsct编译的二进制文件就能知道这个插件有哪些菜单并显示出来就可以了。我们一般的Initialize方法中绑定菜单的单击方法:
OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if ( null != mcs )
{
// Create the command for the menu item.
CommandID menuCommandID = new CommandID(GuidList.guidVSPackage2CmdSet, (int)PkgCmdIDList.cmdidMyCommand);
MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID );
mcs.AddCommand( menuItem );
}
这个menuCommandID关联了一个方法回调(在这里是MenuItemCallback方法),即用户按了这个菜单项之后需要执行的操作。