我正在为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的情况下以托管的方式为每个线程指定一个公寓模型吗?
答案 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(),它已经完成了。