C# Activex开发、打包、签名、发布 C# Activex开发、打包、签名、发布 [转]
C# Activex开发、打包、签名、发布
2013-06-22 12:01:20 浏览:3823
一、前言
最近有这样一个需求,需要在网页上面启动客户端的软件,软件之间的通信、调用,单单依靠HTML是无法实现了,因此必须借用Activex来实现。由于本人主要擅长C#,自然本文给出了用C#实现的范例,本文的预期效果是有一定Winform基础的人可都轻松读懂本文。



- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Runtime.InteropServices;
- namespace EasyActivex
- {
- [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
- [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
- public interface IObjectSafety
- {
- [PreserveSig]
- int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
- [PreserveSig()]
- int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
- }
- }




- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Drawing;
- using System.Data;
- using System.Text;
- using System.Windows.Forms;
- using System.Runtime.InteropServices;
- namespace EasyActivex
- {
- //这个Guid,网页调用的时候用到,Mark
- [Guid("685F0A47-944D-4145-BF4E-76A02A422B02")]
- //这里要实现IObjectSafety接口
- public partial class EUserControl : UserControl, IObjectSafety
- {
- public EUserControl()
- {
- InitializeComponent();
- }
- #region IObjectSafety 接口成员实现(直接拷贝即可)
- private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
- private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
- private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
- private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
- private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";
- private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
- private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
- private const int S_OK = 0;
- private const int E_FAIL = unchecked((int)0x80004005);
- private const int E_NOINTERFACE = unchecked((int)0x80004002);
- private bool _fSafeForScripting = true;
- private bool _fSafeForInitializing = true;
- public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
- {
- int Rslt = E_FAIL;
- string strGUID = riid.ToString("B");
- pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
- switch (strGUID)
- {
- case _IID_IDispatch:
- case _IID_IDispatchEx:
- Rslt = S_OK;
- pdwEnabledOptions = 0;
- if (_fSafeForScripting == true)
- pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
- break;
- case _IID_IPersistStorage:
- case _IID_IPersistStream:
- case _IID_IPersistPropertyBag:
- Rslt = S_OK;
- pdwEnabledOptions = 0;
- if (_fSafeForInitializing == true)
- pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
- break;
- default:
- Rslt = E_NOINTERFACE;
- break;
- }
- return Rslt;
- }
- public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
- {
- int Rslt = E_FAIL;
- string strGUID = riid.ToString("B");
- switch (strGUID)
- {
- case _IID_IDispatch:
- case _IID_IDispatchEx:
- if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))
- Rslt = S_OK;
- break;
- case _IID_IPersistStorage:
- case _IID_IPersistStream:
- case _IID_IPersistPropertyBag:
- if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))
- Rslt = S_OK;
- break;
- default:
- Rslt = E_NOINTERFACE;
- break;
- }
- return Rslt;
- }
- #endregion
- /// <summary>
- /// 打开记事本
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void btnOpenNote_Click(object sender, EventArgs e)
- {
- System.Diagnostics.Process.Start("notepad.exe");
- }
- }
- }

小提示:EUserControl代码的Guid可以用VS附带的Guid生成工具生成:

- //用户添加
- [assembly: AllowPartiallyTrustedCallers()]





- [version]
- signature="$CHICAGO$"
- AdvancedINF=2.0
- [Setup Hooks]
- hook1=hook1
- [hook1]
- run=msiexec.exe /i "%EXTRACT_DIR%\EasySetup.msi" /qn

2) build.bat制作。新建txt文件,加入以下内容,将文件名重新命名build.bat即可。其中EasyActivex.cab是生成目标cab的名称;install.inf是第一步生成的文件名,而EasySetup.msi是需要打包的安装程序名;第二条ping命令仅仅是让批处理不要那么快退出,起到更利于观察生成结果的作用。
- "cabarc.exe" -s 6144 n EasyActivex.cab install.inf EasySetup.msi
- ping -n 20 127.0.0.1 >nul




