整理:C#写ActiveX, 从代码到打包到签名到发布的示例
对于不懂C++和VB的我, 在工作上却遇到需要重写旧ActiveX控件的任务.
好在客户机都是Windows PC, 基本上都有.net framework 2.0, 勉强用C#实现可以满足需求
所以我参考了不少前辈在网上分享的示例,
在.net framework 2.0的基础上用C#实现ActiveX小控件.
一波三折, 好不容易测试成功, 所以在此做一次简单的操作整理.
1. 准备一个的ActiveX控件, 这里的示例仅实现最简单的功能, 只包含IE与ActiveX之间的传值功能.
新建一个窗体控件库:
修改工程的属性
注意一下的"生成"中的选择框, 此处根据是Debug和Release分开的, 切换模式时, 请检查此项是否已经勾上:
修改AssemblyInfo, 添加以下代码:
删除默认的UserControl1, 自己新建一个UserControl:
新建一个接口:
代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices; namespace ActiveXDemo
{
[ComImport, GuidAttribute("B5030596-63D6-4B21-9D01-90698B1FC277")]
[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
);
}
}
让我们刚刚新建的UserControl实现上面的接口, GUID处请使用VS自带的Tools->Create GUID新建GUID:
实现接口代码如下:
#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 = ;
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 = ;
if (_fSafeForScripting == true)
pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
break;
case _IID_IPersistStorage:
case _IID_IPersistStream:
case _IID_IPersistPropertyBag:
Rslt = S_OK; pdwEnabledOptions = ;
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
为了可以与前台的js进行交换, 添加以下dll引用和命名空间:
添加一个方法, 用于调用前台js, 参数win为前台传入的window对象, func为前台js方法的名字, para为参数:
代码如下:
public void SetFunc(object win, string func, string para)
{
IHTMLWindow2 htmlWin = win as IHTMLWindow2;
if (htmlWin == null || string.IsNullOrEmpty(func))
{
MessageBox.Show("Assign error.");
}
else
{
string jsCode = string.Format("{0}('{1}')", func, para);
htmlWin.execScript(jsCode, "jscript");
}
}
再添加一个方法, 用于接收前台传入的信息, 然后后台调用前台的方法显示该信息(没错, 这个功能是多此一举的, 仅为了展示前后台之间的传值)
public void ShowMessage(object win, string msg)
{
SetFunc(win, "show", msg);
}
2. 打包步骤1生成的dll, 使之成为msi安装文件
ActiveX控件部分已经完成了, 现在要把控件Build出来的dll打包成msi
新建setup工程:
添加步骤1的工程为输出:
检查属性:
Rebuild步骤1工程, 然后Rebuild步骤2工程, 在工程目录下取出安装包(例子是Release中的msi):
把这个msi放在新建一个空的文件夹, 方便进一步打包:
3. 进一步打包客户端下载后可以自动安装的Cab包
在上面的文件夹中放入以下文件:
cabarc.exe是打包cab的工具, signcode.exe为数字签名工具
build.bat文件控制cabarc打包操作, install.inf是IE安装cab的配置
build.bat文件内容如下:
第一个文件为需要生成的cab, 后面的为cab包含的文件:
@echo off
"cabarc.exe" -s 6144 n ActiveXDemo.cab install.inf ActiveXSetup.msi
pause
install.inf文件内容如下:
在此不具体解释, 可以参考文后的参考文章
[version]
signature="$CHICAGO$"
AdvancedINF=2.0 [Strings]
Version="1.0.0.0" [Setup Hooks]
InstallerHook=InstallerHook [InstallerHook]
run=msiexec.exe /i "%EXTRACT_DIR%\ActiveXSetup.msi" /qn
双击build.bat文件, 打包cab完成:
4. 部署在一个简单网页上
准备一个简单网站(静态html也行, 不过要配搭配IIS上运行):
如图放入cab文件:
写入如下html和js脚本:
注意object标签中的clsid, 它对应前面步骤1生成的GUID
codebase, 意为: ActiveX目录下的ActiveXDemo.cab文件, 版本是1,0,0,0, 与install.inf和程序集中版本对应
IE会根据这个版本号, 决定是否下载或更新cab包
sendMsg获得ActiveX对象, 发送window对象和参数给ActiveX控件,
ActiveX控件接收到后, 根据我们定义的逻辑, ActiveX将调用前台js方法show, 回显msg参数的值
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<object id="objActiveX" classid="clsid:1D1999CC-0221-4A81-A0C5-F5ABA2059249" codebase="ActiveX/ActiveXDemo.cab#version=1,0,0,0">
</object>
<input id="msg" type="text" />
<input type="button" onclick="sendMsg()" value="提交" />
</div>
</form>
<script type="text/javascript">
function sendMsg() {
var objActiveX = document.getElementById("objActiveX");
var msg = document.getElementById('msg').value;
objActiveX.ShowMessage(window, msg);
}
function show(msg) {
alert(msg);
}
</script>
</body>
</html>
5. 使用测试
测试成功
要注意的是, 要下载并运行未签名的控件, 请在Interest选项中
添加信任域名, 启用与ActiveX相关设置
6. 数字签名(这里我们使用自己建立的数字证书)
使用VS自带的命令行, 创建Demo证书:
输入如下命令, 工具会让你输入3次相同的密码:
makecert -ss name -n "CN=DemoName" -sv d:\certDemo.pvk d:\certDemo.cer
接着输入以下命令:
cert2spc d:\certDemo.cer d:\certDemo.spc
这样就一共生成了3个文件:
放到有signcode.exe的文件夹, 双击工具, 下一步, 选择需要签名的cab包:
下一步, 选自定义:
选择刚刚生成的certDemo.spc
选择私钥文件certDemo.pvk
然后一路到底, 弹出需要你输入密码, 就输入证书的密码, 最后就完成签名了.
检查是否签名, 右键cab, 查看属性, 会多出一项:
有了证书, 客户机就可以安装证书, 双击certDemo.cer:
证书安装完成, 接着可以像步骤5一样测试.
注意: 由于证书不是官方购买的, IE认为还是不安全的, 可能会遇到IE拒绝安装的情况.
本人认为上线使用最好还是官方证书, 安全, 不需要手动安装.cer文件.
示例代码和用到的工具: http://yunpan.cn/Q7XhfsMINV5RL (提取码:2bd7)
参考文献:
http://www.cnblogs.com/still-windows7/p/3148623.html
http://blog.csdn.net/tomatozq/article/details/7656729
http://blog.csdn.net/cds27/article/details/7533479
http://www.cnblogs.com/yilin/archive/2009/09/15/1567332.html
http://www.cnblogs.com/catvi/archive/2007/08/15/1952976.html
整理:C#写ActiveX, 从代码到打包到签名到发布的示例的更多相关文章
- C# Activex开发、打包、签名、发布 C# Activex开发、打包、签名、发布 [转]
C# Activex开发.打包.签名.发布 2013-06-22 12:01:20 浏览:3823 一.前言 最近有这样一个需求,需要在网页上面启动客户端的软件,软件之间的通信.调用,单单依靠HTML ...
- C# Activex开发、打包、签名、发布
一.前言 最近有这样一个需求,需要在网页上面启动客户端的软件,软件之间的通信.调用,单单依靠HTML是无法实现了,因此必须借用Activex来实现.由于本人主要擅长C#,自然本文给出了用C# ...
- C#制作、打包、签名、发布Activex全过程
一.前言 最近有这样一个需求,需要在网页上面启动客户端的软件,软件之间的通信.调用,单单依靠HTML是无法实现了,因此必须借用Activex来实现.由于本人主要擅长C#,自然本文给出了用C#实现的范例 ...
- C# winFrom 制作、打包、签名、发布Activex全过程
注:转自园中 http://www.cnblogs.com/still-windows7/p/3148623.html 一.前言 最近有这样一个需求,需要在网页上面启动客户端的软件,软件之间的通信.调 ...
- C#制作、打包、签名、发布Activex全过程【转】
http://www.cnblogs.com/still-windows7/p/3148623.html 一.前言 最近有这样一个需求,需要在网页上面启动客户端的软件,软件之间的通信.调用,单单依靠H ...
- Java工具创建密钥库,用于Unity 3D打包、签名、发布
Java工具创建密钥库 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享.心创新! ...
- weex 项目开发 weexpack 项目 打包、签名、发布
一. weexpack build android 和 weexpack run android 的 区别. (1)单纯打包 weexpack build android (2)打包并运行 wee ...
- weex 项目开发(六)weexpack 项目 打包、签名、发布
一. weexpack build android 和 weexpack run android 的 区别. (1)单纯打包 weexpack build android (2)打包并运行 wee ...
- 将自己写的Python代码打包放到PyPI上
如果是开源的Python代码,为了能够让大家更方便的使用,放到PyPI上也许是个非常不错的主意(PyPI:Python Package Index).刚开始我以为要将代码打包放到PyPI上是一件非常复 ...
随机推荐
- 带左右箭头切换的自动滚动图片JS特效
效果图 按钮 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...
- 电机KV值对应的桨
KV2200 -6寸 KV1400 -8寸 KV1000 -10寸
- Sicily 1133. SPAM
题目地址:1133. SPAM 思路: 题目意思是说在‘@’的前后出现题目给定的合法字符或者不连续出现‘.’字符的话,这个就是合理的输出. 那么以@为中心,向前,向后扫描,当扫描到不符合字符时,记录此 ...
- 转:内核空间与用户空间数据交换的方式之一 --ioctl(通过字符设备演示)
对于linux而言,内核程序和用户程序分别运行在内核空间和用户空间,要实现两者的数据交换,主要有以下几种方式:系统调用,读写系统文件(procfs,sysfs, seq_file,debugfs等), ...
- 转:fopen与open可以转换吗
绝对不可以.fopen是C运行库级别的函数,而open是system call的wrapper routine.fopen返回FILE *的指针,这个结构本身维护着一些关于这个文件的信息,而open返 ...
- SSL 证书申请(居然还可以在淘宝上购买)
免费的目前有 2 个国内的:免费SSL证书申请国外的:StartSSL™ Certificates & Public Key Infrastructure 备注:其实,国内的这家的根证书,也是 ...
- 【转】android ddms中查看线程释疑
原文网址:http://www.mobiletrain.org/lecture/doc/android/2011-05/457.html 大家都用过ddm,如果你用ddms查看一个程序的所有线程,你会 ...
- 扒一扒ReentrantLock以及AQS实现原理
提到JAVA加锁,我们通常会想到synchronized关键字或者是Java Concurrent Util(后面简称JCU)包下面的Lock,今天就来扒一扒Lock是如何实现的,比如我们可以先提出一 ...
- bootstrap完整导航栏
效果图: 代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- 2016-05-I
2016 年上半年软件设计师上午真题 1. VLIW 是( )的简称.A.复杂指令系统计算机 B.超大规模集成电路C.单指令流多数据流 D.超长指令字 2.主存与 Cache 的地址映射方式中,( ) ...