通过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("")) {
_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;
}
}

重点是根据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 = Path.Combine(Path.GetDirectoryName(this.GetType().Assembly.Location), "scriptfolders.txt");
if (File.Exists(filePath) == false) {
File.WriteAllText(filePath,
@"// put you script folder here,single folder single row. example as:
C:\Users\signal\Documents\ProjkyTwo", Encoding.UTF8);
}
} void CreateProjkyAddinFolder() {
string projkyFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\ProjkyAddin";
if (Directory.Exists(projkyFolder) == false) {
Directory.CreateDirectory(projkyFolder);
} for (int i = ; i < ; i++){
string filePath = Path.Combine(projkyFolder, String.Format("{0}.sql", i));
string content = String.Format("SELECT {0};", i);
if (File.Exists(filePath) == false) {
File.WriteAllText(filePath, content, Encoding.UTF8);
}
}
} void SetupDenaliAddinFile() {
string fileContent;
string denaliFilePath; fileContent = @"<?xml version=""1.0"" encoding=""{0}"" 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>{1}\Projky.ForDenali.dll</Assembly>
<FullClassName>Projky.ForDenali.Connect</FullClassName>
<LoadBehavior>1</LoadBehavior>
<CommandPreload>1</CommandPreload>
<CommandLineSafe>0</CommandLineSafe>
</Addin>
</Extensibility>"; fileContent = string.Format(fileContent, Encoding.Default.BodyName, Path.GetDirectoryName(this.GetType().Assembly.Location));
denaliFilePath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\Microsoft\SQL Server Management Studio\11.0\Addins";
Directory.CreateDirectory(denaliFilePath); using (StreamWriter sw = new StreamWriter(denaliFilePath + "\\Projky.ForDenali.AddIn", false)) {
sw.Write(fileContent);
}
} void RemoveDenaliAddinFile() {
string denaliFilePath; denaliFilePath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) +
@"\Microsoft\SQL Server Management Studio\11.0\Addins" +
"\\Projky.ForDenali.AddIn";
if (File.Exists(denaliFilePath)) {
File.Delete(denaliFilePath);
}
} void SetupHekatonAddinFile() {
string fileContent;
string hekatonFilePath; fileContent = @"<?xml version=""1.0"" encoding=""{0}"" 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 2014</Description>
<Assembly>{1}\Projky.ForHekaton.dll</Assembly>
<FullClassName>Projky.ForHekaton.Connect</FullClassName>
<LoadBehavior>1</LoadBehavior>
<CommandPreload>1</CommandPreload>
<CommandLineSafe>0</CommandLineSafe>
</Addin>
</Extensibility>"; fileContent = string.Format(fileContent, Encoding.Default.BodyName, Path.GetDirectoryName(this.GetType().Assembly.Location));
hekatonFilePath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\Microsoft\SQL Server Management Studio\12.0\Addins";
Directory.CreateDirectory(hekatonFilePath); using (StreamWriter sw = new StreamWriter(hekatonFilePath + "\\Projky.ForHekaton.AddIn", false)) {
sw.Write(fileContent);
}
} void RemoveHekatonAddinFile() {
string hekatonFilePath; hekatonFilePath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) +
@"\Microsoft\SQL Server Management Studio\12.0\Addins" +
"\\Projky.ForHekaton.AddIn";
if (File.Exists(hekatonFilePath)) {
File.Delete(hekatonFilePath);
}
}
}
}

该代码是放在“Projky.InstallHelper”项目中的。

添加自定义操作,需要在Setup项目上右键-〉“视图”-〉“自定义操作”,将里面的安装、提交、回滚、卸载,都添加上“InstallHelper”的主输出。效果如下图:

不过呢,假如将来SSMS 插件需要引用.NET 4.5程序集,VS 2010是不能用,留待以后解决。

ProjkyAddin示例代码参见http://www.cnblogs.com/ProJKY/p/ProjkyAddin.html