- <object id="csharpActiveX" codebase="Activex/EasyActivex.cab" classid="clsid:685F0A47-944D-4145-BF4E-76A02A422B02"></object>
运行效果如下:
点击即可在网页中打开记事本了。
前言
ActiveX控件以前也叫做OLE控件,它是微软IE支持的一种软件组件或对象,可以将其插入到Web页面中,实现在浏览器端执行动态程序功能,以增强浏览器端的动态处理能力。通常ActiveX控件都是用C++或VB语言开发,本文介绍另一种方式,在.NET Framework平台上,使用C#语言开发ActiveX控件。
虽然本文通篇都在讲如何使用C#语言开发ActiveX控件,但我并不极力推荐使用这种技术,因为该技术存在明显的局限,即需要浏览器端安装.NET Framework(版本取决于开发ActiveX控件使用的.NET Framework版本),该局限对于挑剔的互联网用户,几乎是不可接受的。所以,我建议以下几条均满足时,方可考虑使用该技术:
- 开发团队中没有人掌握使用C++/VB开发ActiveX控件技术;
- 该ActiveX控件不用于互联网;
- 用户对仅能使用IE浏览器访问表示可以接受;
- 用户对在浏览器端安装.NET Framework组件表示可以接受。
另外,我建议如果不是因为控件的依赖库基于更高版本的.NET Framework,或需要更高版本的.NET Framework提供的扩展功能(如需要WCF等),尽量在.NET Framework 2.0上开发ActiveX控件,因为.NET Framework 2.0只有20M,相比300M的.NET Framework 3.5和40M的.NET Framework 4.0都要小很多,对客户端操作系统的要求也要低很多,并且随着Windows版本的不断升级换代,Windows Vista以后的版本已经内置了.NET Framework 2.0。等到Windows XP系统寿终正寝之时,也将迎来该技术的春天。所以,别被我上面的建议夯退了,掌握该技术其实还是蛮有实用价值的,毕竟,C#高效的开发效率很有吸引力。
本文接下来将使用C#语言开发一个ActiveX控件,实现对浏览器端的MAC地址遍历功能;另外,提供一个在Web静态页面中调用该控件的测试实例。本实例的开发环境为Visual Studio 2010旗舰版(SP1),目标框架为.NET Framework 2.0;浏览器端测试环境为Windows 7旗舰版,IE8。
控件开发
使用C#进行ActiveX控件开发过程其实很简单。首先,在解决方案中添加一个类库项目,目标框架使用.NET Framework 2.0,如图1所示:
图1创建ActiveX控件类库
此处有一个关键操作,需要设置类库项目属性->程序集信息->使程序集COM可见,如图2所示:
图2设置ActiveX控件类库程序集COM可见
ActiveX类库的内容大致包括两部分,IObjectSafety接口和实现该接口的控件类。考虑所有控件类都要实现IObjectSafety接口,可以将该接口的实现抽象为一个控件基类。
一、IObjectSafety接口
为了让ActiveX控件获得客户端的信任,控件类还需要实现一个名为“IObjectSafety”的接口。先创建该接口(注意,不能修改该接口的GUID值),接口内容如下:

