【问题标题】:Why AddRef returns zero为什么 AddRef 返回零
【发布时间】:2014-04-08 04:21:09
【问题描述】:

我正在调试 C++/COM 应用程序,看看我们如何 AddRef 和 Release COM 对象。当 AddRef 返回 0 时,我遇到了奇怪的情况。这是我获取返回值的方法:

ULONG TraceAddRef(LPUNKNOWN pUnk, const std::string &a_msg) {
    ULONG count = pUnk->AddRef(); // count == 0 at some point after execution
    ATLTRACE("%s *** AddRef:  pUnk = 0x%p, referenceCount = %lu\n", a_msg.c_str(), pUnk, count);
    return count;
}

pUnk 实际上是一个 Web 控件的 IWebBrowser2 COM 接口:

pUnk    0x20d763ac  IUnknown *
__vfptr 0x5d85b0d8  const CFrameWebOC::`vftable'{for `IWebBrowser2'}

我已经查看了该行的反汇编(调试构建模式):

    ULONG count = pUnk->AddRef();
6515A52C  mov         eax,dword ptr [pUnk]  
6515A52F  mov         ecx,dword ptr [eax]  
6515A531  mov         esi,esp  
6515A533  mov         edx,dword ptr [pUnk]  
6515A536  push        edx  
6515A537  mov         eax,dword ptr [ecx+4]  
6515A53A  call        eax  
6515A53C  cmp         esi,esp  
6515A53E  call        _RTC_CheckEsp (65323F90h)  
6515A543  mov         dword ptr [count],eax

那一刻eax6515A543线上是0。

在调试器中,当我进入6515A53A 行时,它会显示以下代码:

    CFrameWebOC::AddRef:
5D707B6D  mov         edi,edi  
5D707B6F  push        ebp  
5D707B70  mov         ebp,esp  
5D707B72  push        edi  
5D707B73  mov         edi,dword ptr [ebp+8]  
5D707B76  inc         dword ptr [edi-18h]  
5D707B79  cmp         dword ptr [edi-18h],2  
5D707B7D  je          CFrameWebOC::AddRef+26h (5D707B93h)  
5D707B7F  test        dword ptr [edi-4],0FFFFFFFCh  
5D707B86  jne         5DF2DD04  
5D707B8C  xor         eax,eax  
5D707B8E  pop         edi  
5D707B8F  pop         ebp  
5D707B90  ret         4  
5D707B93  push        esi  
5D707B94  lea         esi,[edi-8]  
5D707B97  call        CTrackerHelper::SetAsRoot (5D85AD2Fh)  
5D707B9C  pop         esi  
5D707B9D  jmp         CFrameWebOC::AddRef+12h (5D707B7Fh)  
5D707B9F  nop  

5D707B76 行上的值dword ptr [edi-18h] 似乎是一个引用计数器,它的值是正确的,在inc 命令之前和之后非零。

我知道 AddRef 的返回值仅用于调试目的。 AddRef 返回 0 似乎是一个错误。这个错误会影响我正在使用的 COM 对象的行为,尤其是生命周期吗?

如果这有助于我在 VirtualBox 内使用 64 位 Win7,使用 MSVS 2010。DLL AddRef 位于:mshtml.dll

mshtml.dll  C:\Windows\SysWOW64\mshtml.dll  Symbols loaded (source information stripped).   C:\SYMBOLS\PUBLIC\mshtml.pdb\049E32F8F9F84F8EB494D8324AC1C3112\mshtml.pdb   104 10.00.9200.16521 (win8_gdr_soc_ie.130216-2100)  10/24/2013 8:37 PM  5D380000-5E137000   [0x21DFC] MyApplication.exe: Native

【问题讨论】:

  • xor eax,eax 肯定会返回 0。它确实像一个错误返回,预期会跳转到 5DF2DD04。不寻常。
  • 我怀疑实际的对象可能是一个单例,从未真正释放过,因此忽略了引用计数。但是返回值真的不打算依赖,所以我不会担心。合同是,如果您有参考,则该对象必须保持有效;其他一切都是可选的。
  • MSDN 文档确实明确说明了返回值,“此值仅用于测试目的。”
  • @AlanStokes:是的,它甚至可以是一个不在动态内存中分配的单例(例如它可以是一个文件级 C++ 变量),Release() 什么都不做并返回零。这看起来令人毛骨悚然,但效果很好。
  • MSHTML 对象有意为AddRef 返回 0,以避免人们依赖引用计数。调试时可以使用mshtml.dll的chk build。该版本返回来自AddRef 的引用计数。

标签: c++ assembly com iwebbrowser2


【解决方案1】:

看起来确实很奇怪,但艾伦的猜测听起来很对。从 AddRef 返回零不应影响 COM 内部的任何内容,因为正如您所提到的,该值仅用于调试。

【讨论】:

    猜你喜欢
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-08
    相关资源
    最近更新 更多