CSharp Tips:让DotNet实现的COM对象支持IObjectSafety接口

原创 2003年10月16日 09:40:00
当我们实现的COM对象,或者ActiveX控件在浏览器中调用的时候,往往会出现警告框,提示不安全的控件正在运行。这是因为浏览器安全策略所限定的,浏览器认为只有“安全的对象”才能够被执行。
所谓安全的对象就是指那些不访问本地资源的对象,例如不会去读注册表,不会写文件等等。一个满足条件的对象通过支持IObjectSafety接口告诉浏览器,自己是合法的。
下面就简单的介绍一下怎么在C#中实现对于IObjectSafety接口的支持。
 
思路
C/C++d的程序可以直接在SDK中找到IObjectSafety的定义,所以需要支持的话非常容易。C#比较麻烦,因为我们没有办法获得IObjectSafety的定义,不过没有问题,我们可以按照IObjectSafety在SDK中的定义,在C#的工程中重新定义该接口。
如果大家了解COM机制一定会知道,所谓借口的定义之出现在类型库中,与实现无关。而判断一个接口唯一性就是定义接口时指定的UUID。此外自己重新定义时需要保证接口中没有函数的参数与返回值必须与原定义一致即可。
我们的做法就是,找到ObjSafe.idl,然后复制其中的UUID,利用这个UUID在C#中定一个interface IObjectSafety,并且申明其中的两个函数;定义完成之后,让需要检查安全接口的组件继承该接口,并在该组件内部实现IObjectSafety的两个函数,按照要求做适当的返回,那么用这个组件包装的COM对象在IE中调用就被认为是安全的了。
 
第一次尝试
按照上面的思路,我们开始进行尝试
idl中的接口定义
[
 object,
 uuid(CB5BDC81-93C1-11cf-8F20-00805F2CD064),
 pointer_default(unique)
]
interface IObjectSafety : IUnknown
{
 HRESULT GetInterfaceSafetyOptions(
  [in]  REFIID riid,     // Interface that we want options for
  [out] DWORD * pdwSupportedOptions, // Options meaningful on this interface
  [out] DWORD * pdwEnabledOptions);  // current option values on this interface
 
 HRESULT SetInterfaceSafetyOptions(
  [in]  REFIID riid,     // Interface to set options for
  [in]  DWORD  dwOptionSetMask,  // Options to change
  [in]  DWORD  dwEnabledOptions);  // New option values
}
IObjectSafety接口定义
    因为接口中存在指针,所以直接采用Int32的整型形式,用到了unsafe code。
 [Guid("CB5BDC81-93C1-11cf-8F20-00805F2CD064")]
 public interface IObjectSafety
 {
  // methods
  unsafe void GetInterfacceSafyOptions(
   System.Int32 riid,
   System.Int32* pdwSupportedOptions,
   System.Int32* pdwEnabledOptions);
  void SetInterfaceSafetyOptions(
   System.Int32 riid,
   System.Int32 dwOptionsSetMask,
   System.Int32 dwEnabledOptions);
 }
继承
 public class MyControl : System.Windows.Forms.UserControl,IObjectSafety
实现
  // implement functions of IObjectSafety
  public unsafe void GetInterfacceSafyOptions(System.Int32 riid,System.Int32* pdwSupportedOptions,System.Int32* pdwEnabledOptions)
  {
        ...
  }
  public void SetInterfaceSafetyOptions(System.Int32 riid,System.Int32 dwOptionsSetMask,System.Int32 dwEnabledOptions)
  {
        ...    
  }
    一切正常编译通过,但是通过IE调用测试页面,在装载页面的时候却产生了一个关闭应用程序系统异常,仔细察看内容Error Report是非法的内存地址访问。无语中...
 
第二次尝试
    由于是非法的内存地址访问,很自然的联想到是接口定义的问题,因为存在unsafe code,查查文档发现根本无需使用unsafe code这么夸张,可以通过out这个参数修饰符解决。
    修改定义和实现如下
IObjectSafety接口定义
 [Guid("CB5BDC81-93C1-11cf-8F20-00805F2CD064")]
 public interface IObjectSafety
 {
  // methods
  void GetInterfacceSafyOptions(
   System.Int32 riid,
   out System.Int32 pdwSupportedOptions,
   out System.Int32 pdwEnabledOptions);
  void SetInterfaceSafetyOptions(
   System.Int32 riid,
   System.Int32 dwOptionsSetMask,
   System.Int32 dwEnabledOptions);
 }
实现
  // implement functions of IObjectSafety
  public unsafe void GetInterfacceSafyOptions(System.Int32 riid,out System.Int32 pdwSupportedOptions,out System.Int32 pdwEnabledOptions)
  {
        ...
  }
  public void SetInterfaceSafetyOptions(System.Int32 riid,System.Int32 dwOptionsSetMask,System.Int32 dwEnabledOptions)
  {
        ...    
  }
    编译通过,不错;IE调用测试页面,同样的错误!郁闷,无斗志,回家。
 
