5

我正在为具有以下说明的 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]

我没有遇到过需要让我的应用程序为线程创建一个新单元的情况,这样一些见解将有助于更好地理解线程模型。

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

4

1 回答 1

6

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

于 2015-04-01T09:40:08.903 回答