- 1 [ComImport, Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
- 2 [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- 3 public interface IObjectSafety
- 4 {
- 5 [PreserveSig]
- 6 int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
- 7
- 8 [PreserveSig()]
- 9 int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
- 10 }

二、ActiveXControl控件基类

- 1 public abstract class ActiveXControl : IObjectSafety
- 2 {
- 3 #region IObjectSafety 成员
- 4
- 5 private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
- 6 private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
- 7 private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
- 8 private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
- 9 private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";
- 10
- 11 private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
- 12 private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
- 13 private const int S_OK = 0;
- 14 private const int E_FAIL = unchecked((int)0x80004005);
- 15 private const int E_NOINTERFACE = unchecked((int)0x80004002);
- 16
- 17 private bool _fSafeForScripting = true;
- 18 private bool _fSafeForInitializing = true;
- 19
- 20
- 21 public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
- 22 {
- 23 int Rslt = E_FAIL;
- 24
- 25 string strGUID = riid.ToString("B");
- 26 pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
- 27 switch (strGUID)
- 28 {
- 29 case _IID_IDispatch:
- 30 case _IID_IDispatchEx:
- 31 Rslt = S_OK;
- 32 pdwEnabledOptions = 0;
- 33 if (_fSafeForScripting == true)
- 34 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
- 35 break;
- 36 case _IID_IPersistStorage:
- 37 case _IID_IPersistStream:
- 38 case _IID_IPersistPropertyBag:
- 39 Rslt = S_OK;
- 40 pdwEnabledOptions = 0;
- 41 if (_fSafeForInitializing == true)
- 42 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
- 43 break;
- 44 default:
- 45 Rslt = E_NOINTERFACE;
- 46 break;
- 47 }
- 48
- 49 return Rslt;
- 50 }
- 51
- 52 public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
- 53 {
- 54 int Rslt = E_FAIL;
- 55
- 56 string strGUID = riid.ToString("B");
- 57 switch (strGUID)
- 58 {
- 59 case _IID_IDispatch:
- 60 case _IID_IDispatchEx:
- 61 if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) &&
- 62 (_fSafeForScripting == true))
- 63 Rslt = S_OK;
- 64 break;
- 65 case _IID_IPersistStorage:
- 66 case _IID_IPersistStream:
- 67 case _IID_IPersistPropertyBag:
- 68 if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) &&
- 69 (_fSafeForInitializing == true))
- 70 Rslt = S_OK;
- 71 break;
- 72 default:
- 73 Rslt = E_NOINTERFACE;
- 74 break;
- 75 }
- 76
- 77 return Rslt;
- 78 }
- 79
- 80 #endregion
- 81 }

三、MacActiveX控件类

- 1 [Guid("65D8E97F-D3E2-462A-B389-241D7C38C518")]
- 2 public class MacActiveX : ActiveXControl
- 3 {
- 4 public string GetMacAddress()
- 5 {
- 6 var mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
- 7 var mos = mc.GetInstances();
- 8 var sb = new StringBuilder();
- 9
- 10 foreach (ManagementObject mo in mos)
- 11 {
- 12 var macAddress = mo["MacAddress"];
- 13
- 14 if (macAddress != null)
- 15 sb.AppendLine(macAddress.ToString());
- 16 }
- 17
- 18 return sb.ToString();
- 19 }
- 20 }

注意,第一行指定的Guid值即为该ActiveX控件的唯一标识,请保证其唯一性。Guid的生成有多种方法,你可以在系统目录的Program Files目录搜索一个名为guidgen.exe的工具,用该工具产生;也可以写一段测试代码,调用Guid.NewGuid()方法产生;有的Visual Studio版本也提供了快捷方式,在“工具->生成GUID”菜单下。另外,访问MAC需要添加对System.Management系统组件的引用。
到此,控件类库的开发工作就做完了,整个实现过程确实很简单。
发布
C#开发的ActiveX控件类库不像OCX那样可以直接通过regsvr32.exe注册(实际上,微软提供了替工具regasm.exe,但由于这种方式要不能实现自动升级,所以本文就不介绍了),要使控件类库运行于浏览器端,可以采取两种方式,一种是将控件类库打包为MSI安装包,然后直接在浏览器端安装;另一种是将MSI再封装为一个CAB包,这个CAB包就是一个ActiveX控件了,可以将它随应用程序一并发布,浏览器端访问包含有该控件的页面时,就会自动提示安装了。接下来就后一种发布方式进行详细讲解。
一、安装项目
在解决方案中添加一个安装项目,如图3所示:
图3添加安装项目
右键点击新添加的安装项目,依次选择“添加->项目输出”菜单,打开添加项目输出组对话框,并选择ActiveX控件类库“CSharpActiveX”作为主输出,如图4所示:
图4添加项目输出
双击安装项目检测到的依赖项“Microsoft .NET Framework”,打开安装项目的启动条件界面,选中“.NET Framework”项,如图5所示:
图5安装项目启动条件
按F4快捷键,打开属性窗口,设置.NET Framework项的Version为“.NET Framework 2.0”,如图6所示:
图6设置安装项目的依赖框架
下面这步很关键,选中“主输出来自CSharpActiveX(活动)”项,如图7所示:
图7主输出内容项
设置主输出项内容的Register属性值为vsdrpCOM,如图8所示:
图8设置主输出项属性
二、制作CAB包
Visual Studio 2010提供了CAB项目模板,但非常遗憾,无论我怎么设置,其生成的CAB安装包都不能在终端成功安装,最终只能放弃,转而选择了makecab.exe工具。源码提供了该打包工具,位于CAB目录下,共包含makecab.exe、cab.ddf、installer.inf和makecab.bat四个文件,其中cab.ddf和installer.inf文件需要简单说明下。
cab.ddf文件定义了CAB文件的打包行为,内容包括打包参数,打包内容项以及输出文件等。需要指出的是,使用C#开发的ActiveX控件CAB包中需要包含MSI文件和installer.inf安装文件两部分。cab.ddf文件内容如下:

