我有一个与WMI相关的代码,一旦启动新应用程序就会获得一个事件。 我已经跳过了初始化部分,这里是代码。请注意,一切正常,所有HRESULT都是S_OK。
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内存分析器查看给我们这张图片:
从我的角度来看 - 我已经清除\释放了所有内容,然而,一旦新事件到来并且它们永远存在,分配就像屏幕截图一样。
我发现this question,似乎是相同的,但没有收到回复。
Visual Studio 2015 Update 3,最新的Windows 10 x64 Professional。
答案 0 :(得分:1)
当您致电str->QueryInterface()
时,您将覆盖pclsObj
指针而不事先致电pclsObj->Release()
。您在Release()
返回的pclsObj
对象上调用了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
}
}