Management Studio 插件生成安装包要点(以ProjkyAddin为例)的更多相关文章

  1. 开源一款私藏Management Studio插件,ProjkyAddin,送给所有使用SQLServer的园友们

    ProjkyAddin 是一款Management Studio 插件,安装包才500多kb,兼容SSMS 2005.SSMS 2008.SSMS 2008 R2.SSMS 2012.SSMS 201 ...

  2. Qt5.4生成安装包过程

    所需工具: 1.  HM NIS Edit 2.  windeployqt.exe 第一个工具需要自己去网上下载,第二个工具可以在qt安装目录下找到:D:\qtopengl\5.4\mingw491_ ...

  3. VS2010生成安装包制作步骤

    VS2010生成安装包制作步骤   在VS2010中文旗舰版本中生成winForm安装包,可以复制你电脑中的开发环境,避免你忘记了一下配置然后在别的机器上运行不起来.也省去了Framwork的安装. ...

  4. VS2010生成安装包制作步骤 (转)

    阅读目录 VS2010生成安装包制作步骤 回到目录 VS2010生成安装包制作步骤   在VS2010中文旗舰版本中生成winForm安装包,可以复制你电脑中的开发环境,避免你忘记了一下配置然后在别的 ...

  5. UWP项目生成安装包远程安装在树莓派上

    原文: UWP项目生成安装包远程安装在树莓派上 哎,好纠结啊!如果这个名字写的太长,会显得太繁琐,如果写的短又好像说不清楚,我这语言表达水平实在是令人担忧啊!不过应该能够明白啥意思吧!因为对这个感兴趣 ...

  6. VISUAL STUDIO 2008 WINDOWS FORM项目发布生成安装包详解(转)

    转自:http://www.cnblogs.com/killerofyang/archive/2012/05/31/2529193.html Visual Studio 2008 Windows Fo ...

  7. VS2010生成安装包

    项目的第一个版本出来了,要做个安装包,之前没有做过,网上看看贴,写了一个,总结下,根据本项目的需要,没有写的太复杂,可能还不是很完善,仅作参考. 首先在打开 VS2010    >   文件 & ...

  8. Flink打包生成安装包缺少jar包

    官方默认打包生成的安装包的flink-release-1.7.0\flink-dist\target\flink-1.7.0-bin\flink-1.7.0\lib下缺少jar flink-dist项 ...

  9. cxfreeze打包python程序的方法说明(生成安装包,实现桌面快捷方式、删除快捷方式)

    一.cxfreeze基础 1.cxfreeze功能 python代码文件转exe方法有三种,分别是cx_freeze,py2exe,PyInstaller,这三种方式各有千秋,本人只用过py2exe和 ...

随机推荐

  1. jetbrains golang IDE

    非常好的IDE,叫goland. 支持最新的golang1.8了 下载地址: https://www.jetbrains.com/go/ 开始使用手册: https://www.jetbrains.c ...

  2. 仿制淘宝sku点击效果

    1.依赖jquery,主要利用二维数组. 2.原生手写. 代码如下: <!DOCTYPE html> <html> <head> <meta charset= ...

  3. Centos下Kubernetes+Flannel部署(新)

    一.准备工作 1) 三台centos主机 k8s master: 10.11.151.97  tc-151-97 k8s node1: 10.11.151.100  tc-151-100 k8s no ...

  4. elasticsearch(四) 之 elasticsearch常用的一些集群命令

    目录 elasticsearch常用的一些集群命令 查看集群健康状态 查看集群的节点列表 查看所有的索引 删除索引 查询索引的某个文档内容 更新文档 删除文档 自动创建索引 定时删除索引 elasti ...

  5. springcloud 熔断处理

    在springcloud微服务中,有时候一个服务挂了,我们需要友好的提示,此时我们在api网关路由上做一下过滤,进行友好的提示处理. 代码如下: import com.fasterxml.jackso ...

  6. 别被官方文档迷惑了!这篇文章帮你详解yarn公平调度

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由@edwinhzhang发表于云+社区专栏 FairScheduler是yarn常用的调度器,但是仅仅参考官方文档,有很多参数和概念文 ...

  7. 【设计模式】观察者模式 Observer Pattern

    定义:观察者模式定义了对象之间的一对多依赖.当“主题”(Object)状态改变事,所有依赖它的“观察者”(Observer)都会受到通知并自动更新.主题支持观察者订阅和退订. 观察者模式提供了一种对象 ...

  8. redis实战笔记(6)-第6章 使用 Redis构建应用程序组件

    本章主要内容   1.构建两个前缀匹配自 动补全程序 2.通过构建分布式锁来提高性能 3.通过开发计数信号量来控制并发 4.构建两个不同用途的任务队列 5.通过消息拉取系统来实现延迟消息传递 6.学习 ...

  9. Rails中实现批量删除

    在Rails生成的控制器模版中,包含的destroy只能处理单个对象,而批量删除要求能够同时处理多个对象,这需要自定义一个批量操作action.批量删除的效果图如下:

  10. Android源码博客目录

    每次都找不到,干脆每个部分都开个目录,方便找 0. 杂项 一些Android的博客,没事翻翻 1. 构建相关 linux和Android的Makefile和android.mk android 目录下 ...