- .OPTION EXPLICIT
- .Set Cabinet=on
- .Set Compress=on
- .Set MaxDiskSize=CDROM
- .Set ReservePerCabinetSize=6144
- .Set DiskDirectoryTemplate="."
- .Set CompressionType=MSZIP
- .Set CompressionLevel=7
- .Set CompressionMemory=21
- .Set CabinetNameTemplate="CSharpActiveX.CAB"
- "installer.inf"
- "CSharpActiveX.msi"

installer.inf文件定义了CAB文件的安装行为,作为控件的一部分打入CAB包中,其内容如下:

- [Setup Hooks]
- hook1=hook1
- [hook1]
- run=msiexec /i %EXTRACT_DIR%\CSharpActiveX.msi /qn
- [Version]
- Signature= "$CHICAGO$"
- AdvancedInf=2.0

makecab.bat文件是调用makecab.exe进行打包的批处理文件,内容如下:
- makecab.exe /f "cab.ddf"
当生成安装项目后,将CSharpActiveX.msi文件拷贝到CAB目录下,就可以双击makecab.exe文件进行打包了,执行完成后会输出CSharpActiveX.CAB文件,这就是所谓的ActiveX控件了。
三、签名
IE采用了AuthentiCode代码签名技术,对浏览器端安装ActiveX控件行为进行了控制。上面生成的ActiveX控件如果想在浏览器端成功安装,需要对浏览器进行设置,具体操作参见部署章节。
让所有用户都对IE进行设置,显得不太友好,为此,我们可以考虑使用AuthentiCode技术对ActiveX控件进行签名。Visual Studio 2010附带的signtool.exe(以前版本的VS提供的是另一个工具signcode.exe)代码签名工具可以完成该工作(注意,并非一定要用微软提供的工具进行签名,只要按照AuthentiCode技术标准,使用 PKCS#7标准定义的数据结构生成待签名文件的数字签名,并加入到待签名文件的PE结构中即可)。但需要先准备一个PKCS#12(证书及私钥)文件(.pfx),注意,该证书的增强型密钥用法须包含代码签名这项,如图9所示:
图9代码签名证书
本文源码提供了一份测试PKCS#12文件Apollo.pfx,PIN码为11111111。在Visual Studio命令提示(2010)中,进入源码的CAB目录,输入如下命令即可对ActiveX控件进行签名操作了:
- signtool sign –f Apollo.pfx –p 11111111 CSharpActiveX.CAB
图10对比了签名前后的ActiveX控件文件属性,可以看出,签名后的ActiveX控件属性中已经多了一项数字签名,表示该文件已经过签名。
图10签名前后的ActiveX控件属性对比
出于方便考虑,本文源码的CAB目录下提供了一份signtool.exe工具的拷贝,这样就可以将签名命令加入makecab.bat文件中,修改后的makecab.bat我将其命名为makecabsigned.bat,内容如下:
- makecab.exe /f "cab.ddf"
- signtool sign -f Apollo.pfx -p 11111111 CSharpActiveX.CAB
应用
ActiveX控件用于HTML静态页面,执行于IE浏览器端。需要以<object>标签的形式引入页面文件,然后使用Javascript语言调用它。测试代码如下:

- 1 <html>
- 2 <head>
- 3 <title>CSharpActiveX测试</title>
- 4 </head>
- 5 <body>
- 6 <object id="cSharpActiveX" classid="clsid:65D8E97F-D3E2-462A-B389-241D7C38C518" codebase="CSharpActiveX.CAB#version=1,0,0" ></object>
- 7 <script type="text/javascript" language="javascript" defer="defer">
- 8 var activeX = document.getElementById("cSharpActiveX");
- 9 alert(activeX.GetMacAddress());
- 10 </script>
- 11 </body>
- 12 </html>

注意,<object>标签的classid属性值即为MacActiveX类的Guid特性值。
部署
ActiveX控件在IE浏览器端的部署会因ActiveX控件是否签名而有所区别。下面就以此分类进行说明。当然,首先需要将test.htm和CSharpActiveX.CAB文件部署到服务器上,假设部署后的访问地址为http://192.168.1.1/test.htm。
一、部署未签名的ActiveX控件
未签名的ActiveX控件不受浏览器端信任,默认是不被允许安装的。需要先将站点添加为可信站点,具体步骤为:依次打开IE“工具->Internet选项”,在“安全”选项卡中,选中“可信站点”,如图11所示:
图11 Internet安全选项
点击“站点”按钮,打开可信站点管理对话框,将服务器站点添加到可信站点列表中,如图12所示:
图12可信站点对话框
回到“Internet选项”对话框,点击“自定义级别”选项卡,打开可信站点的安全设置对话框,如图13所示:
图13可信站点安全设置对话框
确认“对未标记为可安全执行脚本的ActiveX控件初始化并执行脚本”项设置为“启用”,“下载未签名的ActiveX控件”项设置为“提示”。
IE设置完成后,访问http://192.168.1.1/test.htm测试页面(注意,Windows 7需要“以管理员身份运行”IE方可成功安装ActiveX控件),IE便会提示加载ActiveX控件,如图14所示:
图14首次访问提示加载ActiveX控件
点击“为此计算机上的所有用户安装此加载项”,IE将弹出安全警告,确认是否要安装该ActiveX控件,如图15所示:
图15 ActiveX控件安装安全警告
点击“安装”按钮,确认安装该ActiveX控件,待IE状态栏进度条完成,说明控件已安装完成,可以通过查看“卸载或更改程序”项来确认是否安装成功,如图16所示:
图16确认ActiveX控件成功安装
我们可以从ActiveX控件安装过程看出,浏览器端其实是以静默安装的方式完成对CAB包中的MSI安装文件的安装(有点拗口J)。安装完成后,页面成功调用ActiveX控件,弹出接口调用结果(注意Windows 7需要重启IE,且不能用“以管理员身份运行”方式启动,否则会再次提示安装ActiveX控件,但其实控件已经成功安装了,这个问题很奇怪),效果如图17所示:
图17成功调用ActiveX控件接口
二、部署已签名的ActiveX控件
因为IE默认允许安装并运行收信任的已签名ActiveX控件,所以通过对ActiveX控件签名,可以有效简化浏览器端的配置工作。你仅需要安装签名所用的证书及其证书链文件(本文源码提供的签名文件所含证书是自签名证书,所以它的证书链就只是它自己)。打开源码CAB目录下的Apollo.cer(与Apollo.pfx文件对应的数字证书文件)代码签名证书文件,如图18所示:
图18签名证书文件
点击“安装证书”按钮,将该证书安装到“受信任的根证书颁发机构”,如图19所示:
图19安装代码签名证书
打开IE的“工具->Internet选项”对话框,选择“内容”选项卡,点击“证书”按钮,打开IE证书对话框,确认在“受信任的根证书颁发机构”选项卡中包含刚才导入的代码签名证书,如图20所示:
图20成功导入代码签名证书
此时,再访问测试页面http://192.168.1.1/test.htm,IE就会提示安装ActiveX控件了,而不再需要将站点添加到可信站点并设置IE选项了。
但是,如果用户不能接受初次安装需要导入代码签名证书及其证书链的方式,怎么办呢?从图20可以看到,Windows其实默认内置了一些权威的CA机构证书,可以向这些机构申请一份代码签名证书及私钥文件来对ActiveX控件签名,这样就可以避免该问题了。但是,向权威的CA机构申请证书是需要付费的,所以需要权衡成本和易用性后,再做出选择。
升级
要使C#编写的ActiveX控件支持自动升级,需要做四件事情,即升级ActiveX控件库版本、升级安装项目版本、设置安装项目注册表项版本和升级网页<object>版本。
一、升级ActiveX控件版本
打开ActiveX控件项目的“程序集信息”对话框,升级程序集版本和文件版本,如图21所示:
图21升级ActiveX控件版本
二、升级安装项目版本
选中安装项目,按F4快捷键打开安装项目的属性窗口,升级安装项目的版本,如图22所示:
图22升级安装项目版本
注意,此处还有一项关键工作要做,就是设置RemovePreviousVersions属性值为True,这样就会在升级时先自动卸载之前版本的控件。
三、设置安装项目注册表项版本
浏览器端检测ActiveX控件是否需要升级,是通过比对<object>标签的codebase属性值和本地HKEY_CLASSES_ROOT/CLSID/{GUID}/InstalledVersion键值是否相等来判断的。所以,如果要实现自动更新,需要手动添加该注册表项,并在每次升级控件时,相应更改该项键值。
右键点击安装项目,依次选择“视图->注册表”菜单,打开安装项目的注册表编辑界面,并在HKEY_CLASSES_ROOT节点下,建立CLSID/{GUID}/InstalledVersion注册表键路径,如图23所示:
图23创建注册表键路径
右键点击InstalledVersion键节点,选择“新建->字符串值”菜单,新建一个名称为空(空名称会显示为“(默认值)”),值为当前控件版本号的键值,如图24所示:
图24添加InstalledVersion默认键值
该步骤有几个地方需要特别说明。首先,{GUID}指的是ActiveX控件类的GUID,对应本文MacActiveX类指定的GUID,且该项需要包括左右花括号;其次,如果该安装项目用于发布多个ActiveX控件(类),需要创建多个{GUID}/InstalledVersion路径;最后,InstalledVersion的默认键值的主次版本号间是用“,”分隔,而不是“.”,后续升级时,需要同步升级该键值版本号。
四、升级网页<object>版本
最后,需要升级网页中的ActiveX对象引用版本号,如下用下划线标识部分:
- <object id="csharpActiveX" classid="clsid:65D8E97F-D3E2-462A-B389-241D7C38C518" codebase="CSharpActiveX.CAB#version=1,0,1" ></object>
重新生成安装程序,打CAB包,将升级的页面及ActiveX控件(CAB包)更新到服务器。此时,浏览器端重新访问时,就会提示/自动升级ActiveX控件了。
C# Activex开发、打包、签名、发布 C# Activex开发、打包、签名、发布 [转]的更多相关文章
- 发布MFC ActiveX控件并实现自动更新
一. 引言 上一篇我们讲了如何使用 VC 2005来开发 MFC ActiveX控件,我们开发 ActiveX控件最终目的是将 ActiveX控件发布出来并嵌入在 Web网页中,随着控件 ...
- C#-Xamarin的Android项目开发(三)——发布、部署、打包
前言 部署,通常的情况下,它其实也是项目开发的一个难点. 为什么这么说呢?因为,它不是代码开发,所以很多开发者本能的拒绝学习它. 并且一个项目配置好一次以后,部署的步骤和部署的人通常很固定,所以大部分 ...
- 基于MFC的ActiveX控件开发教程------------浏览器插件之ActiveX开发
浏览器插件之ActiveX开发(一) 一般的Web应用对于浏览器插件能不使用的建议尽量不使用,因为其涉及到安全问题以及影响用户安装(或自动下载注册安装)体验问题.在有特殊需求(如涉及数据安全的金融业务 ...
- 开发ActiveX控件调用另一个ActiveX系列0——身份证识别仪驱动的问题
程序员要从0下表开始,这篇是介绍这个系列的背景的,没有兴趣的人可以直接跳过. 为什么要开发ActiveX控件 由于工作需要,我们开发了一个网站,使用了一款身份证识别仪的网页ActiveX(OCX)插件 ...
- 开发ActiveX控件调用另一个ActiveX系列1——开发一个MFC ActiveX控件
ActiveX开发的教程有很多,我也从中受益匪浅,例如以下这几篇: 基本教程:http://www.cnblogs.com/guenli/articles/1629915.html 注意事项:http ...
- [Swift实际操作]九、完整实例-(3)创建和安装开发证书、发布证书及开发证书配置文件、发布证书配置文件
本文将为你演示,如何创建开发证书和发布证书,以及其他辅助内容.首先打开浏览器,进入[苹果开发者网站]输入[Apple ID]和[密码],点击登录按钮,进入开发者管理后台. 点击左侧的[Membersh ...
- [转]安卓新一代多渠道打包工具Walle 解决渠道包V2签名问题
转自https://www.jianshu.com/p/572b59829a08 为什么要打多个渠道的包? 大家都知道,android应用商店大大小小有几百个,作为一个有志向的app,就需要做到统计各 ...
- 如何通过webpack和node来实现多个静态页面html,多个入口,能打包能热加载开发环境调试
demo已经传到了github,地址:https://github.com/13476075014/04.node-vue-project/tree/master/03.singlewebpack: ...
- GJM : Taurus.MVC 2.0 开源发布:WebAPI开发教程 [转载]
Taurus.MVC 2.0 开源发布:WebAPI开发教程 转载自http://www.cnblogs.com/cyq1162/p/6069020.html 因是新手 粘贴时有一个版权问题 本文原 ...
随机推荐
- checkboxes(复选按钮)
复选按钮是input的输入框的另一种类型. 每一个复选按钮都应该嵌套进label元素中. 所有关联的复选按钮应该具有相同的name属性. 下面是复选按钮的例子: <label><in ...
- I Hate It(hdu1754)(线段树区间最大值)
I Hate It hdu1754 Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- [C++]项目中的代码注释规范(整理)
原文:http://blog.csdn.net/pleasecallmewhy/article/details/8658795 1 源文件头部注释 列出:版权.作者.编写日期和描述. 每行不要超过80 ...
- [原] XAF 如何非常容易禁止清除一个下拉字段的值?
- linux增加根分区大小
以下操作以root身份运行 1.增加一个新分区(从原有硬盘分,或增加一个新硬盘并进行分区fdisk) 格式化成ext4(mkfs.ext4 /dev/sdb1,假设为/dev/sdb1) 2.将新的 ...
- 无线安全专题01--kali破解WPA
最近一直用flask写自己的博客框架,等过段时间才能将其分享出来,所以在此期间决定开个无线安全的专题,分享一些无线安全方面的知识. 好了,废话不多说,咱们进入今天的主题,使用kali linux上的无 ...
- SQL中的取整函数FLOOR、ROUND、CEIL、TRUNC、SIGN
1 trunc(value,precision)按精度(precision)截取某个数字,不进行舍入操作.2 round(value,precision)根据给定的精度(precision)输入数值. ...
- JS模块间错误隔离
问题背景: 页面中有多个功能模块,怎么在一个模块出了问题之后,保证其它模块的正常工作. 上面的差不多就是面试官的原话了,姑且称之为模块间错误隔离问题 第一反应是动态按需加载代码,用户操作发生后再加载对 ...
- 解决“在多字节的目标代码页中,没有此Unicode字符可以映射到的字符”
今天在处理Google网站管理员中的500错误时发现这样一些URL: http://www.cnblogs.com/Garnai/tag/3D%3F%96%CA/ http://www.cnblogs ...
- Local Optimization Revisited
十年前刚入行的时候,做为一名被agile刚洗脑的新兵,觉得自己仿佛掌握了什么神兵秘器.你看,你们这里那里都是在做local optimization,你看你不懂什么叫value driven吧,你做这 ...