使用ATL和IUnknownPtr时,正确的方法是什么?

时间:2010-03-08 15:22:32

标签: com casting atl void-pointers iunknown

在修改现有的ATL COM对象期间,我看到了一篇名为“The New New Thing”博客的文章,名为“人们搞乱IUnknown :: QueryInterface的方式”,并在评论部分进行了讨论。其中一位受访者(Norman Diamond)指出,在文章的一个例子中,演员无效**是不正确的。

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

示例如下:

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

诺曼说

  朋克不是空虚*。朋克是IUnknown *。

     

void **不是通用指针类型。 void *是一个通用的指针类型,并且char *和亲属在这方面是相同的,但是void **不是。

     

如果你想遵守召唤惯例并避免可怕的死亡,你必须这样做:   IUnknown *朋克;   void * punkvoid;   psf-> QueryInterface(IID_IUnknown,& punkvoid);   punk =(IUnknown *)punkvoid;

     

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

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

#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对象的内存泄漏

2 个答案:

答案 0 :(得分:0)

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

pUnk.Attach(reinterpret_cast<IUnknown*>(pUnkVoid));

答案 1 :(得分:0)

你可能有内存泄漏,因为你调用GetActiveObject()QueryInterface()成功递增对象的引用计数,但是之后不要再调用Release()来减少引用计数