前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >(翻译)LearnVSXNow!-#5 VSX的基本概念

(翻译)LearnVSXNow!-#5 VSX的基本概念

作者头像
明年我18
发布2019-09-18 11:31:32
8770
发布2019-09-18 11:31:32
举报
文章被收录于专栏:明年我18明年我18

在前几篇文章中,我们只是通过创建和“分析”三个非常小的、由VSPackage向导生成的package来管中窥豹地见识了一下VSX。这些例子有助于我们熟悉创建小的package的基本步骤。但是,我们必须更深入一些, 看一下Visual Studo IDE是怎样工作的,以及它是怎样集成package的。

在我们涉及到其他细节之前,我们先要整理一下对VSX的认识。在本篇文章里,我们不会创建任何代码,只是试图去搞清楚和VSX相关的概念。

警告:“底层用的是COM”

我在前面几篇文章中多次提到过,Visual Studio扩展性开发是基于COM技术的。package中的对象和实体(例如命令、菜单、工具栏、窗口、编辑器、项目等)都是COM对象。当然,如果我们用的是托管代码(例如C#、VB.NET),我们看到这些类和实例是托管的.NET类型和实例。但如果我们用了非托管代码,我们不得不处理COM对象和实例。

在开发VSX的代码时,之所以可以用很多模式和特性,是因为VSX里里外外都用了COM。我假设你对COM没有太深入的理解(我自己也不是一个COM专家),但我待会会告诉你一些必须要了解的基础知识。

什么是Visual Studio Package?

在前几篇文章中,我们创建了几个简单的Visual Studio Package,所以我们已经对VSPackage有了一个初步的认识,现在让我们更深入的探讨一下它。

VSPackage是构建Visual Studio的一个基本的单元。实际上,Visual Studio是由一系列的VSPackage协同工作而成的,就像一个生态系统一样。一个Package,不论是从VS体系结构上来看,还是从部署、安全和许可认证方面来看,它都是VS的一个基本单元。另外,在物理上,一个或多个package可以存在于同一个程序集中。

开发者(包括Visual Studio的开发者)通过创建VSPackage来扩展VS IDE。这些扩展可以是:

  1. 服务(Service)。服务是一些对象,它们提供功能供开发者或者其他package调用。例如,C#语言服务(顾名思义)是一个服务。
  2. 界面元素。例如菜单、工具栏、窗口等,开发者可以用它们在用户界面上执行一些动作,显示消息、信息和图片等等。
  3. 编辑器。在开发过程中,我们通过编写程序去创建应用程序。编写程序这项任务是由编辑器负责的。Visual Studio 2008有它自己的核心编辑器,但是我们也可以在VSPackage中创建我们自己的编辑器。
  4. 设计器。应用程序的创建不只是简单的敲入文本这么简单。我们拥有很多被称为设计器的可视化工具,我们可以利用他们来设计模块、组件、零部件、甚至整个应用系统。著名的例子是WinForm设计器,我们可以用它来创建WinForm的用户界面。
  5. 项目。当开发应用程序的时候,我们一般会面向一大堆的文件。项目用来组织这些源文件和资源,并且不是简单的存储这些文件这么简单,它还可以用来编译、调试和发布由源文件创建的产品。

在后面的文章中,我们将逐一探讨这些扩展的细节,今天在这里我先给大家一个基本概述来说明它们是什么,以及它们如何在VS中使用。

另外,一个package可以在Visual Studio的启动界面里或在关于对话框里显示它自己的信息。

一个package可以把它的状态和配置信息保存在持久化存储设备中,并且可以读取这些配置。例如文本编辑器可以设置语法高亮、字体、颜色、标签等。

每个package必须被所谓的package load key(PLK)签名,Visual Studio通过它来检查package的合法性。Visual Studio只会加载拥有合法PLK的package。另外,从技术上来说,Package是实现了IVsPackage接口的类型。这一次我们不会深入讨论IVsPackage,但在后面的文章中,我们将通过代码来测试它的细节。

什么是服务(Service)?

一般来讲,我们不会为了开发package而开发package。我们创建package是因为它们不但可以为我们自己提供功能(此时,我们是消费者),也可以为其他的package提供功能(此时,其他package是消费者)。例如,假设我们的package提供了一个工具窗去查找特定方法的引用,我们就是这个窗口的消费者。如果这个package不仅为这个工具窗提供查找功能,也作为“可调用的方法”为其他package服务,那么其他package就是这个服务的消费者。

所以,服务是package之间或package和与它相关的对象(当我说“package的对象”时,我指的是窗口、命令、设计器等这些被package自己创建的东西)之间的契约。

下图说明了VSPackage和服务之间的概念:

(译者注:非常遗憾,这里缺图。原文中的图片链接已经无效,联系了原文作者但一直没有回应,以后如果找到这个图片一定补上。)

VSPackage可以包含服务,这些package被称为service provider。在上图中,VSPackage1VSPackage3是service provider,而VSPackage2不是。能给其他package调用的服务被称为全局服务(global service)。VsPackage1和VsPackage3都包含global service,这些服务可以被VSPackage2调用(当然也可以被其他的package调用)。package也可以包含只能被自己调用或者只能被package的对象调用的服务。这种服务被称为本地服务(local service)。VSPackage1和VSPackage3都包含local service,它们被对象调用(例如被VSPackage1中的编辑器和VSPackage3中的工具窗)。

使用Service

关于VSX中的服务,有一个坏消息:它们是隐蔽的,不容易被发现。这意味着我们不能猜测出一个package(或其他对象)中能提供哪些服务。

所以,如果你想使用一个服务,你必须“通过它的名字调用它”,这意味着你必须知道这个服务的名字。要知道服务的名字,唯一的方法是去查阅这些服务所在package提供的文档。VSX的文档里列出了大概130个服务。

一般来说,服务被定义成接口。大部分服务只实现一个接口,但也有一部分服务实现了多个。所以,当我们想使用一个服务的时候,我们必须要知道两个“名字”:服务的名字和接口的名字。

你也许注意到了,我在“名字”这里用了引号。这是因为所有的服务都是对象。如果我们用的是interop类型,“名字”就是它们的.NET类型;如果我们用的是COM对象(非托管代码),“名字”就是这些COM类型的GUID。

让我们用一个例子来更清楚的说明它!在SimpleCommand里,我们使用SVsUIShell服务去显示一个消息框,我们用GetService方法去获得一个IVsUIShell接口的引用:

代码语言:javascript
复制
1: IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));    2: uiShell.ShowMessageBox(...);

