在WinForms的线程使用的CoInitializeEx线程、WinForms、CoInitializeEx

2023-09-03 06:50:20 作者:扯不断的红尘//

我工作的SDK的数码单反相机,它具有以下说明:

  

在开发Windows应用程序在创建应用程序的注意事项   Windows下的运行,一个COM初始化需要对每个   线程以便从一个线程比主其他访问照相机   线。要创建一个用户线程,并从该访问摄像头   线程,一定要执行的CoInitializeEx(NULL,   COINIT_APARTMENTTHREADED)在螺纹的开始和   CoUnInitialize()结尾。样品code如下所示。这是   同一控制时EdsVolumeRef或EdsDirectoryItemRef的对象   另一个线程,不仅仅是EdsCameraRef。

 无效TakePicture(EdsCameraRef摄像头)
{
    //执行的被另一个线程
    HANDLE hThread =(HANDLE)_beginthread(ThreadProc的,0,摄像头);
    //阻止,直到完成
    :: WaitForSingleObject的(hThread,INFINITE);
}

无效ThreadProc的(无效* lParam的)
{
    EdsCameraRef摄像头=(EdsCameraRef)lParam的;
    过CoInitializeEx(NULL,COINIT_APARTMENTTHREADED);
    EdsSendCommand(照相机,kEdsCameraCommand_TakePicture,0);
    CoUninitialize();
    _endthread();
}
 

我的应用程序是一个C#的WinForms应用程序,通常情况下,我用的是托管线程类和Control.Invoke功能,以避免交叉线的问题。

由于我没有示例源$ C ​​$ C在C#中消耗的SDK,我的问题是,它是有用的和/或需要使用的CoInitializeEx 在应用程序打上 [STAThread] 属性?

我还没有碰到过的场景中我需要有我的应用程序创建一个新的公寓线程所以一些有识之士将有助于了解线程模型更好。

更新:阅读一些有关公寓和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如果正确使用。

这也是你的code段是做错了,它是非法的启动STA线程,而不是泵消息循环。你会摆脱它意外。有时候,你不和code会死锁或以其他方式失败,如不加预期的事件。由于供应商认可它做错了,它可能并不重要位置。但是,如果你注意到的僵局,那么你会知道去哪里找。

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

性能全面提升 多路至强Nehalem EX解读

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

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();
}

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

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.

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?

解决方案

a COM initialization is required for each thread

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.

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.

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.

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