用C#编写ActiveX控件的基础练习--经过测试的完整代码

前言

  activex控件以前也叫做ole控件或ocx控件,它是一些软件组件或对象,可以将其插入到web网页或其它应用程序中。使用activex插件,可以轻松方便的在 web页中插入多媒体效果、交互式对象以及复杂程序等等。

  通常使用c++或vb开发activex控件,本文探讨一下在visual studio 2005环境中使用c#开发activex控件的技术实现。

1. 问题场景

  在c/s架构的系统中,客户端要实现某些业务功能,可以通过安装相关的应用程序集来方便的实现。同样的需求,在b/s架构的系统里实现起来却比较困难。因为所有的程序都放在服务器端,客户端只是采用浏览器,通过http协议来访问服务器端。比较成熟的解决办法是开发activex控件安装到客户端,这样客户端的浏览器就可以访问本地的activex控件来执行相关的本地操作。本文将要谈论的,就是使用c#开发一个activex控件实现读取并显示客户端的系统时间。

2. 开发环境

  windows xp

  visual studio 2005

  .net framework 2.0(c#)

3. 实现过程

3.1.activex控件开发

  在visual studio 2005开发环境中,可以使用windows控件库项目实现activex控件的开发,但是需要对项目做一些必要的设置。下面就来看看如何使用 windows控件库项目开发一个activex控件。首先创建一个应用程序解决方案,并添加一个windows控件库项目:

用C#编写ActiveX控件的基础练习--经过测试的完整代码_第1张图片

更改“项目属性-应用程序-程序集信息”设置,勾选“使程序集 com 可见”:

用C#编写ActiveX控件的基础练习--经过测试的完整代码_第2张图片

用C#编写ActiveX控件的基础练习--经过测试的完整代码_第3张图片

更改“项目属性-生成”设置,勾选“为 com interop 注册”(注意,此处如果实在debug状态下修改的,那在调到release状态下还需要再设置一次):
用C#编写ActiveX控件的基础练习--经过测试的完整代码_第4张图片
修改assemblyinfo.cs文件,添加[assembly: allowpartiallytrustedcal<wbr>lers()]项(需要引用system.security名称空间):  <p><code>using system.reflection;  <br> using system.runtime.compilerservices;  <br> using system.runtime.interopservices;  <br><span style="color:#ff0000">using system.security;  <br></span> <br> [assembly: assemblytitle("yilin.preresearch.csharpactivex")]  <br> [assembly: assemblydescription("")]  <br> [assembly: assemblyconfiguration("")]  <br> [assembly: assemblycompany("10bar")]  <br> [assembly: assemblyproduct("yilin.preresearch.csharpactivex")]  <br> [assembly: assemblycopyright("copyright ? 10bar 2009")]  <br> [assembly: assemblytrademark("")]  <br> [assembly: assemblyculture("")]  <br><span style="color:#ff0000">[assembly: allowpartiallytrustedcal<wbr>lers()] </wbr></span> <br> [assembly: comvisible(true)]  <br> [assembly: guid("114d1f0c-43b8-40ac-ae7c-5adccc19aef3")]  <br> [assembly: assemblyversion("1.0.0.0")]  <br> [assembly: assemblyfileversion("1.0.0.0")]<br><br></code></p> <p><code>右击面板右侧的项目名称“testActiveX”,选择“添加”一个windows用户控件:</code></p> <p><code><img alt="" src="http://hi.csdn.net/attachment/201111/9/0_13208245837s9H.gif"></code></p> <p><code>按照开发windows用户控件一样的思路完成该控件的开发,本例中主要实现了两个业务功能,一个是提供一个公共方法,用于读取usbkey中保存的签名证书,保存到本地c盘根目录下,并返回操作信息;另一个业务功能提供ui界面,包括一个button控件和一个label控件,button控件的 click事件调用前面提供的那个方法,并将返回信息显示到label控件上。这样做可以达到两个目的,其一,activex控件提供公共方法供B/S程序直接调用,从后实现业务功能;其二,activex控件可以提供B/S程序ui界面,通过响应B/S程序中对ui的操作事件实现业务功能。</code></p> <p>  完成控件开发后,为了使该用户控件作为一个activex控件进行使用,还需要做以下修改:</p> <p>  首先,为控件类添加guid,这个编号将用于B/S系统的客户端调用时使用(可以使用 工具-创建guid 菜单创建一个guid): </p> <p><code>guid("4a44cf4e-f859-4328-aa22-3e9d7afff1ab")]  <br> public partial class hello : usercontrol  <br> {  </code></p> <p>  其次,为了让activex控件获得客户端的信任,控件类还需要实现一个名为“iobjectsafety”的接口。先创建该接口(注意,不能修改该接口的guid值): </p> <p><code>using System;<br> using System.Collections.Generic;<br> using System.ComponentModel;<br> using System.Drawing;<br> using System.Data;<br> using System.Text;<br> using System.Windows.Forms;<br><span style="color:#ff0000">using System.Runtime.InteropServices; <br></span></code></p> <p> <span style="color:#ff0000">[ComImport, GuidAttribute("67E30C07-CF4B-49c0-B835-ED2125A6EC2E")]<br> [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]<br> public interface iobjectsafety</span></p> <p><span style="color:#ff0000"> {<br> [PreserveSig]<br> int getinterfacesafetyoptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int PdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int PdwEnabledOptions);</span></p> <p><span style="color:#ff0000"> [PreserveSig()]<br> int setinterfacesafetyoptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int DwOptionSetmask, [MarshalAs(UnmanagedType.U4)] int DwEnabledOptions);<br> } </span><br></p> <p><code>  然后在控件类中继承并实现该接口: </code></p> <code></code> <p>#region iobjectsafety 成员</p> <p> private const string _iid_idispatch = "{00020400-0000-0000-c000-000000000046}";<br> private const string _iid_idispatchex = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";<br> private const string _iid_ipersiststorage = "{0000010a-0000-0000-c000-000000000046}";<br> private const string _iid_ipersiststream = "{00000109-0000-0000-c000-000000000046}";<br> private const string _iid_ipersistpropertybag = "{37d84f60-42cb-11ce-8135-00aa004bb851}";</p> <p> private const int interfacesafe_for_untrusted_caller = 0x00000001;<br> private const int interfacesafe_for_untrusted_data = 0x00000002;<br> private const int s_ok = 0;<br> private const int e_fail = unchecked((int)0x80004005);<br> private const int e_nointerface = unchecked((int)0x80004002);</p> <p> private bool _fsafeforscripting = true;<br> private bool _fsafeforinitializing = true;</p> <p> public int getinterfacesafetyoptions(ref Guid riid, ref int pdwsupportedoptions, ref int pdwenabledoptions)<br> {<br> int rslt = e_fail;</p> <p> string strguid = riid.ToString("b");<br> pdwsupportedoptions = interfacesafe_for_untrusted_caller | interfacesafe_for_untrusted_data;<br> switch (strguid)<br> {<br> case _iid_idispatch:<br> case _iid_idispatchex:<br> rslt = s_ok;<br> pdwenabledoptions = 0;<br> if (_fsafeforscripting == true)<br> pdwenabledoptions = interfacesafe_for_untrusted_caller;<br> break;<br> case _iid_ipersiststorage:<br> case _iid_ipersiststream:<br> case _iid_ipersistpropertybag:<br> rslt = s_ok;<br> pdwenabledoptions = 0;<br> if (_fsafeforinitializing == true)<br> pdwenabledoptions = interfacesafe_for_untrusted_data;<br> break;<br> default:<br> rslt = e_nointerface;<br> break;<br> }</p> <p> return rslt;<br> }</p> <p> public int setinterfacesafetyoptions(ref Guid riid, int dwoptionsetmask, int dwenabledoptions)<br> {<br> int rslt = e_fail;<br> string strguid = riid.ToString("b");<br> switch (strguid)<br> {<br> case _iid_idispatch:<br> case _iid_idispatchex:<br> if (((dwenabledoptions &amp; dwoptionsetmask) == interfacesafe_for_untrusted_caller) &amp;&amp; (_fsafeforscripting == true))<br> rslt = s_ok;<br> break;<br> case _iid_ipersiststorage:<br> case _iid_ipersiststream:<br> case _iid_ipersistpropertybag:<br> if (((dwenabledoptions &amp; dwoptionsetmask) == interfacesafe_for_untrusted_data) &amp;&amp; (_fsafeforinitializing == true))<br> rslt = s_ok;<br> break;<br> default:<br> rslt = e_nointerface;<br> break;<br> }</p> <p> return rslt;<br> }</p> <p> #endregion</p> <p></p> <p><code>  这样,一个activex控件就开发完成了。</code></p> <p><strong>3.2.Activex控件部署</strong></p> <p>  activex控件可以使用visual studio 2005的安装项目进行部署。这与普通的windows form应用程序的部署几乎一样,只有一个地方需要注意,将前面创建的用户控件项目作为主输出项目,并设置其register属性为vsdrpcom,如下图所示:</p> <p><img src="http://hi.csdn.net/attachment/201111/9/0_13208277376KVO.gif" alt=""></p> </wbr>
3.3.测试

  建立一个web应用程序项目,在测试页面的html代码中添加对activex控件的引用,并且可以通过javascript调用控件的公共成员(注意这里clsid后面的值即为前面为用户控件类设置的guid): 

