通過Visual Studio向導生成Management 插件框架就不說了,網上能搜到不少資料。本篇重點是說明怎么設計一個插件安裝包,適用于Management Studio 2005 到2014的版本。
先講明這么做要面臨的幾個難點:
1、SSMS 2008 和 SSMS 2008 R2的安裝包注冊表項名稱一樣,但只能放一個。也就是,如果只放SSMS 2008的注冊表項,SSMS 2008 R2 啟動的時候會嘗試讀取,并報錯,錯誤本質上是SSMS 2008 R2程序集和SSMS 2008 不同 。同理,如果只是單獨放SSMS 2008 R2的注冊表項,在SSMS 2008的機器上也會報錯。
2、SSMS 2012 和 SSMS 2014查找插件的方法不再通過注冊表了,而是通過目錄上特定的文件來查找的,這個是個關鍵,如果你不知道該把向導生成的*.addin放哪兒,SSMS 就不能正常加載。
3、要同時兼容.NET Framework 2.0 - 4.0 并具有Windows Installer安裝項目的只有Visual Studio 2010,必須采用VS 2010來編寫。
下面,進入正題。
先拿最簡單的SSMS 2005來說,對應于ProjkyAddin項目的ForYukon項目。
項目ForYukon中,編譯后程序集文件名稱是“Projky.ForYukon.dll”,插件加載時必須指定一個實現“IDTExtensibility2”的類,這在向導中就已經生成好了的,這里是“Projky.ForYukon.Connect”類。
那么,接下來就是讓“Projky.ForYukon”插件項目,在SSMS 2005中正常加載,步驟如下。
同一解決方案中,添加一個名為“Projky.Setup”的安裝項目,在Setup項目上右鍵-〉“添加”-〉“項目輸出”,從下拉列表中選擇“Projky.ForYukon”,然后會看到Setup項目下包含一“主輸出來自Projky.ForYukon(活動)”的項。到這里還不夠,選中該主輸出項,右鍵-〉“屬性”,將“Register”項設置為“vsdrpCOM”。最關鍵的是下一步,設置注冊表項。在Setup項目上,右鍵-〉“視圖”-〉“注冊表”。經過本人多次測試,依下圖的方式設置,兼容性最好。
特別說明的是,注冊項位于LocalMachine根下,里面的“Addins”下項“Projky.ForYukon.Connect”是“Projky.ForYukon.dll”中實現了“IDTExtensibility2”接口的類全名。
如果只是單獨需要SSMS 2008 或 2008R2中的一個插件的話,可依上一步的操作即可。我們的目標是讓它們同時有效,而且加載時互不干擾。
針對SSMS 2008的插件項目名稱是“Projky.ForKatmai”,SSMS 2008R2的插件項目名稱是“Projky.ForKilimanjaro”,這里我們的訣竅是采用一個插件中間項目“Projky.ForSQL08Transfer”,在Setup的項目中注冊表項里面只保留Transfer的注冊表項。然后,在Transfer項目中同時引用“ForKatmai”和“ForKilimanjaro”項目,在Transfer插件啟動過程中,根據SSMS版本,決定實例化那個一個具體的“IDTExtensibility2”實例。關鍵代碼如下:
using System;using Extensibility;using EnvDTE;using EnvDTE80;namespace Projky.ForSQL08Transfer { public class Connect : IDTExtensibility2, IDTCommandTarget { public Connect() { } public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom) { _addInInstance = (AddIn)addInInst; _applicationObject = (DTE2)_addInInstance.DTE; if (_applicationObject.Version.StartsWith("2007")) { _transfer = new Projky.ForKatmai.Connect(); } else { _transfer = new Projky.ForKilimanjaro.Connect(); } _transfer.OnConnection(application, connectMode, addInInst, ref custom); } public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom) { if (_transfer != null) { _transfer.OnDisconnection(disconnectMode, ref custom); } } public void OnAddInsUpdate(ref Array custom) { if (_transfer != null) { _transfer.OnAddInsUpdate(ref custom); } } public void OnStartupComplete(ref Array custom) { if (_transfer != null) { _transfer.OnStartupComplete(ref custom); } } public void OnBeginShutdown(ref Array custom) { if (_transfer != null) { _transfer.OnBeginShutdown(ref custom); } } public void Exec(string CmdName, vsCommandExecOption ExecuteOption, ref object VariantIn, ref object VariantOut, ref bool Handled) { var target = _transfer as IDTCommandTarget; if (target != null) { target.Exec(CmdName, ExecuteOption, ref VariantIn, ref VariantOut, ref Handled); } } public void QueryStatus(string CmdName, vsCommandStatusTextWanted NeededText, ref vsCommandStatus StatusOption, ref object CommandText) { var target = _transfer as IDTCommandTarget; if (target != null) { target.QueryStatus(CmdName, NeededText, ref StatusOption, ref CommandText); } } DTE2 _applicationObject; AddIn _addInInstance; IDTExtensibility2 _transfer = null; }}View Code
重點是根據SSMS版本號實例化一個“IDTExtensibility2”對象,再將接口中各項調用轉發到_transfer的對應實現上。
設置后效果圖:
特別說明,對于“Transfer”、“ForKatmai”、“ForKilimanjaro”項目,在Setup項目中都要添加主輸出,并在各自的主輸出項上右鍵-〉屬性,設置“Register”項為“vsdrpCOM”。SSMS 2012 和 SSMS 2014也一樣,就不強調了。
解決了第一個問題和第三個問題,只剩下第二個問題了,就是實現SSMS 2012 和SSMS 2014插件的加載。
這個方法是在“RedGate”插件上應用的,就是將向導生成的附帶Addin結尾的文件放到特定目錄。SSMS 2012放到Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"/Microsoft/SQL Server Management Studio/11.0/Addins"目錄下,SSMS 2014放到Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"/Microsoft/SQL Server Management Studio/12.0/Addins"目錄下。
然而,這不是僅僅復制這兩個文件到對應目錄就完成的事情。通常Addin文件內容如下:
<?xml version="1.0" encoding="gb2312" standalone="no"?><Extensibility xmlns="http://schemas.microsoft.com/AutomationExtensibility"> <HostApplication> <Name>Microsoft SQL Server Management Studio</Name> <Version>*</Version> </HostApplication> <Addin> <FriendlyName>ProjkyAddin</FriendlyName> <Description>ProjkyAddin for sql 2012</Description> <Assembly>C:/Program Files (x86)/ProjkyAddin/Projky.ForDenali.dll</Assembly> <FullClassName>Projky.ForDenali.Connect</FullClassName> <LoadBehavior>1</LoadBehavior> <CommandPreload>1</CommandPreload> <CommandLineSafe>0</CommandLineSafe> </Addin></Extensibility>
注意了,里面Assembly中是包含了路徑的,如果用戶在Setup包安裝過程中選擇了其它目錄,不是默認目錄,那就導致不能正常加載。
綜上,需要一個定制化的安裝過程。在.NET 里面就是實現System.Configuration.Install.Installer類(需要引用System.Configuration程序集),再在Setup項目中指定自定義動作,指向該類。
ProjkyAddin中的實現代碼如下:
using System;using System.Collections;using System.Collections.Generic;using System.ComponentModel;using System.Configuration.Install;using System.IO;using System.Text;namespace Projky.InstallHelper { [RunInstaller(true)] public partial class SetupAddinFile : System.Configuration.Install.Installer { #region Installer public SetupAddinFile() { InitializeComponent(); } protected override void OnAfterUninstall(IDictionary savedState) { RemoveDenaliAddinFile(); RemoveHekatonAddinFile(); base.OnAfterUninstall(savedState); } public override void Rollback(IDictionary savedState) { RemoveDenaliAddinFile(); RemoveHekatonAddinFile(); base.Rollback(savedState); } public override void Install(IDictionary stateSaver) { base.Install(stateSaver); SetupDenaliAddinFile(); SetupHekatonAddinFile(); CreateProjkyAddinFolder(); CreateScriptFoldersTextFile(); } #endregion void CreateScriptFoldersTextFile() { string filePath =
新聞熱點
疑難解答