1

在修改现有 ATL COM 对象的过程中,我看到了一篇来自“The Old New Thing”博客的文章,名为“人们搞砸 IUnknown::QueryInterface 的方式”,评论部分开始讨论其中一个受访者 (Norman Diamond) 指出,在文章的一个示例中,强制转换为 void** 是不正确的。

但是,当我尝试纠正我的代码以正确进行转换时,我最终会出现内存泄漏。

示例如下:

IShellFolder *psf = some object;
IUnknown *punk = NULL;
psf->QueryInterface(IID_IUnknown, (void**)&punk);

诺曼说

朋克不是虚无*。朋克是一个未知数*。

void** 不是通用指针类型。void* 是一种通用指针类型,并且 char* 和亲戚以这种方式被视为等价,但 void** 不是。

如果你想遵守调用约定并避免可怕的死亡,你必须这样做:IUnknown *punk; 无效*朋克无效;psf->QueryInterface(IID_IUnknown, &punkvoid); 朋克 = (IUnknown *)punkvoid;

许多其他 MSDN 贡献者犯了同样的错误……有些人可能会说它在迄今为止的所有 VC++ 实现中都有效,但这并不能使它成为正确的代码,而且它仍然违反了调用约定。

鉴于此,我去更改我的旧代码 - 如下:

#include <comdef.h>

...

HRESULT FinalConstruct()
{ 
    if (m_dwROTCookie != 0)
        return E_FAIL;

    //Check whether there already is an instance of the Object
    IUnknownPtr pUnk = NULL;
    if (GetActiveObject(CLSID_Object, NULL, &pUnk) == S_OK)
    {
        TRACE_WARNING("An instance of Object already exists in the current context");
        return S_OK;
    }
    HRESULT hr = QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&pUnk));

    hr = RegisterActiveObject(pUnk, CLSID_Object, ACTIVEOBJECT_WEAK, m_dwROTCookie);        
    if (FAILED(hr))
        return hr;

    hr = CoLockObjectExternal(pUnk, TRUE, TRUE);
    pUnk = NULL;
    ATLASSERT(m_dwRef == 2);
    return hr;
}

然后我将其更改如下:

HRESULT FinalConstruct()
{ 
    if (m_dwROTCookie != 0)
        return E_FAIL;

    //Check whether there already is an instance of the Object
    IUnknownPtr pUnk = NULL;
    if (GetActiveObject(CLSID_Object, NULL, &pUnk) == S_OK)
    {
        TRACE_WARNING("An instance of Object already exists in the current context");
        return S_OK;
    }
    void* pUnkVoid = NULL;
    HRESULT hr = QueryInterface(IID_IUnknown, &pUnkVoid);

    if (SUCCEEDED(hr)
    {
        pUnk = reinterpret_cast<IUnknown*>(pUnkVoid);
        hr = RegisterActiveObject(pUnk, CLSID_Object, ACTIVEOBJECT_WEAK, m_dwROTCookie);        
        if (FAILED(hr))
            return hr;

        hr = CoLockObjectExternal(pUnk, TRUE, TRUE);
        pUnk = NULL;
    }
    ATLASSERT(m_dwRef == 2);

    return hr;

但是现在我的应用程序有一个来自 COM 对象的内存泄漏

4

2 回答 2

0

嗯,我认为与其将 void* 分配给 pUnk 我应该使用:

pUnk.Attach(reinterpret_cast<IUnknown*>(pUnkVoid));
于 2010-03-08T15:51:10.780 回答
0

您可能有内存泄漏,因为您调用GetActiveObject()并且QueryInterface()成功增加对象的引用计数,但不要Release()稍后调用以减少引用计数。

于 2010-03-09T07:41:04.367 回答