У меня есть код, связанный с 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, мы получаем следующую картину:
С моей точки зрения — я все очистил \ отпустил, однако распределения, как на скриншотах, происходят, когда приходят новые события, и они остаются навсегда.
я обнаружил этот вопрос, кажется, что это то же самое, но ответа не получено.
Visual Studio 2015, обновление 3, последняя версия Windows 10 x64 Professional.
Когда вы звоните 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
}
}
Других решений пока нет …