(翻译)LearnVSXNow! #14- VSCT文件基础
在第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文件的基础,然后再用一些例子来说明它。
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子节点定义菜单,菜单有多种表现形式,最常用的有:
- 标准菜单:例如VS IDE中的文件、编辑、视图菜单。
- 上下文菜单:当在某些对象上点击鼠标右键时,弹出上下文菜单。
- 工具条:多个命令可以放在一行里。
Buttons
在Buttons节点里可以定义多个Button节点,一个Button代表用户可以交互的一个UI。不过,“Button”这个名字很容易让我们误解,因为我们通常所说的“Button”代表的是在表单上可以点击的按钮。但是在这里,“Button”的含义更像是一个菜单项。在vsct文件里,我们可以定义几种类型的Button:
- 标准按钮:用来执行命令的菜单项。
- 菜单按钮:用来显示子菜单。
- 下拉按钮:例如VS IDE里的Undo和Redo。
- “Swatch”按钮:用于显示像字体颜色选择器之类的按钮。
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”的菜单,并且包含两个菜单命令。我们需要按照下面的步骤来做:
- 第一步:在Symbols节点下,添加一个GuidSymbol节点,在这里定义我们需要用到的符号。
- 第二步:在Menus节点下,添加一个Menu节点,用来定义显示在主菜单里的菜单,并把它的Parent设置成一个主菜单级别的Group。
- 第三步:在Groups节点下,添加一个Group节点,用来定义我们的两个菜单命令的组。并把Parent设置成第二步里添加的Menu的id。
- 第四步:在Buttons节点下,添加两个Button节点,用于定义这两个命令。并且把Parent设置成第三步里添加的Group的id。
对应的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:
- 第一步:为新的group和button添加新的Symbols。
- 第二步:添加一个新的Group。
- 第三步:添加两个新的Button。
<?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属性:
- 第一步:为Bitmap strip添加一个ID。
- 第二步:添加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文件。
但这仅仅是个开始。
原文链接:http://dotneteers.net/blogs/divedeeper/archive/2008/03/02/LearnVSXNowPart14.aspx
写在后面的话:
离上一篇本系列的翻译已经过了很长时间了,在这里要和各位关注vsx的同学说声对不起。由于本人水平有限,翻译一篇实在太耗费时间和精力了,再加上最近比较忙,所以这个系列的进度很慢。还望各位在理解的同时,多多支持,您的支持就是我继续下去的动力。
出处:http://www.cnblogs.com/default
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。