简体   繁体   中英

QT QFileDialog create unknown COM Object and security

I need help for this issue. i want to uses WMI in my project, so that i can use WQL to get some data fom Windows OS. Here is my code

QList<Drive> SystemDrive::getSystemDrive()
{
    QList<Drive> list;

    #ifdef _WIN64
    HRESULT hRes;
    hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED );
    if(hRes == RPC_E_CHANGED_MODE)
    {
        //qDebug() << "Unable to launch COM: 0x" << QString::number(hRes, 16) << endl;
        //OleUninitialize();
        CoUninitialize();
        hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
        if(FAILED(hRes))
        {
            qDebug() << "Unable to launch COM: 0x" << QString::number(hRes, 16);
        }
        //return 1;
    }
    qDebug() << "CoInitializeEx result 0x" << QString::number(hRes, 16);

    if((FAILED(hRes = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0))))
    {
        qDebug() << "Unable to initialize security: 0x" << QString::number(hRes, 16);
    }
    IWbemLocator* pLocator = NULL;
    if(FAILED(hRes = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pLocator))))
    {
        qDebug() << "Unable to create a WbemLocator: " << std::hex << hRes << endl;
        //return 1;
    }

    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();
        qDebug() << "Unable to connect to \"CIMV2\": " << std::hex << hRes << endl;
        //return 1;
    }

    IEnumWbemClassObject* pEnumerator = NULL;
    if(FAILED(hRes = pService->ExecQuery(L"WQL", L"SELECT * FROM Win32_LogicalDisk", WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumerator)))
    {
        pLocator->Release();
        pService->Release();
        qDebug() << "Unable to retrive Logical Disk: " << QString::number(hRes, 16) << endl;
        //return 1;
    }

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

        Drive *tmpDrive;

        VARIANT vRet;
        VariantInit(&vRet);
        if(SUCCEEDED(clsObj->Get(L"Caption", 0, &vRet, NULL, NULL)) && vRet.vt == VT_BSTR)
        {
            tmpDrive = new Drive(QString((QChar*) vRet.bstrVal, SysStringLen(vRet.bstrVal)));
            tmpDrive->setType(Drive::DRIVE_TYPE::DRIVE_LOGICAL);
            VariantClear(&vRet);
        }
        VariantInit(&vRet);
        if(SUCCEEDED(clsObj->Get(L"DeviceID", 0, &vRet, NULL, NULL)) && vRet.vt == VT_BSTR)
        {
            QString id = "\\\\.\\";

            id.append(QString((QChar*) vRet.bstrVal, SysStringLen(vRet.bstrVal)));
            tmpDrive->setId(id);
            VariantClear(&vRet);
        }

        clsObj->Release();
        list.append(*tmpDrive);
    }

     pEnumerator->Release();
     pService->Release();
     pLocator->Release();
     CoUninitialize();
#endif

     return list;
}

that code run perfectly every time i call it. I can get what i need (List of Logical drive). The problem is when i call QFileDialog object and then call that function, that code will not work. I get error for coInitializeSecurity with error RPC_E_TOO_LATE and as result my ExecQuery will fail with error code 0x80041003 (WBEM_E_ACCESS_DENIED).

I think QFileDialog create COM object because there is mesage output in Aplication Output Tab (stdout) when I call QFileDialog object.

CoCreateInstance failed ()
CoCreateInstance failed ()

If I Call QFileDialog object first before that function, these message will not occur, and that function still not work. I need that function run normally without any interuption from any COM objects.

My questions :

  1. Are there any way to detect what COM object that created by QT?

  2. How can I know which security that initialized (CoInitializeSecurity) by QT?

EDITED After read answers from Hans and Daniel , I change my code. So I put CoInitializeEx in first time my app running with COINIT_APARTMENTTHREADED , after that I initialize CoInitializeSecurity , and then erase all CoInitializeEx , CoInitializeSecurity , and 'CoUninitialize' in that function. It works, i can call that function after opening QFileDialog .

Now,

  1. Where should I call 'CoUninitialize'? should I call it before my app closed?
  2. how can I assure that all COM interfaces that I have created ( WMI and QFileDialog ) destroyed properly? asume that I release all interface and enumeration from WMI like in my code, and for QFileDialog I call it in stack memory.

CoInitializeSecurity should be called only once for a process. RPC_E_TOO_LATE means that it has already been called. Move call earlier, probably into initialization section of your process.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM