2016-10-28 56 views
-1

我有一個WMI相關的代碼,一旦啓動新應用程序,就會得到一個事件。 我跳過了初始化部分,這裏是代碼。請注意,一切正常,所有HRESULT都是S_OK。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(); 
} 

此代碼取自MSDN並稍作修改。但是,它泄漏了內存,我不知道爲什麼。通過MSVC內存分析器展望爲我們提供了這樣的畫面: screen1

或本: screen2

從我的觀點 - 我已經清理\發佈的一切,但是,分配,就像截圖發生一次新的事件到達並且他們永遠留下。

我找到了this question,它看起來是一樣的,但沒有收到答覆。

Visual Studio 2015 Update 3,最新的Windows 10 x64 Professional。

+2

你呼籲pEnumerator發行()?這也是COM對象 – Matt

+0

@matt,我試過了,沒幫助 – Starl1ght

+0

試試這個工具DebugDiag:https://www.microsoft.com/en-us/download/details.aspx?id=49924 – Matt

回答

1

當您撥打str->QueryInterface()時,您將覆蓋pclsObj指針,而不預先撥打pclsObj->Release()。您在pclsObj對象上調用Release()對象,即QueryInterface()返回,並泄漏原始pclsObj對象。

您應該停止手動管理接口引用計數並使用_com_ptr_t包裝代替。

原來pclsObj從哪裏來?看起來您錯過了撥打pEnumerator->Next()的電話。

嘗試更多的東西像這樣的,而不是(處理略去了錯誤):

_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 
    } 
} 

或者:

_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

還有方便[IID_PPV_ARGS](https://msdn.microsoft.com/en-us/library/windows/desktop/ee330727.aspx)宏,它允許你寫:'str-> QueryInterface(IID_PPV_ARGS(&pclsObj));' 。它不僅更短,而且更安全,因爲接口ID和指針類型保證匹配。 – IInspectable