• (翻译)LearnVSXNow!#2 创建一个空的VS Package


        为了熟悉Visual Studio Package的概念,在这篇文章中我们将创建一个空的Visual Studio 2008 package。

        打开Visual Studio 2008,新建项目,在项目类型对话框中选择“其他项目类型”/“扩展性”/Visual Studio Integration Package,如下图:(译者注:原文的图片无法打开,本系列的图是由译者另外截图的,并非原图)

     image

        如上图所示,我们把Framework的版本设为.NET Framework 2.0(译者注:实际上,不一定非得选择.NET Framework 2.0作为framework的版本,采用默认的3.5版本即可),项目名称设为EmptyPackage,点击“确定”后,将弹出Visual Studio Integration Package向导,如下图:

    image

        点击Next按钮,开始定义我们的Package。

     image

         如上图所示,我们选择C#作为该Package的开发语言,另外,由于VS Package必须被强命名,所以我们需要一个key文件来给我们的package程序集进行签名,在这里我们利用向导帮我们自动生成一个key文件。点击“Next”,将在下一步中设置Package的基本信息。

    image

        请根据上图填入相应的内容。VSPackage Name, VSPackage Version and Detailed information用于显示我们的package,Minimum Visual Studio value选项代表我们的package支持哪个版本的vs。

        这个选项非常重要,因为不同版本的Visual Studio有不同的service。如果我们的package用到了VS专业版才有的service,那么在VS标准版中将不能用我们的package。同时,我们也应该根据到自己的Visual Studio的版本和许可证来设置该选项。

        下一步是设置VS Package的选项。

    image

        向导可以帮助我们创建一个菜单命令(menu command)、一个工具窗口(tool window)和一个自定义编辑器(custom editor),但是由于我们这次只是创建一个空的package,所以在这里一个框都不要勾选。点击Next按钮后,会转到向导的最后一步,在这里我们可以为我们的package添加测试项目。

    image

        像上一步一样,为了创建一个最简单的package,在这里我们也不要勾选任何选项(事实上,我们需要勾掉它们,因为它们默认是被勾中的)。点击Finish按钮,Visual Studio会在几秒钟内帮我们创建该package的项目。成功创建项目后,在解决方案浏览器中,我们将看到下面的结构:

    image

        可以看到,在项目引用中,包含很多interop assembly,这些程序集帮助我们与Visual Studio IDE中的COM对象交互,并提供package需要的service。你也许发现了项目引用中的System.Core.dll,这个程序集是.Net Framework 3.5的一部分,这和我们一开始创建项目的时候选择的.NET Framework 2.0有些矛盾,不过没关系,现在我们先忽略它。

    Package的文件

        在我们的项目中,最重要的文件是一个资源文件和两个cs文件,如下:

    文件名 描述
    EmptyPackagePackage.cs 该文件定义了可以被Visual Studio加载的EmptyPackagePackage类。
    Guids.cs 就像COM世界充满GUID一样,我们的package也用GUID来标识自己。这个文件用于定义这些GUID
    VSPackage.resx 资源文件,保存我们package用到的字符串和图片

        向导也生成了一些“并不重要”的文件:

    文件名 描述
    AssemblyInfo.cs 定义程序集的信息
    Package.ico 该package的图标
    Resources.resx package级别的资源文件(初始的时候是空文件)
    GlobalSupressions.cs Global static code analysis rule suppressions(译者注:用于取消报告特定的静态分析工具规则冲突)

    测试这个Package

        如果是一个“Hello, world”程序的话,测试它是否正确是很简单的:只需要运行它使他显示信息即可。但是对于这个空的Package来说,只有一个地方可以证明这个Package注册成功了并且被IDE识别了:在“帮助|关于”菜单下,所有的packages都会被列出。如果运行我们的package(Ctrl+F5),将会启动Visual Studio 2008实验室(Microsoft Visual Studio 2008 Experimental hive),通过点击“帮助|关于”菜单,就可以看到我们的package:

    image

     

    它是如何工作的?

        现在是时候去查看这些代码并弄清楚我们的package是如何工作的了。为了使代码的可读性更好,我将忽略掉注释和不重要的部分。

        让我们从Guid.cs文件开始:

       1: using System;  
       2: namespace MyCompany.EmptyPackage
       3: {
       4:   static class GuidList
       5:   {
       6:     public const string guidEmptyPackagePkgString = "223643a0-af7c-4741-99df-e9641691af50";
       7:  
       8:     public const string guidEmptyPackageCmdSetString = "cecdc1f1-2fb2-40e4-88e8-ae8c85287a7c";
       9:  
      10:     public static readonly Guid guidEmptyPackageCmdSet = new Guid(guidEmptyPackageCmdSetString);
      11:  
      12:   };
      13: }

        这个文件定义了GuidList类,该类负责定义我们的package用到的GUID。第一个字符串guidEmptyPackagePkgString是我们的package的GUID,第二个字符串是我们的package的命令集(Command Set)的标识。由于我们只是做一个空的package,并没有任何命令(Command),所以我们可以忽略掉第二个GUID。

        Package定义在EmptyPackagePackage.cs文件中:

       1: using System;
       2: using System.Diagnostics;
       3: using System.Globalization;
       4: using System.Runtime.InteropServices;
       5: using Microsoft.VisualStudio.Shell;  
       6: namespace MyCompany.EmptyPackage
       7: {
       8:   [PackageRegistration(UseManagedResourcesOnly = true)]
       9:   [DefaultRegistryRoot("Software\\Microsoft\\VisualStudio\\9.0")]
      10:   [InstalledProductRegistration(false, "#110", "#112", "1.0", 
      11:     IconResourceID = 400)]
      12:   [ProvideLoadKey("Standard", "1.0", "EmptyPackage", "MyCompany", 1)]
      13:   [Guid(GuidList.guidEmptyPackagePkgString)]
      14:   public sealed class EmptyPackagePackage : Package
      15:   {
      16:     public EmptyPackagePackage()
      17:     {
      18:       Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, 
      19:         "Entering constructor for: {0}", this.ToString()));
      20:     } 
      21:     protected override void Initialize()
      22:     {
      23:       Trace.WriteLine (string.Format(CultureInfo.CurrentCulture, 
      24:         "Entering Initialize() of: {0}", this.ToString()));
      25:         base.Initialize();  
      26:     }
      27:   }
      28: }

        EmptyPackagePackage类定义上面有一些属性(Attribute),并且继承于Package抽象类,Package抽象类实现了IVsPackage接口。只要一个类实现了IVsPackage接口并注册到Visual Studio shell中,这个类就是一个package。标注在EmptyPackagePackage类上面的属性(Attribute)描述了怎样去注册package:

    属性 描述
    PackageRegistration

        regpkg.exe命令发现到类定义中有PackageRegistration这个Attribute时,会把该类当作一个package。例如把这个Attribute加到我们的类定义上面,regpkg.exe就会把我们的EmptyPackagePackage类当作一个package,并且根据该类上面含有的其他Attribute来注册我们的类。另外,在我们的例子中,我们把PackageRegistrationUseManagedResourcesOnly设成了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:Software\Microsoft\VisualStudio\9.0Exp /ranu /codebase "路径\EmptyPackage\bin\Debug\EmptyPackage.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的引用,等等。

        对于定义一个空的package来说,这些Attribute已经足够了。为了使package正常工作,必须初始化它。有两个地方可以放置初始化代码:

        — package类的构造函数可以初始化任何不需要放到VS IDE中的东西。当package的构造函数执行的时候,package虽然已经被实例化了,但是还没有和VS IDE关联起来。所以在构造函数里,我们不能访问到VS IDE的service和VS IDE的对象。

        — 当我们的package实例和VS IDE关联起来的时候,VS会调用Package类的虚方法Initialize。我们可以重写这个方法,并且在这个方法里去初始化任何需要访问到VS IDE的service的对象。

    总结

        我们创建了一个最小功能的和VS IDE集成的VS package(并且证明了它可以在关于对话框中显示)。这个package继承了Package类,Package类实现了IVsPackage接口。同时,我们为这个package类加了一下Attribute的标记,这些Attribute被regpkg.exe命令用来注册package。

        下一步,是时候为我们的package增加一些实用的功能了。

     

    原文链接:http://dotneteers.net/blogs/divedeeper/archive/2008/01/03/LernVSXNowPart2.aspx

  • 相关阅读:
    Seafile V4.1 安装笔记
    mysql int(3)与int(11)的区别
    python命令行参数处理模块 optparse 使用参考
    Python标准库 urllib2 的使用
    Python默认模块 os和shutil 实用函数
    ApacheBench 使用教程
    ThinkPHP中PATHINFO模式优化
    Perl中的特殊内置变量详解
    Perl内置变量速查表
    eclipse jetty debug
  • 原文地址:https://www.cnblogs.com/default/p/1674584.html
Copyright © 2020-2023  润新知