首页 > 开发 > 综合 > 正文

Management Studio 插件生成安装包要点(以ProjkyAddin为例)

2024-07-21 02:49:05
字体:
来源:转载
供稿:网友
Management Studio 插件生成安装包要点(以PRojkyAddin为例)

通过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 =
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表