博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

如何判断两个COM指针是同一个对象

Posted on 2009-06-02 11:38  一桶浆糊  阅读(997)  评论(0编辑  收藏  举报

故事起源于我移植V8到IE中的过程,在CSDN论坛上也发现不少问此问题的人,所以特地整理一篇文章来解释这个问题。

 

这个问题本来是一个非常简单的问题,COM指针也是指针,既然是指针,只要它们的值相同,就表示它们指向相同的COM对象,如果不同则表示不同对象。假设要写一个判断函数的情况下,表示成这样:

 

 

这种判断方法在绝大多数情况下正确,但仅仅是绝大多数,还有极少数情况下判断会失效,尤其在同一个对象有两个不同指针的情况下。什么情况呢?代理对象。微软的很多产品大量使用了代理对象,注意这里的代理对象不是指的COM对象的代理存根。代理对象的作用像一个沙箱,能有效隔离引用计数和其它方法访问异常,而且也能在安全访问方面做更多的控制。Office对Application对象使用了代理对象,IE对IHTMLWindow2对象使用了代理对象,还有其它一些DOM对象也使用了代理对象。

 

言归正传,一个COM对象既然可以存在一至多个代理对象,就必须提供方法来让用户判断这些COM对象是不是相同的对象(注意代理对象应该跟原始对象相同)。为此微软设计了IObjectIdentity接口,通过此接口的IsEqualObject方法来判断两个对象是否相同。下面的方法就是一个改进版。

 

 

到目前为止,上面的 is_com_equal 函数工作得非常好,几乎挑不出什么毛病。但我这人太固执,还真挑出了它的毛病。其实这个毛病是一个伪毛病,函数本身没有问题,但是当我在把V8移植到IE中的时候揪出了IE的一条虫,大概过程是这样的:有两个对象,一个是div对象,另一个是style对象,这两个风马牛不相及的对象居然被 IObjectIdentity::IsEqualObject 判断成了相同的对象,可以想见后果如何。这个问题折腾了我大概一周的时间才找到原因。这个现象其实是微软在实现对象的 IObjectIdentity 接口时写错代码了,迫不得已我只好另辟途径来绕过这个BUG,在判断它之前通过对比IDispatch对象的IID来临时解决接口比较问题。下面的代码体现了这种比较,但是通常读者使用上面的代码就足够了,除非他也遇到了同样的问题。

 

 

 

两个COM接口比较,居然用了如此多的代码和如此多的篇幅介绍,也真够BT的……