2010-03-08 4 views
0

Во время модификации существующего COM-объекта ATL я наткнулся на статью из блога «The Old New Thing» под названием «Пути людей испортили IUnknown :: QueryInterface», и было обсуждение в разделе комментариев, которое начиналось, когда один респондентов (Норман Даймонд) отметили, что в одном из примеров статьи, что литье в пустоту ** было неверным.Каков правильный способ использования при использовании ATL и IUnknownPtr?

Однако, когда я пытаюсь исправить свой код, чтобы правильно выполнить кастинг, я получаю утечку памяти.

пример следующим образом:

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

Норман сказал

панк не является недействительным *. punk - это IUnknown *.

void ** не является универсальным типом указателя. void * - универсальный тип указателя, а char * и родственники дедушкины, чтобы быть эквивалентными таким образом, но void ** - нет.

Если вы хотите повиноваться соглашению о вызове и избегать ужасных смертей, вы должны сделать это: IUnknown * punk; void * punkvoid; psf-> QueryInterface (IID_IUnknown, & punkvoid); punk = (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-объекта

ответ

0

Вы, вероятно, есть утечка памяти, потому что вы называете GetActiveObject() и QueryInterface(), который в случае успеха приращение счетчика ссылок на объект, но не называют Release() позже уменьшаем счетчик ссылок.

0

Ммм, я думаю, что вместо того, чтобы назначать пустоту * на pUnk, я должен использовать:

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

 Смежные вопросы

  • Нет связанных вопросов^_^