2016-10-28 8 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에서 가져 와서 약간 수정했습니다. 그러나 메모리가 누수되고 그 이유는 모르겠습니다. screen1

나이 : MSVC 메모리 프로파일 러를 통해 찾는 것은 우리에게이 사진을 제공 내 관점에서 screen2

을 - 나는 \ 출시 된 모든하지만, 할당이 스크린 샷에 같이 한 번 새로운 이벤트를 발생 클리어했습니다 도착하고 그들은 영원히 머무르고있다.

나는 this question을 찾았지만 동일하게 나타 났지만 답변을받지 못했습니다.

Visual Studio 2015 업데이트 3, 최신 Windows 10 x64 Professional.

+2

당신이 pEnumerator에 릴리스()를 호출합니까? 또한 COM 객체입니다 – Matt

+0

@matt, 시도했으나 도움이되지 않았습니다 – Starl1ght

+0

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

답변

1

str->QueryInterface()으로 전화 할 때 포인터를 미리 지정하고 pclsObj->Release()을 호출하지 않아도됩니다. pclsObj 개체에서 이 반환되고 원래 pclsObj 개체가 누출되면 Release()을 호출하려고합니다.

인터페이스 참조 횟수를 수동으로 관리하지 말고 대신 _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

'str-> QueryInterface (IID_PPV_ARGS (& pclsObj));'라고 쓰여질 수있는 편리한 [IID_PPV_ARGS] (https://msdn.microsoft.com/en-us/library/windows/desktop/ee330727.aspx) . 인터페이스 ID와 포인터 유형이 일치하는 것이 보장되므로 더 짧을뿐 아니라 안전합니다. – IInspectable