我正在尝试获取 Windows 上所有正在运行的进程的信息。通过 ExecMethod 我试图获取进程所有者的用户名和域。我是这样做的:
HRESULT hres;
BSTR MethodName = SysAllocString(L"GetOwner");
BSTR ClassName = SysAllocString(L"Win32_Process");
// get the object containing our desired method
IWbemClassObject* pClass = NULL;
hres = m_pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);
if (FAILED(hres))
{
printf("GetObject hres = %08x\n", hres);
}
// get the desired method
// in our case, we only need pmethodGetOwner since GetOwner really only has output
IWbemClassObject* pMethod_GetOwner = NULL;
hres = pClass->GetMethod(MethodName, 0, NULL, &pMethod_GetOwner);
if (FAILED(hres))
{
printf("GetMethod hres = %08x\n", hres);
}
// spawn the instance of the method
IWbemClassObject* pInInst = NULL;
hres = pMethod_GetOwner->SpawnInstance(0, &pInInst);
if (FAILED(hres))
{
printf("SpawnInstance hres = %08x\n", hres);
}
IEnumWbemClassObject* pEnumerator = NULL;
BSTR wql = SysAllocString(L"WQL");
BSTR query = SysAllocString(L"SELECT * FROM Win32_Process");
hres = m_pSvc->ExecQuery( wql, query,
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
SysReleaseString(wql);
SysReleaseString(query);
if (FAILED(hres))
{
qDebug() << "ExecQuery failed" << " Error code = 0x" << std::hex << hres << '\n';
qDebug()<< _com_error(hres).ErrorMessage() << '\n';
return std::vector<DCProcessInfo>(); // Program has failed.
}
// Get the data from the WQL sentence
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
std::vector<DCProcessInfo> process_list{};
double seconds{};
while (pEnumerator)
{
DCProcessInfo proc_info;
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if(0 == uReturn || FAILED(hr))
break;
VARIANT vtProp;
hr = pclsObj->Get(L"Name",0,&vtProp,NULL,NULL);
if(SUCCEEDED(hr))
proc_info.name = QString::fromWCharArray(vtProp.bstrVal);
VariantClear(&vtProp);
hr = pclsObj->Get(L"ProcessId",0,&vtProp,NULL,NULL);
if(SUCCEEDED(hr))
proc_info.pid = vtProp.uintVal;
VariantClear(&vtProp);
hr = pclsObj->Get(L"CreationDate",0,&vtProp,NULL,NULL);
if(SUCCEEDED(hr))
proc_info.creation_date = tools::fromBSTRToDateTime(vtProp.bstrVal);
VariantClear(&vtProp);
hr = pclsObj->Get(L"ExecutablePath",0,&vtProp,NULL,NULL);
if(SUCCEEDED(hr))
proc_info.file_path = QString::fromWCharArray(vtProp.bstrVal);
VariantClear(&vtProp);
hr = pclsObj->Get(L"CommandLine",0,&vtProp,NULL,NULL);
if(SUCCEEDED(hr))
proc_info.command_line = QString::fromWCharArray(vtProp.bstrVal);
VariantClear(&vtProp);
// std::pair<QString,QString> user_domain = get_process_user_domain(pclsObj);
// proc_info.owner_user = user_domain.first;
// proc_info.owner_domain = user_domain.second;
VARIANT vtVal;
std::pair<QString,QString> user_dom{};
hr =pclsObj->Get(L"__PATH",0,&vtVal,0,0);
if (FAILED(hr))
{
qDebug()<<"get_process_user_domain() failed Get(__PATH)";
pClass->Release();
pMethod_GetOwner->Release();
pInInst->Release();
//return user_dom;
}
std::chrono::time_point<std::chrono::steady_clock> start = std::chrono::steady_clock::now();
hr = m_pSvc->ExecMethod(vtVal.bstrVal, MethodName, 0, NULL, NULL, &pMethod_GetOwner, NULL);
if (FAILED(hr))
{
qDebug()<<"get_process_user_domain() failed ExecMethod against" << QString::fromWCharArray(V_BSTR(&vtVal));;
pclsObj->Release();
continue;
}
VariantClear(&vtVal);
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
qDebug()<<elapsed_seconds.count();
hr = pMethod_GetOwner->Get(L"User", 0, &vtVal, NULL, 0);
if (FAILED(hr))
{
qDebug()<<"get_process_user_domain() failed Get(User)";
pClass->Release();
pMethod_GetOwner->Release();
pInInst->Release();
//return user_dom;
}
else
proc_info.owner_user = QString::fromWCharArray(vtVal.bstrVal);
VariantClear(&vtVal);
hr = pMethod_GetOwner->Get(L"Domain", 0, &vtVal, NULL, 0);
if (FAILED(hr))
{
qDebug()<<"get_process_user_domain() failed Get(Domain)";
//return user_dom;
}
else
proc_info.owner_domain = QString::fromWCharArray(vtVal.bstrVal);
VariantClear(&vtVal);
process_list.push_back(proc_info);
pclsObj->Release();
pclsObj=NULL;
}
qDebug()<<"time passed:"<<seconds;
pClass->Release();
pMethod_GetOwner->Release();
pInInst->Release();
return process_list;
问题是 ExecMethod 非常慢(每次调用大约 0.2 秒,当你调用它 200 次时非常慢)。我想问问也许我做错了什么或者它应该那么慢?如果它应该那么慢,还有其他选择吗?
我试图通过 CreateToolhelp32Snapshot 枚举我的进程,但它没有足够的信息。因此,在我尝试调用 GetOwner 方法之前,WMI 是一个很好(且相对较快)的解决方案。
正如评论所说,流程令牌包含您想要的信息。使用 TokenUser,您将收到一个 TOKEN_USER 结构,其中包含令牌的用户帐户。有关代码示例,请参见答案。