WMI IWbemServices::ExecMethod 在 Win32API 上运行缓慢

问题描述 投票:0回答:1

我正在尝试获取 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 是一个很好(且相对较快)的解决方案。

c++ winapi process wmi
1个回答
0
投票

正如评论所说,流程令牌包含您想要的信息。使用 TokenUser,您将收到一个 TOKEN_USER 结构,其中包含令牌的用户帐户。有关代码示例,请参见答案

© www.soinside.com 2019 - 2024. All rights reserved.