QT QFileDialog 创建未知的 COM 对象和安全
QT QFileDialog create unknown COM Object and security
我需要帮助解决这个问题。我想在我的项目中使用 WMI,这样我就可以使用 WQL 从 Windows OS 获取一些数据。
这是我的代码
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;
}
那个代码 运行 每次我调用它时都非常完美。我可以得到我需要的东西(逻辑驱动器列表)。问题是当我调用 QFileDialog
对象然后调用该函数时,该代码将不起作用。我收到 coInitializeSecurity
错误 RPC_E_TOO_LATE
,结果我的 ExecQuery
将失败,错误代码为 0x80041003
(WBEM_E_ACCESS_DENIED)。
我认为 QFileDialog
创建 COM 对象,因为当我调用 QFileDialog
对象时 Aplication Output Tab
(stdout) 中有消息输出。
CoCreateInstance failed ()
CoCreateInstance failed ()
如果我在该函数之前先调用 QFileDialog
对象,这些消息将不会出现,并且该函数仍然无法工作。我通常需要该函数 运行,而不会受到任何 COM 对象的任何干扰。
我的问题:
有什么方法可以检测 QT 创建的 COM 对象吗?
如何知道QT初始化了哪个安全性(CoInitializeSecurity)?
已编辑
阅读 Hans and Daniel 的答案后,我更改了我的代码。所以我第一次把 CoInitializeEx
放在我的应用程序 运行 COINIT_APARTMENTTHREADED
中,然后我初始化 CoInitializeSecurity
,然后擦除所有 CoInitializeEx
,CoInitializeSecurity
,和 'CoUninitialize' 在该函数中。它有效,我可以在打开 QFileDialog
.
后调用该函数
现在,
- 我应该去哪里打电话 'CoUninitialize'?我应该在我的应用程序关闭之前调用它吗?
- 我如何确保我创建的所有 COM 接口(
WMI
和 QFileDialog
)被正确销毁?假设我像在我的代码中一样从 WMI 释放所有接口和枚举,并且对于 QFileDialog
我在堆栈内存中调用它。
CoInitializeSecurity
只应为一个进程调用 一次 。 RPC_E_TOO_LATE
表示已经调用过。将调用移至更早的位置,可能移至流程的初始化部分。
我需要帮助解决这个问题。我想在我的项目中使用 WMI,这样我就可以使用 WQL 从 Windows OS 获取一些数据。 这是我的代码
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;
}
那个代码 运行 每次我调用它时都非常完美。我可以得到我需要的东西(逻辑驱动器列表)。问题是当我调用 QFileDialog
对象然后调用该函数时,该代码将不起作用。我收到 coInitializeSecurity
错误 RPC_E_TOO_LATE
,结果我的 ExecQuery
将失败,错误代码为 0x80041003
(WBEM_E_ACCESS_DENIED)。
我认为 QFileDialog
创建 COM 对象,因为当我调用 QFileDialog
对象时 Aplication Output Tab
(stdout) 中有消息输出。
CoCreateInstance failed ()
CoCreateInstance failed ()
如果我在该函数之前先调用 QFileDialog
对象,这些消息将不会出现,并且该函数仍然无法工作。我通常需要该函数 运行,而不会受到任何 COM 对象的任何干扰。
我的问题:
有什么方法可以检测 QT 创建的 COM 对象吗?
如何知道QT初始化了哪个安全性(CoInitializeSecurity)?
已编辑
阅读 Hans and Daniel 的答案后,我更改了我的代码。所以我第一次把 CoInitializeEx
放在我的应用程序 运行 COINIT_APARTMENTTHREADED
中,然后我初始化 CoInitializeSecurity
,然后擦除所有 CoInitializeEx
,CoInitializeSecurity
,和 'CoUninitialize' 在该函数中。它有效,我可以在打开 QFileDialog
.
现在,
- 我应该去哪里打电话 'CoUninitialize'?我应该在我的应用程序关闭之前调用它吗?
- 我如何确保我创建的所有 COM 接口(
WMI
和QFileDialog
)被正确销毁?假设我像在我的代码中一样从 WMI 释放所有接口和枚举,并且对于QFileDialog
我在堆栈内存中调用它。
CoInitializeSecurity
只应为一个进程调用 一次 。 RPC_E_TOO_LATE
表示已经调用过。将调用移至更早的位置,可能移至流程的初始化部分。