获取相机名称列表的函数如下:
std::vector<std::string> getCameraNames() {
std::vector<std::string> cameraNames;
HRESULT hr;
/*HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr)) {
std::cerr << "Error initializing COM library." << std::endl;
return cameraNames;
}*/
ICreateDevEnum* pDevEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
if (SUCCEEDED(hr)) {
IEnumMoniker* pEnum = NULL;
hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
if (hr == S_OK) {
IMoniker* pMoniker = NULL;
while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
IPropertyBag* pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
if (FAILED(hr)) {
pMoniker->Release();
continue;
}
VARIANT var;
VariantInit(&var);
// Get description or friendly name.
hr = pPropBag->Read(L"Description", &var, 0);
if (FAILED(hr)) {
hr = pPropBag->Read(L"FriendlyName", &var, 0);
}
if (SUCCEEDED(hr)) {
// Convert BSTR to std::string and add it to the cameraNames vector.
char* bstr = _com_util::ConvertBSTRToString(var.bstrVal);
cameraNames.push_back(bstr);
delete[] bstr;
VariantClear(&var);
}
pPropBag->Release();
pMoniker->Release();
}
pEnum->Release();
}
pDevEnum->Release();
}
//CoUninitialize();
return cameraNames;
}
封装的dll中有该函数,mfc,自己测试时正常,其他人使用时却异常,分析原因后是自己使用时是在主线程中调用,而其他人使用时是在其他线程中调用。com组件的初始化有两种模式:
COINIT_APARTMENTTHREADED
:初始化为单线程公寓模型。COINIT_MULTITHREADED
:初始化为多线程模型。
当使用MFC (Microsoft Foundation Class Library) 时,MFC本身会为主线程进行COM初始化。因此,在MFC应用程序的主线程中,可能会发现即使不显式调用CoInitializeEx
或CoInitialize
,某些COM相关操作(如CoCreateInstance
)也可能成功。
-
线程模型冲突:MFC默认使用单线程公寓(STA)模型初始化COM。如果要创建的COM对象需要多线程模型(MTA),那么
CoCreateInstance
会失败。同样,如果在STA线程中创建了一个对象,而此对象只在MTA中有效,那么也可能会遇到问题。 -
其他线程:在MFC应用程序中,只有主线程默认初始化了COM。如果在后台线程中执行COM操作而没有显式初始化COM,那么这些操作可能会失败。
-
多次初始化:如果在同一个线程中多次调用
CoInitializeEx
或CoInitialize
并指定不同的线程模型,可能会导致行为异常。 -
MFC状态:MFC提供了
AfxOleInit
函数,该函数初始化COM并将线程设置为STA模式。如果此函数未被调用或失败,那么可能会影响COM操作。
因此,如果是在其他线程种调用dll,就会导致失败。
--------------------------------------------------------------------------------------------------------------------------------
COM定义了两种主要的公寓模型:
-
单线程公寓(STA):
- 在STA中,每个线程都有自己的公寓。
- STA对象必须始终在创建它的那个线程上访问。这意味着任何其他线程想要与STA对象交互,都必须通过某种消息传递机制将操作委托给那个线程。
- 这为某些操作提供了序列化,特别是在处理用户界面元素(如Windows Forms或其他UI组件)时,通常只能在特定线程上进行修改。
- COM使用Windows消息循环来跨线程传递方法调用。
-
多线程公寓(MTA):
- MTA可以由多个线程共享。
- 在MTA中创建的COM对象必须是线程安全的,因为多个线程可能会同时访问它。
当说“使用STA模型初始化COM”时,意思是正在设置线程以使用单线程公寓模型。这意味着该线程将拥有自己的公寓,并且在该线程上创建的所有COM对象都将按照STA规则运行。
通常,如果一个应用程序或线程需要与UI交互或依赖于某些只能在STA模型中运行的COM组件,那么它会使用STA模型。相反,如果性能是主要关注点,并且对象是线程安全的,那么可以选择MTA模型。