LearnVSXNow!-#5 VSX的基本概念

LearnVSXNow!-#5 VSX的基本概念

     在前幾篇文章中,我們只是通過創建和“分析”三個非常小的、由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接口的引用:

   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的開發。

 

原文鏈接:http://dotneteers.net/blogs/divedeeper/archive/2008/01/11/LearnVSXNowPart5.aspx

作者:明年我18
出處:http://www.cnblogs.com/default
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,否則保留追究法律責任的權利。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章