<object id="csharpactivex" classid="clsid:e5e0446c-8680-4444-9fc2-f837bc617ed9"></object> 
<input type="button" onclick="alert(csharpactivex.sayhello());" value="显示当前时间" /> 

  将该web应用程序项目发布到iis。另外找一台电脑作为客户端测试环境,确保它与服务器端网络连通,安装.net framework 2.0和该activex控件。安装完成后,就可以用浏览器访问服务器,进行测试了(你也可以在开发环境的系统中安装该activex控件,并直接在vs 2005中运行webapp项目查看结果):

4. 总结

  综上所述,在visual studio 2005环境中使用c#开发activex控件,技术实现上没有什么难度,唯一的问题就是客户端需要安装.net framework。鉴于activex控件一般都是实现一些简单单一的功能,.net framework 2.0已经完全可以应付,所以建议在.net framework 2.0下开发。因为相对于.net framework 3.5两百多兆的安装包,.net framework 2.0安装包只有20多兆,用户相对容易接受一些。<wbr></wbr>

5. 出现如下错误怎么解决?

用C#编写ActiveX控件的基础练习--经过测试的完整代码_第5张图片

经在网上查阅,该问题是visual studio 2005的一个bug,并不是每次都发生。我的解决办法是从visual studio 2008的安装目录里拷贝regcap.exe覆盖visual studio 2005的对应文件,文件目录一般为“~\microsoft visual studio 8\common7\tools\deployment\regcap.exe”。压缩包中提供了该文件的visual studio 2008版本。

你可能感兴趣的:(ActiveX)