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

Com 使用ATL和IUnknownPtr时,正确的施法方式是什么?,com,casting,atl,void-pointers,iunknown,Com,Casting,Atl,Void Pointers,Iunknown,在修改现有ATL COM对象的过程中,我看到了一篇来自“新旧事物”博客的文章,名为“人们搞乱IUnknown::QueryInterface的方式”,在评论部分有一个讨论,开始于一位受访者(诺曼·戴蒙德)指出在文章的一个例子中,强制作废**是不正确的 然而,当我试图纠正我的代码以正确地进行转换时,我最终导致了内存泄漏 示例如下: IShellFolder *psf = some object; IUnknown *punk = NULL; psf->QueryInterface(IID_I

在修改现有ATL COM对象的过程中,我看到了一篇来自“新旧事物”博客的文章,名为“人们搞乱IUnknown::QueryInterface的方式”,在评论部分有一个讨论,开始于一位受访者(诺曼·戴蒙德)指出在文章的一个例子中,强制作废**是不正确的

然而,当我试图纠正我的代码以正确地进行转换时,我最终导致了内存泄漏

示例如下:

IShellFolder *psf = some object;
IUnknown *punk = NULL;
psf->QueryInterface(IID_IUnknown, (void**)&punk);
#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;
诺曼说

朋克不是一片空白*。朋克是个不为人知的人

void**不是通用指针类型。void*是一种通用的指针类型,char*和其亲属可以通过这种方式等效,但void**不是

如果你想遵守召唤规则,避免可怕的死亡,你必须做到: IUnknown*朋克; void*punkvoid; psf->查询接口(IID_IUnknown和punkvoid); 朋克=(IUnknown*)朋克球形

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

有鉴于此,我改变了我的旧代码-如下所示:

IShellFolder *psf = some object;
IUnknown *punk = NULL;
psf->QueryInterface(IID_IUnknown, (void**)&punk);
#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;
#包括
...
HRESULT FinalConstruct()
{ 
如果(m_dwROTCookie!=0)
返回E_失败;
//检查是否已经存在该对象的实例
IUnknownPtr pUnk=NULL;
if(GetActiveObject(CLSID_Object、NULL和pUnk)==S_OK)
{
TRACE_警告(“当前上下文中已存在对象的实例”);
返回S_OK;
}
HRESULT hr=查询界面(IID_IUnknown,重新解释演员和朋克));
hr=RegisterActiveObject(朋克、CLSID_对象、ACTIVEOBJECT_弱、m_dwROTCookie);
如果(失败(小时))
返回人力资源;
hr=CoLockObjectExternal(朋克,真,真);
朋克=零;
ATLASSERT(m_dwRef==2);
返回人力资源;
}
然后我将其更改如下:

IShellFolder *psf = some object;
IUnknown *punk = NULL;
psf->QueryInterface(IID_IUnknown, (void**)&punk);
#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;
HRESULT FinalConstruct()
{ 
如果(m_dwROTCookie!=0)
返回E_失败;
//检查是否已经存在该对象的实例
IUnknownPtr pUnk=NULL;
if(GetActiveObject(CLSID_Object、NULL和pUnk)==S_OK)
{
TRACE_警告(“当前上下文中已存在对象的实例”);
返回S_OK;
}
void*pUnkVoid=NULL;
HRESULT hr=查询接口(IID_IUnknown和pUnkVoid);
如果成功(hr)
{
朋克=重新解释铸造(朋克球形);
hr=RegisterActiveObject(朋克、CLSID_对象、ACTIVEOBJECT_弱、m_dwROTCookie);
如果(失败(小时))
返回人力资源;
hr=CoLockObjectExternal(朋克,真,真);
朋克=零;
}
ATLASSERT(m_dwRef==2);
返回人力资源;

但是现在我的应用程序有一个来自COM对象的内存泄漏,我认为与其将void*分配给pUnk,不如使用:

pUnk.Attach(reinterpret_cast<IUnknown*>(pUnkVoid));
pUnk.Attach(重新解释(pUnkVoid));

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