在 WinForms 线程上使用 CoInitializeEx [英] Using CoInitializeEx on WinForms threads

查看:13
本文介绍了在 WinForms 线程上使用 CoInitializeEx的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为具有以下说明的 DSLR 相机开发 SDK:

I am working an SDK for a DSLR camera which has the following instructions:

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

Notes on Developing Windows Applications When creating applications that run under Windows, a COM initialization is required for each thread in order to access a camera from a thread other than the main thread. To create a user thread and access the camera from that thread, be sure to execute CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ) at the start of the thread and CoUnInitialize() at the end. Sample code is shown below. This is the same when controlling EdsVolumeRef or EdsDirectoryItemRef objects from another thread, not just with 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 函数来避免跨线程问题.

My application is a C# WinForms app and normally, I use the managed thread class and Control.Invoke functions to avoid cross-thread issues.

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

Since I do not have sample source code in C# for consuming the SDK, my question is, is it useful and/or necessary to use CoInitializeEx in an app marked with the [STAThread] attribute?

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

I have not come across a scenario were I would need to have my app create a new apartment for threads so some insight would be helpful to understand threading models better.

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

UPDATE: After reading some more about apartments and COM, it is beginning to make some sense. Now I'm wondering what the .NET managed thread class defaults to and can we specify an apartment model in a managed way to each thread without P/Invoke?

推荐答案

每个线程都需要进行 COM 初始化

a COM initialization is required for each thread

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

Yes, rock-hard requirement. So much so that the CLR does this automatically without you having to help. Every .NET thread has CoInitializeEx() called before it starts running.

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

The CLR needs to know what argument to pass to CoInitializeEx(), selecting between STA and MTA. For the startup thread of your Winforms program it is determined by the [STAThread] attribute on your Main() method in Program.cs. It must be STA, a hard requirement for threads that display UI. For any thread that you start yourself it is determined by your call to Thread.SetApartmentState(), default is MTA. For any thread-pool thread, like the one used by BackgroundWorker or Task or QUWI, it is always MTA and cannot be changed. An automatic consequence of such a thread never being able properly support STA if it is used correctly.

这也是您的代码片段做错的地方,启动 STA 线程而不泵送消息循环是非法的.你往往会意外地逃脱它.有时你不这样做,代码会以其他方式死锁或失败,比如不引发预期的事件.由于供应商认可它做错了,所以这里可能无关紧要.但是,如果您注意到死锁,那么您就会知道该往哪里看.

Which is also what your code snippet is doing wrong, it is illegal to start an STA thread and not pump a message loop. You tend to get away with it by accident. Sometimes you do not and code will deadlock or fail in other ways, like not raising expected events. Since the vendor sanctioned it doing wrong, it probably does not matter here. But if you ever notice deadlock then you'd know where to look.

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

Long story short, you must not call CoInitializeEx() yourself, it was already done.

这篇关于在 WinForms 线程上使用 CoInitializeEx的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