在WinForms线程上使用CoInitializeEx

时间:2015-04-01 07:50:51

标签: c# .net multithreading com apartments

我正在为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的示例源代码,我的问题是,在标有CoInitializeEx属性的应用中使用[STAThread]是否有用和/或必要?< / p>

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

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

1 个答案:

答案 0 :(得分:5)

  

每个线程都需要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(),它已经完成了。