现在的位置: 首页 > 综合 > 正文

(翻译)LearnVSXNow! #14- VSCT文件基础

2011年02月02日 ⁄ 综合 ⁄ 共 4604字 ⁄ 字号 评论关闭

     在第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"

抱歉!评论已关闭.