2012-08-03 76 views
0

我編寫了一個C++函數,該函數通過WMI查詢獲取USB驅動器的PNPDeviceID並在Win32-Console-Application中對其進行測試。它完美地工作,但是當我將代碼放入CredentialProvider-DLL時,CoInitialize()CoInitializeSecurity()函數失敗,因爲DLL調用進程(Windows CredUI-Subsystem)已經調用該函數。那麼如何讓WMI查詢在該DLL上工作?我需要重置COM安全設置,默認情況下似乎不可行。CredentialProvider DLL中的WMI查詢

下面是函數代碼:

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; 
} 

在此先感謝

回答

1

該解決方案可以把所有的代碼獲得一個USB驅動器的PNPDeviceID到Windows服務。通過命名管道在證書提供者和Windows服務之間建立一個IPC。

P.S.這些方法也是很好的方式,所有「硬」的東西都是在windows服務中完成的(它有更多的功能),而且你的提供者很簡單,這會幫助你避免將來出現問題。

+0

謝謝,但我以不同的方式解決了這個問題。我只是簡單地刪除了'CoInitializeSecurity()'調用(因爲這是全過程設置的)並且使用'CoSetProxyBlanket()'來代替,它可以在特定的COM-Proxy上使用。 但我會保存你的解決方案,以便將來的問題不會那麼容易解決...... – Adrian 2012-08-04 15:20:27

+0

也謝謝你=)你的解決方案也很好,在這種情況下,我沒有想過CoSetProxyBlanket()。 – Apokal 2012-08-05 17:52:04

+0

你能幫我解答我的下一個問題嗎? http://stackoverflow.com/questions/11810046/is-the-pnpdeviceid-unique – Adrian 2012-08-06 11:32:45