在WinForms线程上使用CoInitializeEx

我正在为DSLR相机制作SDK,其中包含以下说明:

开发Windows应用程序的注意事项创建在Windows下运行的应用程序时,每个线程都需要进行COM初始化,以便从主线程以外的线程访问摄像机。 要创建用户线程并从该线程访问摄像机,请确保在线程的开头执行CoInitializeEx(NULL,COINIT_APARTMENTTHREADED),最后执行CoUnInitialize()。 示例代码如下所示。 从另一个线程控制EdsVolumeRef或EdsDirectoryItemRef对象时,这是相同的,而不仅仅是EdsCameraRef。

void TakePicture(EdsCameraRef camera) { // Executed by another thread HANDLE hThread = (HANDLE)_beginthread(threadProc, 0, camera); // Block until finished ::WaitForSingleObject( hThread, INFINITE ); } void threadProc(void* lParam) { EdsCameraRef camera = (EdsCameraRef)lParam; CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ); EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0); CoUninitialize(); _endthread(); } 

我的应用程序是一个C#WinForms应用程序,通常,我使用托管线程类和Control.Invoke函数来避免跨线程问题。

由于我在C#中没有使用SDK的示例源代码,我的问题是,在标有[STAThread]属性的应用程序中使用CoInitializeEx是否有用和/或必要?

我没有遇到一个场景,我需要让我的应用程序为线程创建一个新的公寓,所以一些洞察力将有助于更好地理解线程模型。

更新:在阅读了更多关于公寓和COM之后,它开始有所了解。 现在我想知道.NET托管线程类默认是什么,我们可以以托管的方式为每个线程指定一个没有P / Invoke的公寓模型吗?

每个线程都需要COM初始化

是的,坚如磐石的要求。 因此,CLR可以自动执行此操作,而无需您提供帮助。 每个.NET线程在开始运行之前都调用了CoInitializeEx()。

CLR需要知道要传递给CoInitializeEx()的参数,在STA和MTA之间进行选择。 对于Winforms程序的启动线程,它由Program.cs中Main()方法的[STAThread]属性决定。 它必须是STA,对显示UI的线程的硬性要求。 对于您自己开始的任何线程,它由您对Thread.SetApartmentState()的调用决定,默认为MTA。 对于任何线程池线程,如BackgroundWorker或Task或QUWI使用的线程,它始终是MTA并且无法更改。 如果正确使用,这种线程的自动结果永远不能正确支持STA。

这也是您的代码片段出错的原因,启动STA线程并且不抽取消息循环是非法的。 你偶然会逃脱它。 有时你不这样做,代码会以其他方式死锁或失败,比如不提出预期的事件。 由于供应商认可它做错了,这可能无关紧要。 但如果你注意到死锁,那么你就知道在哪里看。

长话短说,你不能自己调用​​CoInitializeEx(),它已经完成了。