在第13篇里,我说过我要给你们展示一些菜单、工具栏和命令的示例代码,但是相关的东西太多了,一篇文章没办法全部囊括,所以在这里我只涉及一些和vsct文件相关的代码。
在本系列前面的文章里,我多次提到过Package是按需加载的,IDE只有在真正用到Package的时候才去加载它们。但这样就带来一个问题:IDE如何在不加载Package的情况下,显示Package里定义的菜单和工具栏?或者说当我们在IDE里看到某个Package的菜单的时候,这个Package到底有没有被加载到IDE里?
当Package被注册后(通过regpkg.exe),Package里代表菜单和工具栏的资源实际上是被单独存放在一个地方,所以在Visual Studio启动后,它就可以从这个地方读取出这个信息,并显示相应的菜单和工具栏,而不必加载Package本身。
实现这种模式的关键,就在于vsct(Visual Studio Command Table)文件。这个文件是旧版的Visual Studio SDK中ctc文件的替代品,是用来定义命令以及与命令相关的UI的。编译完package后,vsct文件被编译到一个cto文件中,并且作为一个资源添加到package的dll里。
在VS 2005版本的Visual Studio SDK里,用的是文本格式的ctc文件。编辑和理解ctc文件并不是一个简单的任务。所以在Visual Studio 2008 SDK里,微软创建了一种新的基于xml的vsct文件和相应的编译器,负责把vsct编译成cto格式。
应用vsct文件的最大的优势在于它就是一个xml文件,它拥有xml文件固有的特性,例如自动生成结束标签或者智能感知。所以微软建议我们用vsct文件来代替ctc文件,当然,ctc文件目前依然可以使用。
在这篇文章里,我将给大家介绍一些在前面的文章里没有提到的关于vsct文件的细节。首先我要先介绍一下vsct文件的基础,然后再用一些例子来说明它。
xml文件的xsd架构可以告诉我们一个xml文件里应该包含什么内容,因为xsd文件里定义了相应的xml文件的语法、词法等很多信息,并且“据说”不管是对计算机还是对人来说,可读性都很好。毫无疑问,计算机可以很牛逼的识别xsd文件,但对于我们人类来说,其实它的可读性并不是那么好。所以在这里我就不给大家展示vsct的xsd架构了,而是通过例子来解释一下vsct的结构。
外层节点
VSCT文件的根结点是CommandTable:
<?xml version="1.0" encoding="utf-8"?><CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/..." xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!-- Content of the command table --></CommandTable>
command table的元素的命名空间是“http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable”,不要忘了加上它,但是我为了使示例代码更短,所以不加这个命名空间。
CommandTable的子节点是:
<CommandTable xmlns="..." xmlns:xs="..."> <Extern/> <Include/> <Define/> <Commands/> <CommandPlacements> <VisibilityConstraints/> <KeyBindings/> <UsedCommands/> <Symbols/></CommandTable>
其中,最重要的是Extern、Commands和Symbols节点,让我们看一下VSPackage向导帮我们生成的vsct文件:
<?xml version="1.0" encoding="utf-8"?><CommandTable xmlns="..." xmlns:xs="..."> <Extern href="stdidcmd.h" mce_href="stdidcmd.h"/> <Extern href="vsshlids.h" mce_href="vsshlids.h"/> <Extern href="msobtnid.h" mce_href="msobtnid.h"/> <Commands package="guidSimpleCommandPkg"> <Groups> <Group guid="guidSimpleCommandCmdSet" id="MyMenuGroup" priority="0x0600"> <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/> </Group> </Groups> <Buttons> <Button guid="guidSimpleCommandCmdSet" id="cmdidMyFirstCommand" priority="0x0100" type="Button"> <Parent guid="guidSimpleCommandCmdSet" id="MyMenuGroup" /> <Icon guid="guidImages" id="bmpPic1" /> <Strings> <CommandName>cmdidMyFirstCommand</CommandName> <ButtonText>My First Command</ButtonText> </Strings> </Button> </Buttons> <Bitmaps> <Bitmap guid="guidImages" href="Resources\Images_32bit.bmp" mce_href="Resources\Images_32bit.bmp" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/> </Bitmaps> </Commands> <Symbols> <GuidSymbol name="guidSimpleCommandPkg" value="{2291da24-92e5-4ea4-bdb7-72a9b5ac7d59}" /> <GuidSymbol name="guidSimpleCommandCmdSet" value="{a982b107-4ad4-437e-b2bc-cdf2708aa376}"> <IDSymbol name="MyMenuGroup" value="0x1020" /> <IDSymbol name="cmdidMyFirstCommand" value="0x0100" /> </GuidSymbol> <GuidSymbol name="guidImages" value="{5c3faf04-8190-48c4-a6e9-71f04f1848e5}" > <IDSymbol name="bmpPic1" value="1" /> <IDSymbol name="bmpPic2" value="2" /> <IDSymbol name="bmpPicSearch" value="3" /> <IDSymbol name="bmpPicX" value="4" /> <IDSymbol name="bmpPicArrows" value="5" /> </GuidSymbol> </Symbols> </CommandTable>
Symbols和IDs
我在第6篇里已经说过了,VS IDE里的对象(例如命令和相关的UI元素)都有唯一的标识,我们需要利用他们的唯一标识符来引用某个元素。标识符由一个GUID和一个32位无符号整数组成。GUID代表一个逻辑上包含对象的容器,32位无符号整数代表这个对象在逻辑容器内的id。(也有一些对象只用GUID来标识,稍后我会介绍它们)。
在vsct文件里,如果直接用这些GUID和ID的话,代码的可读性就太差了,幸好vsct文件里有Symbols节点。该节点用于给这些GUID或者ID起个可读性较好的名字,其中:GuidSysmbol子节点用来给逻辑容器GUID起别名,嵌套的IDSymbol节点用来给32位无符号数起别名。
在上面的代码段中,定义了三个GUID容器。第一个是一个空的容器(别名是guidSimpleCommandPkg),另外两个则包含若干个ID。定义好了symbols之后,就可以引用它们了:
<Commands package="guidSimpleCommandPkg"> <Groups> <Group guid="guidSimpleCommandCmdSet" id="MyMenuGroup" priority="0x0600"> <!-- ... --> </Group> </Groups> <Buttons> <Button guid="guidSimpleCommandCmdSet" id="cmdidMyFirstCommand" priority="0x0100" type="Button"> <!-- ... --> </Button> </Buttons> <Bitmaps> <Bitmap guid="guidImages" href="Resources\Images_32bit.bmp" mce_href="Resources\Images_32bit.bmp" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/> </Bitmaps> </Commands>
在定义命令的时候,我们经常需要引用VS IDE里已经定义好的菜单。例如,如果想在“工具”菜单下添加子菜单,我们必须引用已经定义在VS IDE里的“工具”这个菜单。当然, “工具”菜单和其他菜单(包括我们自己的菜单)的定义方式是一样的:
<Group guid="guidSimpleCommandCmdSet" id="MyMenuGroup" priority="0x0600"> <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/></Group>
Parent子节点指定了由Group元素定义的逻辑容器应该被放在哪个位置。guidSHLMainMenu 代表VS IDE的主菜单的逻辑容器,IDM_VS_MENU_TOOLS 表示“工具”菜单项的ID。也许你已经猜到了,有上千个和VS IDE相关的GUID和ID。
可以用Extern节点来访问它们:
<?xml version="1.0" encoding="utf-8"?><CommandTable xmlns="..." xmlns:xs="..."> <Extern href="stdidcmd.h" mce_href="stdidcmd.h"/> <Extern href="vsshlids.h" mce_href="vsshlids.h"/> <Extern href="msobtnid.h" mce_href="msobtnid.h"/> <!-- ... --></CommandTable>
Extern节点用于引用已经定义好的GUID和ID。.h文件是标准的c++头文件,里面定义了很多标识符和宏,把这些头文件引用进来之后,就可以在vsct文件的任何地方引用已经定义好的GUID和ID了,就像我们定义在Symbols节点里的一样。
这些头文件位于VS 2008 SDK根目录的VisualStudioIntegration\Common\Inc子目录下面:
文件 | 内容 |
---|---|
stdidcmd.h | 包含Visual Studio里公开的所有命令的ID。其中,用于菜单命令的ID用cmdid作为前缀,用于标准编辑器命令的ID用ECMD_prefix作为前缀,还包括一些其他的命令ID |
vsshlids.h | 包含Visual Studio Shell的菜单命令的ID |
msobtnid.h | 包含标准的Microsoft Office命令(其中很多命令用在VS IDE里,例如剪切、复制、粘贴) |
如果你有耐心看一下这几个文件的话,你就会在vsshlids.h文件里找到guidSHLMainMenu和IDM_VS_MENU_TOOLS的定义:
...DEFINE_GUID (guidSHLMainMenu, 0xd309f791, 0x903f, 0x11d0, 0x9e, 0xfc, 0x00, 0xa0, 0xc9, 0x11, 0x00, 0x4f);...#define IDM_VS_MENU_TOOLS 0x0085...
Commands
毫无疑问,vsct文件里最重要的节点就是Commands了。这个节点用来定义命令:
<Commands package="..."> <Groups/> <Menus/> <Buttons/> <Combos/> <Bitmaps/></Commands>
任何一个命令都必须从属于IDE本身或者从属于某个Package。一个程序集可以包括一个或多个Package,为了指定Command所在的Package,Commands节点的package属性必须是相应package的GUID。通常情况下,我们的程序集里只包含一个Package,所以我们通常在把VSPackage向导帮我们生成的Package的ID作为package属性的值:
<Commands package="guidSimpleCommandPkg"> <!-- ... --></Commands>
Commands节点下包含一些子节点,每一个都有自己的功能:
Groups
在Groups下,用子节点Group元素来定义所谓的命令组。一个命令组是一个逻辑容器,里面包含了功能相近的命令。例如,“生成解决方案”、“重新生成解决方案”和“清理解决方案”这几个菜单属于同一个组:它们位于VS主菜单的“生成”菜单下面,或者某个解决方案的右键菜单中:
我们并不是把单独的命令直接放到一个已经存在的菜单下面,而是把一个命令组放进去。属于这个组中的每个命令都会显示在相关的菜单下面,命令组可以看做是重用命令的一种方式。
Menus
在Menus下,用Menu子节点定义菜单,菜单有多种表现形式,最常用的有:
Buttons
在Buttons节点里可以定义多个Button节点,一个Button代表用户可以交互的一个UI。不过,“Button”这个名字很容易让我们误解,因为我们通常所说的“Button”代表的是在表单上可以点击的按钮。但是在这里,“Button”的含义更像是一个菜单项。在vsct文件里,我们可以定义几种类型的Button:
Combos
Combos节点下可以定义多个Combo节点。一个Combo节点用于显示在Combo box里的命令。我认为理解这个需要一定的vsx基础,所以我会在晚些时候再来说明这个概念。在我写这篇文章的时候,VSCT的文档里有一个小错误:它里面说到Combo节点是Commands节点的直接子节点,但实际上正确的结构是Commands、Combos和Combo。所幸,vsct的智能提示是正确的。
Bitmaps
工具条和菜单如果没有图标的话,对用户来说就太索然无味了。Bitmaps节点就是用来定义图标的。图片可以来自于外部文件或者package的资源文件。
可以用多种格式的图片,例如bmp、gif、png。但是对于这几种图片来说,不能用同一种使用方式。例如,我在用32位bmp图片的时候遇到了问题,如果在显示设置里用了120DPI的话,原本16*16像素的图片会被拉伸成20*20的,在拉伸后的图片里自动添加了一些带颜色的像素;但是如果用png图片的好,拉伸后的图片看起来就很圆滑。在某些情况下只有特定格式的图片才能被支持(我不清楚这到底是一个bug还是vs的特性):例如对于工具窗的图标来说,png图片是不支持的(如果用了png,并不会显示图标),只支持24位的以紫红色作为透明色的bmp图片。
所以,如果在用图标时遇到了问题了,不妨换几种图片格式试试看。
定义Command
为了成功的在VS IDE里添加命令,我们至少需要一个Group和一个Button节点,如果我们还想添加图标的话,我们还需要至少一个Bitmap节点。如果我们不想简单的把命令组添加到VS已经定义好的菜单下的话,我们还需要Menu节点。
Menu、Group和Button节点有一些共有的属性和子节点。下表是这些属性:
属性 | 描述 |
---|---|
guid | 元素标识符的GUID部分,必填。 |
id | 元素标识符的uint部分,必填。 |
priority | 表示元素排列顺序的数字,可选项。数字越小,位置越靠前。但是我们并不知道所有元素的priority的值,所以用这个属性并不能保证可以精确的排列元素。 |
type | 确定元素的外观和布局的可选项,但Group节点不包含这个属性。 |
除了Bitmap之外,Commands的其他子节点都有如下的子节点:
子节点 | 描述 |
---|---|
Parent | 该元素的上级。在第13篇文章里我提到过一个命令可以附加到一个或多个菜单项上。在这里你可以定义0个或1个Parent元素。如果想把一个命令附加到一个以上的菜单时,可以用 CommandPlacement元素(稍后我们会提到)。 Parent元素用guid和id属性来标识上级元素。对于Button来说,它的Parent必须是Group;对于Group来说,它的Parent必须是Menu。 |
Annotation | 添加注释,可选项。注释可以是简单的文本,也可以是嵌套的结构。 |
Menu、Button、Combo的子节点如下:
子节点 | 描述 |
---|---|
CommandFlag | 可以包含0个或多个该节点。某些标记只有和特定的标记联合起来使用时才有效,例如, DynamicVisibility和DefaultInvisible两个标记表示在vs启动的时候,对应的菜单项不显示。 |
Strings | 这个节点包括几个子节点,表示对应元素的文本。至少需要包括一个ButtonText子节点,用于定义对应元素的文本标题。另外,还可以有ToolTipText、MenuText、CommandName以及其他子节点。更多细节可以参考vsct的schema。 |
Icon | 只有Button元素才能包含该子节点,用于定义和Button相关的图标。 |
定义Bitmap
Commands节点下的Bitmaps节点用来定义菜单和工具条项中用到的图片。每一个图片用一个Bitmap元素定义。Bitmap元素里引用一个16*16像素的图片,或者一个16*N的bitmap strip,其中N是16的倍数。一个bitmap由一个GUID标识,但这个GUID并不是package的ID,也不是command set的ID。我们用基于1的数字来指定bitmap strip中的一个特定图片。
像command和menu的ID一样,我们也在Symbols里面定义bitmap的ID。例如,如果我们用VSPackage向导创建了一个带有工具窗的package的话,在vsct文件里我们可以看到如下定义:
<?xml version="1.0" encoding="utf-8"?><CommandTable xmlns="..." xmlns:xs="..."> <!-- Extern elements --> <Commands package="..."> <!-- Menus, Groups and Buttons --> <Bitmaps> <Bitmap guid="guidImages" href="Resources\Images_32bit.bmp" mce_href="Resources\Images_32bit.bmp" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/> </Bitmaps> </Commands> <Symbols> <GuidSymbol name="guidImages" value="{...}" > <IDSymbol name="bmpPic1" value="1" /> <IDSymbol name="bmpPic2" value="2" /> <IDSymbol name="bmpPicSearch" value="3" /> <IDSymbol name="bmpPicX" value="4" /> <IDSymbol name="bmpPicArrows" value="5" /> </GuidSymbol> </Symbols></CommandTable>
在Symbols节点下定义了Bitmap专用的GUID(guidImages),并且也用基于1的数字定义了图片在bitmap strip中的索引。在上面这个例子里,bmpPicSearch是strip中的第3个图片。
Bitmap的href属性指定了图片文件的位置,是相对于vsct文件的位置。usedList属性指定bitmap strip里可用的图片。如果我们想把一个Button的图标设置成第三个图片,我们可以用下面的代码:
<Button ...> <Icon guid="guidImages" id="bmpPicSearch" > </Button>
在讨论了vsct的Groups、Menus和Buttons之后,让我们来看一些例子。
创建一个主菜单级别的命令
VSPackage向导可以帮我们把菜单放到如下位置:如果我们创建一个简单的命令的话,向导会把菜单放到“工具”菜单下;如果我们创建一个简单的工具窗的话,向导会把菜单放到“视图”菜单下。然而,在很多情况下我们需要把菜单放到VS的主菜单里。该怎么做呢?
现在我们要在vs的主菜单上添加一个“HowToPackage”的菜单,并且包含两个菜单命令。我们需要按照下面的步骤来做:
对应的vsct文件的内容如下:
<?xml version="1.0" encoding="utf-8"?><CommandTable xmlns="..." xmlns:xs="..."> <Extern href="stdidcmd.h" mce_href="stdidcmd.h"/> <Extern href="vsshlids.h" mce_href="vsshlids.h"/> <Extern href="msobtnid.h" mce_href="msobtnid.h"/> <Commands package="..."> <Menus> <Menu guid="guidHowToPackageCmdSet" id="TopLevelMenu" priority="0x100" type="Menu"> <Parent guid="guidSHLMainMenu" id="IDG_VS_MM_BUILDDEBUGRUN" /> <Strings> <ButtonText>HowToPackage</ButtonText> <CommandName>HowToPackage</CommandName> </Strings> </Menu> </Menus> <Groups> <Group guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup" priority="0x0600"> <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenu"/> </Group> </Groups> <Buttons> <Button guid="guidHowToPackageCmdSet" id="cmdFirstCommand" priority="0x0100" type="Button"> <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup" /> <Strings> <CommandName>cmdidFirstCommand</CommandName> <ButtonText>First Command</ButtonText> </Strings> </Button> <Button guid="guidHowToPackageCmdSet" id="cmdSecondCommand" priority="0x0101" type="Button"> <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup" /> <Strings> <CommandName>cmdidSecondCommand</CommandName> <ButtonText>Second Command</ButtonText> </Strings> </Button> </Buttons> </Commands> <Symbols> <GuidSymbol name="guidHowToPackageCmdSet" value="{8D7B9CB3-3591-47f9-B104-B7EB173E0F03}" > <IDSymbol name="TopLevelMenu" value="0x0100" /> <IDSymbol name="TopLevelMenuGroup" value="0x0200" /> <IDSymbol name="cmdFirstCommand" value="0x0300" /> <IDSymbol name="cmdSecondCommand" value="0x0301" /> </GuidSymbol> <!-- Other Guids for the package --> </Symbols> </CommandTable>
正如你看到的那样,为了实现这个简单的功能,我们写了好多代码。在菜单的定义那里,我把Parent里用到的ID高亮显示了。如果运行起这个Package,会看到在“生成”和“调试”菜单中间,多了一个新的菜单:
这是由Menu的Parent属性和priority属性决定的:
<Menu guid="guidHowToPackageCmdSet" id="TopLevelMenu" priority="0x100" type="Menu"> <Parent guid="guidSHLMainMenu" id="IDG_VS_MM_BUILDDEBUGRUN" /> <!-- ... --></Menu>
IDG_VS_MM_BUILDDEBUGRUN是包含“生成”和“调试”菜单的逻辑组,priority属性值0x100使我们的菜单显示在“调试”之前。如果把priority的值改成0x700的话,我们的菜单就会移到“调试”菜单的后面:
在看到Button定义的代码之后,你也许会觉得Group的存在并不必要:为什么不把Button的Parent直接设置成Menu呢:
<Button ...> <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenu" /> <!-- ... --></Button>
把Button的定义改了以后,会发现HowToPackage菜单消失了。这是因为button的parent不能直接是menu,它的parent必须是group才行。正是由于HowToPackage菜单没有任何子菜单,所以它不显示了。
在一个菜单里分隔菜单命令
如果我们在一个菜单下放一个以上的group,vs会在group直接插入一个分隔符。现在让我们在上面已经创建的vsct文件里再添加一个含有两个命令的group:
修改后的vsct文件如下:
<?xml version="1.0" encoding="utf-8"?><CommandTable xmlns="..." xmlns:xs="..."> <!-- Extern elements --> <Commands package="..."> <!-- Menus section unchanged --> <Groups> <!-- New group added --> <Group guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup2" priority="0x0600"> <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenu"/> </Group> </Groups> <Buttons> <!-- New buttons added --> <Button guid="guidHowToPackageCmdSet" id="cmdThirdCommand" priority="0x0102" type="Button"> <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup2" /> <Strings> <CommandName>cmdidThirdCommand</CommandName> <ButtonText>Third Command</ButtonText> </Strings> </Button> <Button guid="guidHowToPackageCmdSet" id="cmdFourthCommand" priority="0x0102" type="Button"> <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup2" /> <Strings> <CommandName>cmdidFourthCommand</CommandName> <ButtonText>Fourth Command</ButtonText> </Strings> </Button> </Buttons> </Commands> <Symbols> <GuidSymbol name="guidHowToPackageCmdSet" value="{...}" > <!-- New IDSymbols added --> <IDSymbol name="TopLevelMenuGroup2" value="0x0201" /> <IDSymbol name="cmdThirdCommand" value="0x0302" /> <IDSymbol name="cmdFourthCommand" value="0x0303" /> </GuidSymbol> <!-- Other Guids for the package --> </Symbols> </CommandTable>
运行起来后的效果如下图:
为菜单添加图标
如果我们想给菜单添加图标,我们需要定义个Bitmap节点,并且给Button节点添加相应的Icon属性:
修改后的vsct文件如下:
<?xml version="1.0" encoding="utf-8"?><CommandTable xmlns="..." xmlns:xs="..."> <!-- Extern elements --> <Commands package="..."> <!-- Menus section unchanged --> <!-- Groups section unchanged --> <Buttons> <Button guid="guidHowToPackageCmdSet" id="cmdFirstCommand" priority="0x0100" type="Button"> <!-- Icon added, other children unchanged --> <Icon guid="guidImages" id="bmpPic1" /> </Button> <Button guid="guidHowToPackageCmdSet" id="cmdSecondCommand" priority="0x0101" type="Button"> <!-- Icon added, other children unchanged --> <Icon guid="guidImages" id="bmpPic2" /> </Button> <Button guid="guidHowToPackageCmdSet" id="cmdThirdCommand" priority="0x0102" type="Button"> <!-- Icon added, other children unchanged --> <Icon guid="guidImages" id="bmpPicX" /> </Button> <Button guid="guidHowToPackageCmdSet" id="cmdFourthCommand" priority="0x0102" type="Button"> <!-- Icon added, other children unchanged --> <Icon guid="guidImages" id="bmpPicArrows" /> </Button> </Buttons> <Bitmaps> <!-- A new Bitmap added --> <Bitmap guid="guidImages" href="Resources\Images_24bit.bmp" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/> </Bitmaps> </Commands> <Symbols> <!-- New GuidSymbol section added --> <GuidSymbol name="guidImages" value="{...}" > <IDSymbol name="bmpPic1" value="1" /> <IDSymbol name="bmpPic2" value="2" /> <IDSymbol name="bmpPicSearch" value="3" /> <IDSymbol name="bmpPicX" value="4" /> <IDSymbol name="bmpPicArrows" value="5" /> </GuidSymbol> <!-- Other Guids for the package --> </Symbols> </CommandTable>
运行后的效果如下图:
试一下CommandFlag
CommandFlag节点可以定义命令的一些行为。让我们看一个简单的例子:为第一个命令添加TextOnly标记,为第三个命令添加DefaultDisabled 标记:
<Buttons> <Button guid="guidHowToPackageCmdSet" id="cmdFirstCommand" priority="0x0100" type="Button"> <!-- CommandFlag added, other children unchanged --> <CommandFlag>TextOnly</CommandFlag> </Button> <Button guid="guidHowToPackageCmdSet" id="cmdThirdCommand" priority="0x0102" type="Button"> <!-- CommandFlag added, other children unchanged --> <CommandFlag>DefaultDisabled</CommandFlag> </Button>
运行后的效果如下图:
在这篇文章里,我们围绕着vsct文件谈论了Visual Studio的Command table。在生成VSPackage时,vsct文件被编译到cto文件里,并且作为嵌入的资源添加到Package程序集里。通过regpkg.exe注册到VS里之后,VS就知道在启动时应该加载哪些菜单项了。
vsct文件是旧版的ctc文件的替代品,在这个文件里,最重要的部分是Commands节点,在这个节点里可以定义命令以及相关的Menu、Group、Button、Combo和Bitmap元素。IDs定义在Symbols节点里。利用Extern元素,我们可以引用VS预定义的头文件。
在这篇文章的第二部分,我们用几个例子来说明如何定义vsct文件。