【发布时间】: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
那一刻eax在6515A543线上是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