Reputation: 49
I have written the code below to listen to creation and deletion events of when specific applications are created/deleted, and also retrieve their process name
, id
, command line
, using WMI, NotificationQuery, ExecQuery.
I noted that WmiPrvSE.exe
is using "too much" CPU when my program is "idling", it's using like 1.5-2%.
My current code is:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <comdef.h>
#include <Wbemidl.h>
#include <windows.h>
#pragma comment(lib, "wbemuuid.lib")
enum EventType { QUERY, PROCESS_CREATION, PROCESS_DELETION };
class EventSink : public IWbemObjectSink
{
LONG m_lRef = 0;
public:
EventSink(){}
virtual ULONG STDMETHODCALLTYPE AddRef()
{
return InterlockedIncrement(&m_lRef);
}
virtual ULONG STDMETHODCALLTYPE Release()
{
LONG lRef = InterlockedDecrement(&m_lRef);
if(lRef == 0)
delete this;
return lRef;
}
void event(EventType eventType, const std::vector<IWbemClassObject*>& objList)
{
for (IWbemClassObject* obj : objList)
{
DWORD processId = 0;
std::wstring processName = L"";
std::wstring commandLine = L"";
VARIANT vtProp;
HRESULT hr = obj->Get(L"Name", 0, &vtProp, 0, 0);
if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR)
processName = vtProp.bstrVal;
VariantClear(&vtProp);
hr = obj->Get(L"ProcessId", 0, &vtProp, 0, 0);
if (SUCCEEDED(hr) && vtProp.vt == VT_I4)
processId = vtProp.uintVal;
VariantClear(&vtProp);
if (eventType == QUERY || eventType == PROCESS_CREATION)
{
hr = obj->Get(L"CommandLine", 0, &vtProp, 0, 0);
if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR)
commandLine = vtProp.bstrVal;
VariantClear(&vtProp);
//...
}
else if (eventType == PROCESS_DELETION)
{
//...
}
obj->Release();
}
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv)
{
if (riid == IID_IUnknown || riid == IID_IWbemObjectSink)
{
*ppv = (IWbemObjectSink *) this;
AddRef();
return WBEM_S_NO_ERROR;
}
else return E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE Indicate(LONG lObjectCount, IWbemClassObject __RPC_FAR *__RPC_FAR *apObjArray)
{
std::map<EventType, std::vector<IWbemClassObject*>> eventMap;
for (int i = 0; i < lObjectCount; i++)
{
VARIANT vtClass;
HRESULT hr = apObjArray[i]->Get(L"__CLASS", 0, &vtClass, 0, 0);
if (!SUCCEEDED(hr))
continue;
bool creationEvent = (wcscmp(vtClass.bstrVal, L"__InstanceCreationEvent") == 0);
VariantClear(&vtClass);
VARIANT vtTargetInstance;
hr = apObjArray[i]->Get(L"TargetInstance", 0, &vtTargetInstance, 0, 0);
if (!SUCCEEDED(hr) || vtTargetInstance.vt != VT_UNKNOWN)
continue;
IWbemClassObject* pTargetInstance = NULL;
hr = vtTargetInstance.punkVal->QueryInterface(IID_IWbemClassObject, (void**)&pTargetInstance);
if (!SUCCEEDED(hr))
continue;
VariantClear(&vtTargetInstance);
eventMap[creationEvent ? PROCESS_CREATION : PROCESS_DELETION].emplace_back(pTargetInstance);
}
for (auto it = eventMap.begin(); it != eventMap.end(); ++it)
{
event(it->first, it->second);
}
return WBEM_S_NO_ERROR;
}
HRESULT STDMETHODCALLTYPE SetStatus(LONG lFlags, HRESULT hResult, BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam)
{
return WBEM_S_NO_ERROR;
}
};
class ProcessMonitor
{
public:
ProcessMonitor()
{
HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED);
IWbemLocator* pLoc = NULL;
hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc);
if (FAILED(hres))
{
std::cout << "Failed to create IWbemLocator object. Err code = 0x" << std::hex << hres << std::endl;
CoUninitialize();
return;
}
pSvc = NULL;
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // WMI namespace
NULL, // User name
NULL, // User password
0, // Locale
NULL, // Security flags
0, // Authority
0, // Context object
&pSvc // IWbemServices proxy
);
if (FAILED(hres) || !pSvc || !pLoc)
{
std::cout << "Could not connect. Error code = 0x" << std::hex << hres << std::endl;
CoUninitialize();
return;
}
hres = CoSetProxyBlanket(
pSvc, // the proxy to set
RPC_C_AUTHN_WINNT, // authentication service
RPC_C_AUTHZ_NONE, // authorization service
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // authentication level
RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
std::cout << "Could not set proxy blanket. Error code = 0x"
<< std::hex << hres << std::endl;
CoUninitialize();
return;
}
pSink = new EventSink;
pSink->AddRef();
}
void query()
{
IEnumWbemClassObject* pEnumerator = NULL;
pSvc->ExecQuery(bstr_t("WQL"), bstr_t(wmiQuery.c_str()), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
IWbemClassObject* pclsObj = NULL;
ULONG uReturn = 0;
std::vector<IWbemClassObject*> objList;
while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (0 == uReturn)
break;
objList.emplace_back(pclsObj);
}
pSink->event(QUERY, objList);
pEnumerator->Release();
}
void updateQuery(const std::wstring& processName)
{
processList.push_back(processName);
wmiQuery = L"SELECT Name, CommandLine, ProcessId FROM Win32_Process WHERE NAME = '";
processCreationQuery = L"SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA "
L"'Win32_Process' AND (TargetInstance.Name = '"; // notepad.exe' OR TargetInstance.Name = 'CalculatorApp.exe')";
processDeletionQuery = L"SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA "
L"'Win32_Process' AND (TargetInstance.Name = '"; // notepad.exe' OR TargetInstance.Name = 'CalculatorApp.exe')";
for (size_t i = 0; i < processList.size(); ++i)
{
processCreationQuery += processList[i] + L"'";
processDeletionQuery += processList[i] + L"'";
wmiQuery += processList[i] + L"'";
if (i < processList.size() - 1)
{
wmiQuery += L" OR NAME = '";
processCreationQuery += L" OR TargetInstance.Name = '";
processDeletionQuery += L" OR TargetInstance.Name = '";
}
else if (i == processList.size() - 1)
{
processCreationQuery += L")";
processDeletionQuery += L")";
}
}
pSvc->CancelAsyncCall(pSink);
BSTR queryLanguage = SysAllocString(L"WQL");
// Query for process creation
HRESULT hres = pSvc->ExecNotificationQueryAsync(
queryLanguage,
bstr_t(processCreationQuery.c_str()),
WBEM_FLAG_SEND_STATUS,
NULL,
pSink);
if (FAILED(hres))
{
std::wcout << L"ExecNotificationQueryAsync failed with = 0x" << std::hex << hres << std::endl;
CoUninitialize();
return;
}
// Query for process deletion
hres = pSvc->ExecNotificationQueryAsync(
queryLanguage,
bstr_t(processDeletionQuery.c_str()),
WBEM_FLAG_SEND_STATUS,
NULL,
pSink);
if (FAILED(hres))
{
std::wcout << L"ExecNotificationQueryAsync failed with = 0x" << std::hex << hres << std::endl;
CoUninitialize();
return;
}
}
private:
IWbemServices* pSvc;
EventSink* pSink;
std::wstring wmiQuery;
std::wstring processCreationQuery;
std::wstring processDeletionQuery;
std::vector<std::wstring> processList;
};
int main()
{
ProcessMonitor pm;
pm.updateQuery(L"notepad.exe"); // At this point its already listening to create/deletion events
pm.query(); // The call to query will be used to collect the processes running before the application started
std::cin.get(); // Idle, but WmiPrvSE continues using high cpu
}
After pm.query()
the process is "idling" but the CPU usage of WmiPrvSE.exe
continues high, and when i close my process it also continues high, i need to reboot the pc to it "reset".
It's calling the query only once and then listening to the events, am I leaking something?
I also noted on Event Viewer > Application and Services Logs > Windows WMI-Activity > Operational
that it is storing the following errors relative to my process:
Id = {00000000-0000-0000-0000-000000000000}; ClientMachine = DESKTOP-...; User = DESKTOP-...; ClientProcessId = 20240; Component = Unknown; Operation = Start IWbemServices::ExecNotificationQuery - ROOT\CIMV2 : SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process' AND (TargetInstance.Name = 'notepad.exe'); ResultCode = 0x80041032; PossibleCause = Unknown
Id = {00000000-0000-0000-0000-000000000000}; ClientMachine = DESKTOP-...; User = DESKTOP-...; ClientProcessId = 20240; Component = Core; Operation = Start IWbemServices::ExecNotificationQuery - ROOT\CIMV2 : SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process' AND (TargetInstance.Name = 'notepad.exe'); ResultCode = 0x800706BA; PossibleCause = Could not send status to client
Upvotes: 1
Views: 102