注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

古城风~~~

竹密无妨溪水过,天高不碍白云飞。这天下总有一份是属于我古城的天地!

 
 
 

日志

 
 

C#实现ActiveX控件开发  

2011-02-27 10:56:37|  分类: asp |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

要使用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应包含:


C#代码
using System.Runtime.InteropServices;   
  
//使此程序集中的类型对COM组件可见   
[assembly: ComVisible(true)]   
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID   
[assembly: Guid("94882155-3B7C-48e3-B357-234D56D8F15E")]  

using System.Runtime.InteropServices;    //使此程序集中的类型对COM组件可见  [assembly: ComVisible(true)]  // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID  [assembly: Guid("94882155-3B7C-48e3-B357-234D56D8F15E")]  

 

 


加入以下代码到AssemblyInfo.cs确保程序集的可访问性:
C#代码


using System.Security;   
  
[assembly: AllowPartiallyTrustedCallers()]  

using System.Security;    [assembly: AllowPartiallyTrustedCallers()]  

 

 


注意上面的Guid,如果程序集内部的类未标注Guid,COM注册的Guid是会新生成的,此处的Guid没有作用。
创建用户控件(自定义类待测)IdentityKey.cs,加入:
C#代码


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   
    {   
    }   
}  

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      {      }  }  

 

 


这里的Guid和AssemblyInfo.cs一样,它会在COM注册中成为CLSID并被html以clsid调用。
类库工程属性中,选择生成,勾选COM注册,在html文件中加入
Html代码


<object id="controlbyid" classid="clsid:{94882155-3B7C-48e3-B357-234D56D8F15E}" ></object>  

<object id="controlbyid" classid="clsid:{94882155-3B7C-48e3-B357-234D56D8F15E}" ></object>  

 

 


在IE中启用不安全控件,查看html页面,应能访问到控件,现在一个在发布时对COM注册的程序集开发完成了。
使用OLE/COM Object Viewer(安装VC自带)可以在.NET Categories中查看组件和CLSID。
(二)通过IE安全控件认证
如果客户机的IE未开启访问非安全标记的ActiveX控件,通过IE浏览上面的步骤开发出的ActiveX控件,发现IE会给出警告:
此页上的 ActiveX 对象可能不安全的。 要允许它将初始化并通过脚本访问吗?
或禁止访问。这是客户机IE的安全规则设置的,我们应该在控件开发上解决IE安全认证的问题。首先我们要了解IE是如何判断一个ActiveX控件是不安全的,参见Microsoft帮助和支持文档:
How Internet Explorer Determines If ActiveX Controls Are Safe
There are two ways to mark a control as safe for scripting and initialization:
? Implement the IObjectSafety interface.
? Provide the following registry keys for the control's CLSID under the Implemented Categories section:
The following key marks the control safe for scripting: {7DD95801-9882-11CF-9FA9-00AA006C42C4}
The following key marks the control safe for initialization from persistent data: {7DD95802-9882-11CF-9FA9-00AA006C42C4}
Microsoft recommends that you implement IObjectSafety to mark a control as safe or unsafe. This prevents other users from repackaging your control and marking it as safe when it is not.
我决定实现IObjectSafety接口来向IE表明ActiveX控件的安全标识,以保证控件再次打包时安全标识不会被被改写。
IObjectSafety是一个COM下的接口,对于C++程序来说,只需要实现它就行了,而.NET之下没有这个接口,在这种情况下,我们的ActiveX控件就是一个不带类型库的COM组件,必须使用C#代码重新定义COM接口。
这里需要了解一点COM的接口知识。接口是COM的核心,它区分了在客户和对象之间使用的契约和实现。COM的接口有三种类型:定制接口÷分派接口和双重接口。.NET Framework使用ComInterfaceType对它进行了重定义:
C#代码


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,   
    }   
}  

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定义:
C++代码


[   
    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(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:
C#代码


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);   
    }   
}  

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的接口实现:
C#代码


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   
    }   
}  

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控件是安全的。具体参见
如何在 VisualBasic 控件实现 IObjectSafety
(三)签名发布
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中引用
Html代码


<object id="controlbyid" classid="clsid:{94882155-3B7C-48e3-B357-234D56D8F15E}" codebase="setup.exe" ></object>  

<object id="controlbyid" classid="clsid:{94882155-3B7C-48e3-B357-234D56D8F15E}" codebase="setup.exe" ></object>  


客户机安装之后就可以使用ActiveX控件了。

 

 

来源:http://rcfans.javaeye.com/blog/260195

  评论这张
 
阅读(1062)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017