第三次尝试
    睡了一觉,饱餐战饭,继续思考。
    自己比较了编译器生成的类型库,发现一些很奇怪的现象,在类型库中IObjectSafety居然被定义了两次interface IObjectSafety : IUnknown,以及dispinterface IObjectSafety : IDispatch。而偏偏MyControl是从dispinterface IObjectSafety上继承的。这就与正确的IObjectSafety的接口说明相违背,问题应该出在这里。
    MSDN,查文档。System.Runtime.InteropService下有很多关于描述接口的属性,从中可以找到产生问题的原因。有一个属性InterfaceTypeAttribute,就是用来说明定义的接口是从IUnknown继承还是IDispatch继承,缺省情况下是Dual的,所以是两份。
    再次定义如下:
 [Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"),InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
 public interface IObjectSafety
 {
  // methods
  void GetInterfacceSafyOptions(
   System.Int32 riid,
   out System.Int32 pdwSupportedOptions,
   out System.Int32 pdwEnabledOptions);
  void SetInterfaceSafetyOptions(
   System.Int32 riid,
   System.Int32 dwOptionsSetMask,
   System.Int32 dwEnabledOptions);
 }
    其余代码不变,重新编译,通过;察看导出类型库,果然少了很多垃圾;调用测试页面,正确。激动中...
 
怎样让IE认为你的对象安全
    实现了这个接口,剩下的事情就很简单了。前面提到过如果按照正规的途径你需要确保你的代码没有访问系统的本地自然,然后按照文档要求,当该对象被不同的接口调用查询的时候,做不同的反馈。具体实现可以在MSDN的Sample中找到。
    当然我们可以写一个对象读写本地文件,但是支持IObjectSafety接口,并且始终声明自己是合法的,这样来欺骗浏览器,那么代码就很简单了,如下:
  // implement functions of IObjectSafety
  public void GetInterfacceSafyOptions(System.Int32 riid,out System.Int32 pdwSupportedOptions,out System.Int32 pdwEnabledOptions)
  {
   pdwSupportedOptions = CLsObjectSafety.INTERFACESAFE_FOR_UNTRUSTED_CALLER;
   pdwEnabledOptions = CLsObjectSafety.INTERFACESAFE_FOR_UNTRUSTED_DATA;
  }
  public void SetInterfaceSafetyOptions(System.Int32 riid,System.Int32 dwOptionsSetMask,System.Int32 dwEnabledOptions)
  {
  }
    只要这么些,就不会再有讨厌的对话框弹出了。
 
    如果你的组件是在客户端安装,在浏览器中调用,那么所有的工作已经完成;所以是希望通过Codebase的方式下载发布,你还需要去搞一个数字签字,已经不是本文讨论的范围了,就到这里,结束了。
 
 
参考文档
1、HOWTO: Implement IObjectSafety in Visual Basic Controls(http://support.microsoft.com/default.aspx?scid=kb;EN-US;q182598)

CSharp Tips:让DotNet实现的COM对象支持IObjectSafet

  • zgqtxwd
  • zgqtxwd
  • 2008年04月24日 15:47
  • 130

ATL 实现IObjectSafety 接口

如果com组件要在IE中进行调用,则必须实现IObjectSafety接口,不然在ie中必须调整activex选项才可以正常运行,如下是实现IObjectSafety的例子:#include //...
  • sstower
  • sstower
  • 2011年07月05日 21:39
  • 3427

再谈IObjectSafety

都说ActiveX危险,那么为什么XmlHttpRequest以及MediaPlayer都是用ActiveX的方式创建的,却没有问题?原来,这是因为这些ActiveX组件都声明自己是脚本安全的,而IE...
  • optman
  • optman
  • 2007年07月18日 22:39
  • 18036

ActiveX ocx控件有时在网页中无法显示需要实现IObjectSafety接口

ActiveX ocx控件有时在网页中无法显示需要实现IObjectSafety接口 通过自己调试,可能导致的原因是:          如果没有实现IobjectSafety...
  • caijun12358098
  • caijun12358098
  • 2012年03月06日 08:53
  • 2683

ActiveX学习笔记二 ActiveX在IE中安全级别问题-实现IObjectSafety接口

使用MFC开发ActiveX控件,在IE中会提示安全问题,这个可以通过实现IObjectSafety接口来解决问题1.首先要包含头文件#include 2.然后在你的ActiveX头文件中添加DECL...
  • freedomqx
  • freedomqx
  • 2009年12月07日 11:38
  • 3249

COM组件的接口和对象

一、 前言 在COM规范中,最基本的两个要素就是对象与接口,因为COM就是由这两者来共同实现的。COM对象在组件中是被封装起来的,客户代码只能通过接口来访问COM对象并享受其服务,由于客户与COM...
  • u010523811
  • u010523811
  • 2017年02月07日 17:21
  • 2098

COM组件常用接口,以备自用

COM组件有三个最基本的接口类,分别是IUnknown、IClassFactory、IDispatch。 COM组件的存在方式:DLL文件或者EXE文件; COM组件包括COM对象; COM对象包...
  • d977136629
  • d977136629
  • 2017年03月14日 16:48
  • 475

18.可连接对象和连接点原理

讲解可连接对象和连接点原理,说明实现一个可连接对象需要做的事情。
  • wenzhou1219
  • wenzhou1219
  • 2016年07月16日 21:04
  • 769

调用 COM 对象

调用 COM 对象 大多数 Windows 程序员都熟悉组件对象模型(Component Object Model,COM)。在某程度上,.NET 框架 就是为了替换 COM,但是,系统仍然...
  • hadstj
  • hadstj
  • 2014年06月23日 16:41
  • 1211

【COM原理和应用】2、COM对象和接口

1、COM对象 在客户程序与组件交互的过程中,COM组件将以COM对象形式封装的实体提供给客户程序。...
  • shaqoneal
  • shaqoneal
  • 2015年02月04日 17:56
  • 876
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:CSharp Tips:让DotNet实现的COM对象支持IObjectSafety接口
举报原因:
原因补充:

(最多只允许输入30个字)