要使用C#实现一个ActiveX控件,需要解决三个问题: 1.使.NET组件能够被COM调用 2.在客户机上注册后,ActiveX控件能通过IE的安全认证 3.未在客户机上注册时,安装包能通过IE的签名认证 本程序的开发环境是.NET Framework 3.5,工具是Visual Studio .NET 2008,在安装.NET Framework 3.5的客户机上通过测试。 (一)创建可从COM访问的程序集 首先实现一个对COM可见的程序集,创建类库工程,AssemblyInfo.cs应包含:
//使此程序集中的类型对COM组件可见 加入以下代码到AssemblyInfo.cs确保程序集的可访问性:
[assembly: AllowPartiallyTrustedCallers()] 注意上面的Guid,如果程序集内部的类未标注Guid,COM注册的Guid是会新生成的,此处的Guid没有作用。 创建用户控件(自定义类待测)IdentityKey.cs,加入: C#实现一个ActiveX控件 要使用C#实现一个ActiveX控件,需要解决三个问题: 1.使.NET组件能够被COM调用 2.在客户机上注册后,ActiveX控件能通过IE的安全认证 3.未在客户机上注册时,安装包能通过IE的签名认证 本程序的开发环境是.NET Framework 3.5,工具是Visual Studio .NET 2008,在安装.NET Framework 3.5的客户机上通过测试。 下面是实现步骤: (一)创建可从COM访问的程序集 首先实现一个对COM可见的程序集,创建类库工程,AssemblyInfo.cs应包含: using System.Runtime.InteropServices; //使此程序集中的类型对COM组件可见 [assembly: ComVisible(true)] // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID [assembly: Guid("94882155-3B7C-48e3-B357-234D56D8F15E")] 加入以下代码到AssemblyInfo.cs确保程序集的可访问性: using System.Security; [assembly: AllowPartiallyTrustedCallers()] 注意上面的Guid,如果程序集内部的类未标注Guid,COM注册的Guid是会新生成的,此处的Guid没有作用。 创建用户控件(自定义类待测)IdentityKey.cs,加入: using System; using System.ComponentModel; using System.Windows.Forms; using System.Runtime.InteropServices; namespace KeyActiveX { [Guid("94882155-3B7C-48e3-B357-234D56D8F15E")] public partial class IdentityKey : UserControl { } }
C#实现一个ActiveX控件
namespace System.Runtime.InteropServices { // 摘要: // Identifies how to expose an interface to COM. [Serializable] [ComVisible(true)] public enum ComInterfaceType { // 摘要: // Indicates the interface is exposed to COM as a dual interface, which enables // both early and late binding. System.Runtime.InteropServices.ComInterfaceType.InterfaceIsDual // is the default value. InterfaceIsDual = 0, // // 摘要: // Indicates an interface is exposed to COM as an IUnknown -derived interface, // which enables only early binding. InterfaceIsIUnknown = 1, // // 摘要: // Indicates an interface is exposed to COM as a dispinterface, which enables // late binding only. InterfaceIsIDispatch = 2, } }
关于三个接口的具体描述,可以参考《C#高级编程第三版》28.1.3 接口。 在MSDN上查找,可以知道IObjectSafety继承自IUnknown,是一个定制接口;通过上一章节,可以发现向COM注册时,需要提供一个Guid作为CLSID来标识程序集中的C#类,事实上在COM中,接口和类型库都是带有Guid作为唯一标识的,分别为IID和typelib id。 这样,通过在C#编写的接口标上需要的COM接口IID,就可以在注册是向COM表明接口身份了。在Microsoft帮助上查找IObjectSafety定义: IObjectSafety定义: [ uuid(C67830E0-D11D-11cf-BD80-00AA00575603), helpstring("VB IObjectSafety Interface"), version(1.0) ] library IObjectSafetyTLB { importlib("stdole2.tlb"); [ uuid(CB5BDC81-93C1-11cf-8F20-00805F2CD064), helpstring("IObjectSafety Interface"), odl ] interface IObjectSafety:IUnknown { [helpstring("GetInterfaceSafetyOptions")] HRESULT GetInterfaceSafetyOptions( [in] long riid, [in] long *pdwSupportedOptions, [in] long *pdwEnabledOptions); [helpstring("SetInterfaceSafetyOptions")] HRESULT SetInterfaceSafetyOptions( [in] long riid, [in] long dwOptionsSetMask, [in] long dwEnabledOptions); } }
其中的uuid(CB5BDC81-93C1-11cf-8F20-00805F2CD064)就是需要的接口IID。 使用C#编写IObjectSafety: using System; using System.Runtime.InteropServices; namespace KeyActiveX { [ComImport, Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IObjectSafety { [PreserveSig] void GetInterfacceSafyOptions( int riid, out int pdwSupportedOptions, out int pdwEnabledOptions); [PreserveSig] void SetInterfaceSafetyOptions( int riid, int dwOptionsSetMask, int dwEnabledOptions); } } InterfaceType中一定要使用ComInterfaceType.InterfaceIsIUnknown,因为IObjectSafety继承自IUnkown。 接下来是KeyActiveX的接口实现: namespace KeyActiveX { [Guid("94882155-3B7C-48e3-B357-234D56D8F15E")] public partial class IdentityKey : UserControl, IObjectSafety { #region IObjectSafety 成员 public void GetInterfacceSafyOptions(int riid, out int pdwSupportedOptions, out int pdwEnabledOptions) { pdwSupportedOptions = 1; pdwEnabledOptions = 2; } public void SetInterfaceSafetyOptions(int riid, int dwOptionsSetMask, int dwEnabledOptions) { throw new NotImplementedException(); } #endregion } } 通过返回一个已定值来告诉IE控件是安全的。具体参见http://support.microsoft.com/kb/182598/ (三)签名发布 C#开发的ActiveX控件发布方式有三种: 1.制作客户端安装包,分发给客户机安装; 2.制作在线安装包,客户机联机安装; 3.使用html中object的codebase指向安装包地址。 前两个比较简单,适合在局域网内实施;最后一种方式,需要在安装包上进行数字签名,以保证客户机的安全信任。受信任的签名证书应该向证书提供商(如Versign)购买,然后使用签名工具对安装包进行签名。 下面利用Visual Studio 2008自带的测试证书创建工具MakeCert和签名工具SignTool进行测试,首先创建一个带有公司信息的测试证书,在Visual Studio命令提示符后输入: makecert -sk ABC -n "CN=ABC Corporation" f:\abccorptest.cer 在F盘上创建了测试证书。然后输入 signtool signwizard 在Signing Options页面上,选择Custom,定义证书文件的位置,再下一步选择一个加密算法(MD5或SHA1),指定应用程序的名称和描述URL,确认。 此时ActiveX控件安装包有了一个被标记为未信任的测试证书,需要将IE设置为启用未信任安装程序,在html中引用 <object id="controlbyid" classid="clsid:{94882155-3B7C-48e3-B357-234D56D8F15E}" codebase="setup.exe" ></object> |