Question

Lors de la modification d'un objet ATL COM existant je suis tombé sur un article du « The Old New Thing » blog intitulé « Les façons dont les gens gâcher IUnknown :: QueryInterface » et il y avait une discussion dans la section des commentaires qui a commencé quand l'un des répondants (Norman diamant) a fait remarquer que ce que la distribution d'annuler ** dans l'un des exemples de l'article était incorrect.

Mais quand je tente de corriger mon code pour faire la coulée correctement je me retrouve avec une fuite de mémoire.

L'exemple est le suivant:

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

Norman dit

  

Punk est pas un vide *. le punk est un IUnknown *.

     

vide ** est pas un type de pointeur universel. void * est un type de pointeur universel, et char * et les parents sont pour être des droits acquis équivalent de cette façon, mais vide ** est pas.

     

Si vous voulez obéir à la convention d'appel et d'éviter des morts horribles, vous devez faire ceci:   IUnknown * le punk;   void * punkvoid;   psf-> QueryInterface (IID_IUnknown, & punkvoid);   Punk = (IUnknown *) punkvoid;

     

Beaucoup d'autres contributeurs MSDN fait la même erreur identique .... certaines personnes pourraient dire que cela fonctionne dans les mises en œuvre à ce jour de tous les VC, mais cela ne fait pas bon code, et il ne respecte pas toujours la convention d'appel.

À la lumière de cela, je suis allé à changer mon vieux code - dont voici le texte:

#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;
}

J'ai ensuite changé comme suit:

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;

Mais maintenant, ma demande a une fuite de mémoire de ce l'objet COM

Était-ce utile?

La solution

Vous avez probablement une fuite de mémoire parce que vous appelez GetActiveObject() et qui QueryInterface() sur le succès incrémenter le compteur de référence sur l'objet, mais ne remet pas plus tard Release() pour décrémenter le compte de référence.

Autres conseils

Mmm, je pense que, plutôt que d'assigner le vide * à pUnk je devrais utiliser:

pUnk.Attach(reinterpret_cast<IUnknown*>(pUnkVoid));
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top