c# ActiveX 控件的开发
关于ActiveX控件的开发,网上很多例子,昨天也整整研究一天才捋顺了.
网上大部分例子都是js调用控件的方法,由于要实现在html页面"相应"控件的事件,整整折腾一天.
关键点在于 "创建ActiveX控件" 的 第2,和第7
该技术局限性较大,如浏览器端需安装 .net 框架,仅限于IE浏览器.
关于ActiveX的证书及浏览器安装时设置,可参考 http://www.cnblogs.com/weixing/archive/2013/06/28/3161165.html 这也是我看到比较详细的介绍了.
创建ActiveX控件
1.创建一个类库;
2.项目属性-应用程序-程序集信息-"使程序集COM可见"勾上;
3.项目属性-生成-"为COM互操作注册"勾上.(这个折腾一天,否则注册事件不可用);
4.创建接口: IObjectSafety (注意GUID不能变);
5.创建ActiveX控件的基类并实现IObjectSafety,ActiveX控件可以继承它来减少代码;
6.创建一个ActiveX自定义控件如:ActiveXDemo1;
7.定义ActiveXDemo1的"方法接口"及"事件接口".(如使用自定义事件需用此方式), "事件接口"成员应加上[DispId(x)]标识;
8.创建ActiveX控件完成.
IObjectSafety 接口定义
1 2 3 4 5 6 7 8 9 10 11 | [ComImport, Guid( "4A359FBB-C9A4-494E-B048-AC068DB4FCB2" )] //该GUID不能变 [InterfaceType(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); } } |
ActiveX控件基类(ActiveXControlBase)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | public class ActiveXControlBase : IObjectSafety { #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 } |
自定义ActiveX控件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | [ComVisible( true )] [Guid( "684AAD87-C086-4F27-AE55-941A1AAC7212" )] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IThreadDemoEvent { [DispId(1)] //使用事件,必须加上该标识 void ShowMessage1( string str_Msg); [DispId(2)] void ShowMessage2( string str_Msg); } [ComVisible( true )] [Guid( "4D12136B-9545-423B-A110-B9405ADF8B30" )] [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IThreadDemo { string StartTimer(); string StopTimer(); } [Guid( "2B4FCB85-A3B7-43BD-B104-7380E7F3483F" ), ClassInterface(ClassInterfaceType.AutoDual), ComDefaultInterface( typeof (IThreadDemo)), ComSourceInterfaces( typeof (IThreadDemoEvent)), ComVisible( true ) ] public class ActivexThreadDemo : ActiveXControlBase, IThreadDemo { ~ActivexThreadDemo() { ShowMessage1( "释放了啊" ); } Thread _th; bool _isStop; public event ShowMessageHandle ShowMessage1; public event ShowMessageHandle ShowMessage2; void ThreadMethd() { while ( true ) { Thread.Sleep(3000); if (ShowMessage1 != null ) { ShowMessage1.Invoke(DateTime.Now.ToString()); } if (_isStop) break ; } _th.Abort(); _th = null ; } public string StartTimer() { if (_th == null ) { _isStop = false ; _th = new Thread(ThreadMethd); _th.IsBackground = false ; _th.Start(); return "开起计时" ; } if (ShowMessage2 != null ) { ShowMessage2( "执行了 StartTimer" ); } return "已经开起过计时;" ; } public string StopTimer() { if (_isStop) { return "已经停止计时了!" ; } else { _isStop = true ; return "停止计时" ; } } } |
注意:
不能使用泛型委托来声明事件,如:public event Action<T> ShowMessageHandle;
当类里面包含 static成员,刷新页面不会清空
跨线程触发事件: [事件].Invoke(参数1,参数2 ...);
ActiveX控件Setup
1.创建Installer项目;
2.右击项目 添加->项目输出 打开添加项目输出组对话框,并选择ActiveX控件类库;
3.主输出文件的属性 Register 值为 vsdrpCOM (关键),RemovePreviousVersions 设置为true
web页面测试;
1.创建一个object 标签,calassid为控件GUID
<object id="ActiveXObj1" classid="clsid:3BCF612C-91CF-4543-83BB-FD2331FDDCB6" ></object>
2.调用控件方法
var r = document.ActiveXObj1.Test1();
3."注册控件的事件"
<script language="javascript" type="text/javascript" for="ActiveXObj1" event="ShowMessage1(msg)">
alert("ActiveXObj1 :"+ msg )
</script>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | < html xmlns="http://www.w3.org/1999/xhtml"> < head > < title >ActiveX测试页面</ title > < script type="text/javascript"> function test1() { var r = document.ActiveXObj1.Test1(); window.status = r; } function StartTimer() { alert(document.ActiveThreadEvent); var r = document.ActiveThreadEvent.StartTimer(); window.status = r; } function StopTimer() { var r = document.ActiveThreadEvent.StopTimer(); window.status = r; } </ script > <!--事件的注册--> < script language="javascript" type="text/javascript" for="ActiveXObj1" event="ShowMessage1(msg)"> alert("ActiveXObj1 :"+ msg ) </ script > < script language="javascript" type="text/javascript" for="ActiveXObj1" event="ShowMessage2(msg)"> alert("ActiveXObj1:" + msg) </ script > <!--线程事件注册--> < script language="javascript" type="text/javascript" for="ActiveThreadEvent" event="ShowMessage1(msg)"> alert("ActiveThreadEvent :"+ msg ) </ script > < script language="javascript" type="text/javascript" for="ActiveThreadEvent" event="ShowMessage2(msg)"> alert("ActiveThreadEvent:" + msg) </ script > </ head > < body > < object id="ActiveXObj1" classid="clsid:3BCF612C-91CF-4543-83BB-FD2331FDDCB6" ></ object > < br /> < object id="ActiveThreadEvent" classid="clsid:2B4FCB85-A3B7-43BD-B104-7380E7F3483F" ></ object > < br /> < br /> < input type="button" value="测试4-相应事件!" onclick="test1();" />< br /> < input type="button" value="开始计时!" onclick="StartTimer();" />< br /> < input type="button" value="停止计时!" onclick="StopTimer();" />< br /> </ body > </ html > |
源码共享: 戳我
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