2016-10-28 6 views
-1

Ich habe einen WMI-bezogenen Code, der ein Ereignis erhält, sobald die neue App gestartet wird. Ich habe Initialisierungsteil übersprungen, hier ist der Code. Beachten Sie, dass alles funktioniert, alle HRESULTs sind S_OK.Speicherverlust in IWbemServices-> ExecNotificationQuery?

IEnumWbemClassObject* pEnumerator = NULL; 

pSvc->ExecNotificationQuery(// IWbemServices *pSvc is initialized 
    bstr_t("WQL"), 
    bstr_t("SELECT * FROM __InstanceCreationEvent WITHIN 1 " 
     "WHERE TargetInstance ISA 'Win32_Process'"), 
    WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
    NULL, &pEnumerator); 

while (pEnumerator) { 
    _variant_t v1, v2; 
    pclsObj->Get(_bstr_t(L"TargetInstance"), 0, &v1, 0, 0); 
    IUnknown* str = v1; 
    str->QueryInterface(IID_IWbemClassObject, reinterpret_cast< void** >(&pclsObj)); 
    pclsObj->Get(bstr_t(L"Handle"), 0, &v2, 0, 0); 
    LONG pid{ 0 }; 
    hr = VarI4FromStr(v2.bstrVal, LOCALE_NOUSEROVERRIDE, 409, &pid); 
    Internal::Inject(pid); // It's my code, not relevant here 

    str->Release(); 
    pclsObj->Release(); 
    v1.Clear(); 
    v2.Clear(); 
} 

Dieser Code wurde von MSDN übernommen und geringfügig geändert. Allerdings verliert es Speicher und ich habe keine Ahnung warum. Blick über MSVC Speicher-Profiler gibt uns dieses Bild: screen1

oder dies: screen2

Aus meiner Sicht - ich gelöscht habe \ freigegeben alles jedoch Zuweisungen, wie auf Screenshots, sobald neues Ereignis eintritt ankommen und sie bleiben für immer.

Ich habe this question gefunden, es scheint das gleiche zu sein, aber keine Antwort erhalten.

Visual Studio 2015 Update 3, aktuelles Windows 10 x 64 Professional.

+2

Haben Sie die Release() auf pEnumerator nennen? Es ist auch ein COM-Objekt – Matt

+0

@matt, ich habe versucht, nicht geholfen – Starl1ght

+0

versuchen dieses Tool DebugDiag: https://www.microsoft.com/en-us/download/details.aspx?id=49924 – Matt

Antwort

1

Wenn Sie str->QueryInterface() aufrufen, überschreiben Sie zuvor den pclsObj Zeiger, ohne zuvor aufzurufen. Sie rufen Release() auf dem pclsObj Objekt, das QueryInterface() zurückgibt, und undicht das ursprüngliche Objekt pclsObj.

Sie sollten die Verwaltung der Schnittstellenreferenzzähler nicht mehr manuell ausführen und stattdessen den Wrapper _com_ptr_t verwenden.

Woher kommt das Original pclsObj? Offenbar fehlt ein Anruf an pEnumerator->Next().

Probieren Sie etwas wie folgt statt (Fehler der Kürze halber weggelassen Abwicklung):

_com_ptr_t<IEnumWbemClassObject> pEnumerator; 

pSvc->ExecNotificationQuery(// IWbemServices *pSvc is initialized 
    bstr_t("WQL"), 
    bstr_t("SELECT * FROM __InstanceCreationEvent WITHIN 1 " 
     "WHERE TargetInstance ISA 'Win32_Process'"), 
    WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
    NULL, &pEnumerator); 

if (pEnumerator) 
{ 
    while (true) 
    { 
     _com_ptr_t<IWbemClassObject> pclsEvent, pclsObj; 
     _variant_t v1, v2; 
     ULONG ulReturned = 0; 

     pEnumerator->Next(WBEM_INFINITE, 1, &pclsEvent, &ulReturned); 
     pclsEvent->Get(_bstr_t(L"TargetInstance"), 0, &v1, 0, 0); 

     _com_ptr_t<IUnknown> str = v1; 
     str->QueryInterface(IID_IWbemClassObject, reinterpret_cast<void**>(&pclsObj)); 
     pclsObj->Get(bstr_t(L"Handle"), 0, &v2, 0, 0); 

     LONG pid{ 0 }; 
     hr = VarI4FromStr(v2.bstrVal, LOCALE_NOUSEROVERRIDE, 409, &pid); 
     Internal::Inject(pid); // It's my code, not relevant here 
    } 
} 

Alternativ:

_com_ptr_t<IEnumWbemClassObject> pEnumerator; 

pSvc->ExecNotificationQuery(// IWbemServices *pSvc is initialized 
    bstr_t("WQL"), 
    bstr_t("SELECT * FROM __InstanceCreationEvent WITHIN 1 " 
     "WHERE TargetInstance ISA 'Win32_Process'"), 
    WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
    NULL, &pEnumerator); 

if (pEnumerator) 
{ 
    while (true) 
    { 
     _com_ptr_t<IWbemClassObject> pclsObj; 
     _variant_t v1, v2; 
     ULONG ulReturned = 0; 

     pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &ulReturned); 
     pclsObj->Get(_bstr_t(L"TargetInstance"), 0, &v1, 0, 0); 

     // _com_ptr_t::operator&() calls Release() on the current object 
     // if not NULL before then returning the address of the the 
     // interface pointer... 

     _com_ptr_t<IUnknown> str = v1; 
     str->QueryInterface(IID_IWbemClassObject, reinterpret_cast<void**>(&pclsObj)); 
     pclsObj->Get(bstr_t(L"Handle"), 0, &v2, 0, 0); 

     LONG pid{ 0 }; 
     hr = VarI4FromStr(v2.bstrVal, LOCALE_NOUSEROVERRIDE, 409, &pid); 
     Internal::Inject(pid); // It's my code, not relevant here 
    } 
} 
+1

Es gibt auch die handy [IID_PPV_ARGS] (https://msdn.microsoft.com/en-us/library/windows/desktop/ee330727.aspx) Makro, mit dem Sie schreiben können: 'str-> QueryInterface (IID_PPV_ARGS (& pclsObj));' . Es ist nicht nur kürzer, es ist auch sicherer, da Schnittstellen-ID und Zeigertyp garantiert übereinstimmen. – IInspectable