当我们得到一个服务的引用后,我们就可以使用它提供的方法和属性了。在上面的例子中,我们调用了这个服务实例uiShell的ShowMessageBox方法。

加载package和访问服务

VSPackage访问服务的方式(现在我只是指通过GetService方法去得到服务实例)为服务模型带来了一些“特性”和结果。

  1. 按需加载。如果一个package的服务没有被使用,它是不需要被加载到内存的。所以,VS IDE只会加载那些服务被调用的package(译者注:作者的意思应该是指service provider)。实际上,package和service provider是两个不同的概念。理论上任何实现了IServiceProvider的对象都可以提供服务。如果我们继承了抽象类Package(就像我们在前几个篇文章中的例子那样),我们的package会自动成为一个service provider,这是因为基类Package实现了IServiceProvider接口以及很多其他接口。
  2. Siting VSPackages. IDE为所有的VSPackage提供了一个service provider,利用它可以获得由其他package或service provider提供的服务实例。当package加载到内存的时候,Visual Studio传递给package一个service provider的引用,可以用这个引用来访问全局服务(global service)。所以我们称呼它为siting VSPackage,如果一个package没有被site,它就不能够通过服务的实例来和Visual Studio交互。
  3. 访问全局服务(global service)。如果我们有一个已经被site的对象(例如一个VSPackage或实现了IVsPackage接口的对象),可以很简单的利用GetService方法去访问全局服务;如果我们的对象没有被site,但是我们可以通过它得到它所在的VSPackage的实例,我们依然可以用GetService方法;然而,在某些情况下我们的对象没有被site,并且没办法得到所在的package的实例,此时我们可以用Package.GetGlobalService这个静态方法。
注册服务

了解了关于服务的这么多信息之后,如果我告诉你在使用服务前必须要注册它们,我猜你们都不会感到奇怪。

要想注册服务,需要在Package的类定义文件上面加上ProvideServiceAttributeregpkg.exe会利用这个属性来注册服务。

虽然还有很多关于服务的有趣的东西,但就目前来说,这些已经足够了。以后我们会通过代码去深入研究它。

Interoperability程序集和Managed Package Framework

