安装完相应的插件工具后,就开始自己建立一个新的package文件了
打开VS,选择其他项目类型-扩展性,我们可以看到下图:
1 static class GuidList 2 { 3 public const string guidVSPackageEmptyPkgString = "4cd4d350-c117-4dde-afb1-368af69b118d"; 4 public const string guidVSPackageEmptyCmdSetString = "c565f06f-5723-4ab5-9eec-f429c14adbf4"; 5 public const string guidToolWindowPersistanceString = "4f19b025-dfd2-4b3f-a12d-2f9840509558"; 6 7 public static readonly Guid guidVSPackageEmptyCmdSet = new Guid(guidVSPackageEmptyCmdSetString); 8 };
其中guidVSPackageEmptyPkgString代表package name
guidVSPackageEmptyCmdSetString对应着guidVSPackageEmptyCmdSet,
guidToolWindowPersistanceString对应着package显示的ToolWindowPane,
文件PkgCmdIDList.cs
static class PkgCmdIDList { public const uint cmdidCalculateTool = 0x101; }
cmdidCalculateTool对应着guidVSPackageEmptyPkgString的id
然后就是StartupToolset.vsct文件了,可以说它是整个vspackage的核心
<?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"/> <Extern href="msobtnid.h"/> <Commands package="guidVSPackageEmptyPkg"> <Buttons> <Button guid="guidVSPackageEmptyCmdSet" id="cmdidCalculateTool" priority="0x0100" type="Button"> <Parent guid="guidSHLMainMenu" id="IDG_VS_WNDO_OTRWNDWS1"/> <Icon guid="guidImage" id="bmpPic1"/> <Strings> <CommandName>cmdidCalculateTool</CommandName> <ButtonText>Calculate Tool Window</ButtonText> </Strings> </Button> </Buttons> <Bitmaps> <Bitmap guid="guidImage" href="ResourcesPackage.ico" usedList="bmpPic1"/> </Bitmaps> </Commands> <Symbols> <GuidSymbol name="guidVSPackageEmptyPkg" value="{4cd4d350-c117-4dde-afb1-368af69b118d}"/> <GuidSymbol name="guidVSPackageEmptyCmdSet" value="{c565f06f-5723-4ab5-9eec-f429c14adbf4}"> <IDSymbol name="cmdidCalculateTool" value="0x0101"/> </GuidSymbol> <GuidSymbol name="guidImage" value="{91CB158E-29BC-4818-8C1F-967AF94D96B1}"> <IDSymbol name="bmpPic1" value="1"/> </GuidSymbol> </Symbols> </CommandTable>
他把前面提到的Guid.cs,PkgCmdIDList.cs关联了起来,指定了相应的guid
.vsct文件是Visual Studio 2008 SDK里的一种新的XML格式,vsct代表Visual Studio的命令表(Command Table),Visual Studio利用vsct文件的定义为我们的package的命令创建用户界面。如果你查看这个文件的属性的话,你会发现该文件的Build Action是VSCTCompile。在package编译过程中,vsct文件会被编译成二进制的资源,并以1000作为资源ID添加到VSPackage.resx资源文件中。当regpkg.exe去注册我们的package的时候,vsct文件代表的资源也会注册到Visual Studio中。而当VS实验室启动的时候,VS只需要去读取已注册的资源以便更新VS的界面(例如显示菜单或工具栏项),而不需要加载我们的package。
最后我们要看的是VSPackageEmptyPackage.cs文件
[PackageRegistration(UseManagedResourcesOnly = true)] // This attribute is used to register the informations needed to show the this package // in the Help/About dialog of Visual Studio. [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] [Guid(GuidList.guidVSPackageEmptyPkgString)] [ProvideMenuResource(1000, 1)] [ProvideToolWindow(typeof(MyToolWindow))] public sealed class VSPackageEmptyPackage : Package
属性 | 描述 |
PackageRegistration |
regpkg.exe命令发现到类定义中有PackageRegistration这个Attribute时,会把该类当作一个package。例如把这个Attribute加到我们的类定义上面,regpkg.exe就会把我们的EmptyPackagePackage类当作一个package,并且根据该类上面含有的其他Attribute来注册我们的类。另外,在我们的例子中,我们把PackageRegistration的UseManagedResourcesOnly设成了true,这意味着我们的package中的所有资源都会定义在可管理的package中(managed package),而不是定义在卫星程序集里(statelite.dll) |
DefaultRegistryRoot |
VS提供了一个简单的方法去开发和调试Visual Studio组件:在运行devenv.exe(也就是VS IDE)时,可以指定一个注册表的根。当我们在调试模式下运行我们的VS组件时,我们的组件实际上会运行在Visual Studio实验室下(Microsoft Visual Studio 2008 Experimental hive)。实验室模式下的VS和我们平时的开发环境应用了不同的设置。(译者注:有两种方式启动Visual Studio实验室,1、在开发package的VS IDE点击调试/开始执行或Ctrl+F5。2、通过开始-》所有程序-》Microsoft Visual Studio 2008 SDK-》Start Microsoft Visual Studio 2008 SP1 under Experimental hive) 当我们在VS中执行“开始调试”时(译者注:应该是利用VS进行编译时),VS会执行regpkg.exe命令,并且为该命令指定参数,以便注册我们的package到VS实验室环境中。 如果regpkg.exe命令在运行时并没有指定参数,那么就会用到DefaultRegistryRoot属性里指定的注册表的根。在我们的例子中,我们指定了“普通”的VS 2008 IDE用到的注册表根。 (译者注:利用VS进行编译时,查看输出窗口,可以看到有这么一条命令:RegPkg.exe /root:SoftwareMicrosoftVisualStudio9.0Exp /ranu /codebase "路径EmptyPackageinDebugEmptyPackage.dll",在这条命令里,通过/root开关指定了注册表的根为9.0Exp,也就是说我们通过DefaultRegistryRoot指定的根并没有用到。所以在通过VS进行编译时,会把package注册到Experimental hive中。原文作者的意思是如果不指定RegPkg命令的/root开关的话,就会用到DefaultRegistryRoot指定的注册表根) |
InstalledProductRegistration |
这个Attribute提供的信息会显示在VS IDE的“帮助|关于”对话框里。它的构造函数需要四个参数: --第一个参数是false,表示我们并不提供自己的界面去显示package信息。 --第二和第三个参数分别表示package的名字和描述。字符“#”表明名字和描述的值需要在资源文件中读出,资源名就是#号后面的ID。 --第四个参数“1.0”是产品ID(版本号) --第五个参数(IconResourceID)代表package的图标。 资源(名字、描述和图标)定义在VSPackage.resx文件中。 |
ProvideLoadKey |
每一个VS组件都应该用所谓的package load key(PLK)进行签名,Visual Studio用PLK去检查package的合法性。不过,如果你安装了Visual studio SDK的话,会安装一个VSIP的许可证,通过它,package可以在没有PLK的情况下运行。 但是,我们的package的最终用户很可能没有VSIP的许可证,所以我们需要PLK。ProvideLoadKey属性用于定义PLK和生成PLK的基础信息。通过比较基础信息和PLK是否一致,VS可以验证package并决定是否允许package加载运行。 ProvideLoadKey属性构造函数的前4个参数分别表示如下含义: --预计的最小版本 --产品(Package)的版本号 --产品(Package)的名字 --公司名称(所有者/开发者) 第5个参数是资源文件中定义PLK的资源ID。 (译者注:PLK需要到微软网站上http://msdn.microsoft.com/en-us/vsx/cc655795.aspx去申请) |
Guid |
这个Attribute定义了我们package的GUID。GUID是我们package的唯一标识,被用作COM注册、在IDE里得到我们package的引用,等等。 |
另外ProvideMenuResourceAttribute构造函数有两个参数,第一个参数是resourceID,这个参数值必须是1000,因为VSCT编译器在把vsct文件编译到VSPackage资源中的时候,默认用1000作为vsct文件对应的资源ID。第二个参数是versionID,它的取值在资源的缓存机制中非常重要。现在先不要深入研究它的细节了,只需要记住ProvideMenuResourceAttribute允许我们为package注册菜单资源。 我们需要修改project如下:
<VSCTCompile Include="StartupToolset.vsct">
<ResourceName>1000</ResourceName>
</VSCTCompile>