QT QFileDialog create unknown COM Object and security

0

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.
c++
windows
qt
wmi
asked on Stack Overflow Oct 5, 2017 by serius777 • edited Oct 5, 2017 by serius777

1 Answer

0

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.

answered on Stack Overflow Oct 5, 2017 by Daniel Sęk

User contributions licensed under CC BY-SA 3.0