.NET开发人员更喜欢用托管的.NET类型,因为它们可以利用底层运行环境的强大特性。然而,由于历史原因(.NET时代之前的VS版本),Visual Studio的主体部分是建立在非托管代码上的,并支持COM类和接口。为了访问到COM对象,.NET提供了一种被称为interoperability程序集的东西,简单来讲,就是用.NET类型来包装了COM类型。我们有两种主要的方法去使用VSX中的COM对象:创建非托管代码(例如用C++);或者利用interoperability程序集中来编写托管代码(用c#或VB.NET)。

对于我来说,我更喜欢托管代码(并且我猜大部分.NET开发人员也是如此),所以我会用interop程序集去做我的示例代码。在一些常见的任务中,COM使用了不同的模式,例如在类型标识、内存分配、异常管理等方面,另外,COM不支持继承。

如果只使用interop程序集的话,我们的代码会变得非常冗长,并且不能够使用.NET和C#提供的语言和一些运行时的功能。微软在Visual Studio的COM interoperability程序集之上创建了一个框架,叫做Managed Package Framework(MPF),可以帮助我们用“本土化”的托管代码来创建VSPackage。

VSX中Interop程序集

GAC中安装了一堆的VSX的interop程序集,你也可以在VS SDK的安装目录(例如在C:\Program Files\Microsoft Visual Studio 2008 SDK)下的下VisualStudioIntegration\Common\Assemblies子目录中找到它们。这些interop程序集的名字以Microsoft.VisualStudio开头,但不是所有以这个开头的程序集都是interop程序集。在这个文件夹下面,你可以看到差不多100个程序集文件。其中,interop程序集如下(我省略了Microsoft.VisualStudio前缀):

程序集

描述

~.Shell.Interop

这个程序集定义了几百个核心的interop类型(包括接口,结构,枚举,类,等等)

~.Shell.Interop.8.0~.Shell.Interop.9.0

在VS 2005和VS 2008中,有不同的COM类型,这些不同的COM类型定义在这两个程序集中,其中8.0是给VS 2005用的,9.0是给VS 2008用的。

~.OLE.Interop

这个程序集包装了几百个标准OLE类型。

~.TextManager.Interop~.TextManager.Interop.8.0

Visual Studio有一个很好的内置编辑器。这两个程序集用来访问编辑器接口。其中,8.0是针对Visual Studio 2005和2008中新增的接口类型的。

~.Debugger.Interop

如果你想访问VS IDE提供的内置调试器中的接口和调试功能,你可以用这个程序集。

Managed Package Framework中的程序集

MPF程序集与interop程序集(以及其他的VSX相关的程序集)在同一个文件夹中,并且也是以Microsoft.VisualStudio开头的。其中,最重要的程序集如下:

程序集

描述

~.Shell and~.Shell.9.0

这两个程序集定义了MPF的核心类型。以9.0结尾的程序集是针对于VS 2008的,如果你用VS 2008开发,你应该用这个程序集,以便regpkg.exe可以注册你编译后的package。

~.Shell.Design(译者注:原文中的~.Shell.Desing应该属于笔误)

这个程序集中定义的类型可以用来扩展Visual studio的设计器。

VSPackage中需要引用的程序集

如果用VS 2008创建一个新的VSPackage,向导会帮我们添加一些对interop程序集和MPF程序集的引用,这些引用有:

  1. Microsoft.VisualStudio.OLE.Interop
  2. Microsoft.VisualStudio.Shell.9.0
  3. Microsoft.VisualStudio.Shell.Interop
  4. Microsoft.VisualStudio.Shell.Interop.8.0
  5. Microsoft.VisualStudio.Shell.Interop.9.0
  6. Microsoft.VisualStudio.TextManager.Interop

如果你需要其他的interop或者MPF程序集,你可以自己再添加引用。

总结

在这篇文章中,我们VSX的基本概念和最重要的细节做了一些探讨。

  1. VSPackage是Visual Studio的基础结构、安全、部署和许可认证中的基本单元。Visual Studio它自己也是建立在一系列的VSPackage之上的。
  2. VSPackage可以为其他package提供全局服务;服务是隐蔽的、不容易发现的;在使用服务前必须先注册它们;Visual Studio提供了一种按需加载的模式去查找和加载service provider。
  3. VSPackage是基于COM技术的。Visual Studio提供了interop程序集来访问COM类型;MPF(Managed Package Framework)对interop程序集做了一层包装,允许用“本地化”的托管代码开发Package。

当然,VSX中还有很多其他的重要的概念,但对于继续我们的学习来说,今天讨论的这些已经足够了。

在下一篇,我们继续用代码示例来探讨VSX的开发。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2010-03-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 警告:“底层用的是COM”
  • 什么是Visual Studio Package?
  • 什么是服务(Service)?
    • 使用Service
      • 加载package和访问服务
        • 注册服务
        • Interoperability程序集和Managed Package Framework
          • VSX中Interop程序集
            • Managed Package Framework中的程序集
              • VSPackage中需要引用的程序集
              • 总结
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档