Qt中使用WMI时遇到的那些坑儿

之前都很顺利,稳稳地,根据msdn的文档简单修改就可以了。

Windows客户端开发–WMI技术介绍

Windows客户端开发–使用WMI获取显卡详细信息(win32控制台程序)

但是,可但是,当我们把wmi用于qt中时,一个接一个的坑儿就来了。

CoInitializeEx
在GUI程序中,不再是这样:

hres = CoInitializeEx(0, COINIT_MULTITHREADED);

改成

hres = CoInitializeEx(0, COINIT_APARTMENTTHREADED); 

MFC中存在类似的问题:

An MFC application uses a lot of thread local storage to store thread state information and to process state information. Therefore, an MFC application is not compatible with a free threaded programming model. For example, if you write an application that displays a user interface (UI) and that also uses some remote Component Object Model (COM) objects, during any method calls to the remote COM objects, the UI may stop responding. This behavior occurs because the UI thread that you initialize as an MTA thread by using the CoInitializeEx(…, COINIT_MULTITHREADED) method makes blocking Remote Procedure Calls (RPCs) to another COM apartment. While the UI thread waits for the RPC response message, any window messages that are posted to the queue of the UI thread are accumulated. Therefore, windows that were created by the UI thread may stop responding. This behavior may cause end users to prematurely quit the application.

CoInitialize与CoInitializeEx的区别:
CoInitialize指明以单线程方式创建。
CoInitializeEx可以指定COINIT_MULTITHREADED以多线程方式创建。
创建单线程方式的COM服务器时不用考虑串行化问题,多线程COM服务器就要考虑。
在使用中,使用CoInitialize创建可使对象直接与线程连接,得到最高的性能。创建多线程对象可以直接接收所有线程的调用,不必像单线程那样需要消息排队,但却需要COM创建线程间汇集代理,这样访问效率不高。

CoInitializeSecurity返回RPC_E_TOO_LATE也是正确
你会发现CoInitializeSecurity返回的不是想要的,是一个特别大的负数,但是转换为十六进制为0x80010119

这时候发现0x80010119就是RPC_E_TOO_LATE
因此我们需要修改代码:

    if (FAILED(hres))
    {
        qDebug() << "Failed to initialize security. "
                 << "Error code = 0x"
                 << hex << hres << endl;
        CoUninitialize();
        return "";
    }

修改为:

    if ((hres != RPC_E_TOO_LATE) && FAILED(hres))
    {
        qDebug() << "Failed to initialize security. "
                 << "Error code = 0x"
                 << hex << hres << endl;
        CoUninitialize();
        return "";
    }

调用函数ExecQuery时,编译报错
错误为:
error: undefined reference to `_com_util::ConvertStringToBSTR(char const*)@4

因此我们需要正确的方式从QString转到BSTR,因此修改代码:
由:

    hres = pSvc->ExecQuery(
    bstr_t("WQL"),
    bstr_t("SELECT * FROM Win32_VideoController"),
    WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
    NULL,
    &pEnumerator);

改为:

    BSTR sql = SysAllocString(L"SELECT * FROM Win32_VideoControlle");
    BSTR wql = SysAllocString(L"WQL");

    hres = pSvc->ExecQuery(wql,
                           sql,
                           WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
                           NULL,
                           &pEnumerator);

这里用到了SysAllocString
SysAllocString函数说明:
This function allocates a new string and copies the passed string into it.

Next函数的返回值正确,但是uReturn等于0
到最后,我们使用了Next进行查询,但是发现该函数的返回值hres是正确的,uReturn始终为0

hres = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);

完全是自己马虎造成,不知道细心的您发现了没有上面的代码:

BSTR sql = SysAllocString(L"SELECT * FROM Win32_VideoControlle");

再自信看一下,是不是SQL语句的拼写错误。。。。。

尼玛,果然,Win32_VideoControlle错误了,应该是Win32_VideoController

修正为:

BSTR sql = SysAllocString(L"SELECT * FROM Win32_VideoController");

你可能感兴趣的:(windows,qt,wmi)