【问题标题】:WMI Query in CredentialProvider DLLCredentialProvider DLL 中的 WMI 查询
【发布时间】:2012-08-01 17:35:11
【问题描述】:

我编写了一个 C++ 函数,该函数通过 WMI 查询获取 USB 驱动器的 PNPDeviceID,并在 Win32-Console-Application 中对其进行了测试。它工作得很好,但是当我将代码放入 CredentialProvider-DLL 时,CoInitialize()CoInitializeSecurity() 函数失败了,因为它们已经被 DLL 调用进程(Windows CredUI-Subsystem)调用了。那么如何使 WMI 查询在该 DLL 上工作?我需要重置 COM 安全设置,默认情况下似乎无法做到这一点。

功能代码如下:

std::wstring GetHardwareID(char driveLetter)
{
std::wstring returnString = L"";
wchar_t volumeAccessPath[] = L"\\\\.\\X:";
volumeAccessPath[4] = driveLetter;

HANDLE deviceHandle = CreateFileW(volumeAccessPath,
    0,                // no access to the drive
    FILE_SHARE_READ | // share mode
    FILE_SHARE_WRITE,
    NULL,             // default security attributes
    OPEN_EXISTING,    // disposition
    0,                // file attributes
    NULL);      // do not copy file attributes

DWORD bytes;
STORAGE_DEVICE_NUMBER  devd;
STORAGE_BUS_TYPE busType = BusTypeUnknown;


if (DeviceIoControl(deviceHandle,
    IOCTL_STORAGE_GET_DEVICE_NUMBER ,
    NULL, 0,
    &devd, sizeof(devd),
    &bytes, NULL))
{
    HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);

    if((FAILED(hRes = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0))))
    {
               return returnString;
            }

    IWbemLocator* pLocator = NULL;
    if(FAILED(hRes = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pLocator))))
    { return returnString;}

    IWbemServices* pService = NULL;

    if(FAILED(hRes = pLocator->ConnectServer(L"root\\CIMV2", NULL, NULL, NULL, WBEM_FLAG_CONNECT_USE_MAX_WAIT, NULL, NULL, &pService)))
    {
        pLocator->Release();
        dbg(convertInt(hRes).c_str());
        return returnString;
    }

    IEnumWbemClassObject* pEnumerator = NULL;
    if(FAILED(hRes = pService->ExecQuery(L"WQL", L"SELECT * FROM Win32_DiskDrive ", WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumerator)))
    {
        pLocator->Release();
        pService->Release();
dbg(convertInt(hRes).c_str());
        return returnString;
    }

    IWbemClassObject* clsObj = NULL;
    int numElems;
    while((hRes = pEnumerator->Next(WBEM_INFINITE, 1, &clsObj, (ULONG*)&numElems)) != WBEM_S_FALSE)
    {
        if(FAILED(hRes))
            break;

        VARIANT vRet;
        VariantInit(&vRet);
        if(SUCCEEDED(clsObj->Get(L"DeviceID", 0, &vRet, NULL, NULL)) && vRet.vt == VT_BSTR)
        {
            bool found = false;
            std::wstring ws(vRet.bstrVal);
            if (ws[17] == '0' + devd.DeviceNumber)
            found = true;
            VariantClear(&vRet);

            if(SUCCEEDED(clsObj->Get(L"PNPDeviceID", 0, &vRet, NULL, NULL)) && vRet.vt == VT_BSTR  && found)
            {
                std::wstring retStr(vRet.bstrVal);
                VariantClear(&vRet);
                std::wstring k(L"&");
                int pos =retStr.rfind(k);
                returnString = retStr.substr(0, pos);
            }
        }

        clsObj->Release();
    }

    pEnumerator->Release();
    pService->Release();
    pLocator->Release();
}
return returnString;
}

提前致谢

【问题讨论】:

    标签: winapi dll wmi


    【解决方案1】:

    解决方案是将用于获取 USB 驱动器的 PNPDeviceID 的所有代码放入 Windows 服务中。并通过命名管道在凭据提供程序和 Windows 服务之间建立 IPC。

    附:这些方法也很好,因为所有“硬”的东西都在 Windows 服务(具有更多功能)中完成,并且您的提供程序轻巧简单,这将帮助您避免将来出现问题。

    【讨论】:

    • 谢谢,但我以不同的方式解决了这个问题。我只需删除CoInitializeSecurity()-call(因为这是在进程范围内设置的)并改用CoSetProxyBlanket(),它可以在特定的COM-Proxy上使用。但我会牢记您的解决方案,以防将来不容易解决的问题......
    • 也谢谢你=)你的解决方案在这种情况下也很好,我没有考虑 CoSetProxyBlanket()。
    • 你能帮我解决下一个问题吗? stackoverflow.com/questions/11810046/is-the-pnpdeviceid-unique
    猜你喜欢
    • 1970-01-01
    • 2016-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-25
    相关资源
    最近更新 更多