在.NET中与COM交互之前,我需要调用CoInitialize吗? [英] Do i need to call CoInitialize before interacting with COM in .NET?

查看:132
本文介绍了在.NET中与COM交互之前,我需要调用CoInitialize吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道一个需求的COM,每个线程调用 CoInitialize ,然后再与COM系统交互。



.NET公开了内部在线程上操作的一些项目,例如:





如果我要从线程与COM对象进行交互, CoInitialize 第一次?



我问,因为可能有一些为我自动调用它的魔法 - 我不知道。






奖金阅读




托管和非托管线程



对于互操作性,公共语言运行库创建和
在调用COM对象时初始化公寓。受管线程
可以创建和输入一个单线程公寓(STA),其中包含
只有一个线程,或者是一个包含一个
或更多线程的多线程公寓(MTA)。当COM公寓和线程生成的公寓
兼容时,COM允许调用线程直接调用
到COM对象。如果公寓不兼容,COM创建一个
兼容的公寓,并通过新的
公寓中的代理调度所有调用。



运行时调用CoInitializeEx将COM公寓初始化为
MTA或STA公寓。


更新二:



看起来你不应该使用.NET可以提供的任何类型的线程:


管理线程池



有几种情况下创建和
管理自己的线程,而不是使用线程池线程:



    $ b $

    b $ b
  • 您有任务导致线程长时间阻塞
    时间。线程池有最大线程数,所以一个大的
    的阻塞线程池线程数可能阻止
    开始执行任务。


  • 您需要将线程放入单线程公寓。所有
    ThreadPool线程都位于多线程公寓中。


  • 您需要拥有与线程相关的稳定身份,或
    将线程专用于任务。





更新三



看起来像您可以 设置无线线程的线程模型:


管理和在Microsoft Windows中的非托管线程



托管线程可以被标记为指示它将托管单线程或多线程公寓。 GetApartmentState SetApartmentState TrySetApartmentState 主题类返回并分配线程的公寓状态。如果尚未设置状态, GetApartmentState 会返回公司状态。未知



属性只能在线程处于 ThreadState.Unstarted 状态时设置;



如果在启动线程之前未设置公寓状态,线程将初始化为多线程公寓(MTA)。


很多冲突的信息。



这是为什么我们将使用不管Stackoverflow上的人说什么都是真正的答案。

解决方案

这里的信息实际上并不是冲突 -



简短答案:





更长的答案:有两种方法可以调用CoInitialize - 您可以使用它来初始化您的线程为单线程公寓线程(STA)或多线程公寓线程(MTA)。上面的文本是说,默认情况下,新线程和线程池线程自动预先CoInitialized作为MTA风味。但是使用一个新的线程,你可以使用ApartmentState来指定STA-flavor,如果你这样做之前实际启动线程。



请注意,基于UI的程序的Main()标有[STAThread]属性,以确保它是基于STA的;而在控制台应用程序,缺乏[STAThread]意味着它Coinited作为MTA。顺便说一句,这个属性的原因是,调用Main()的线程是一个线程,你不能指定STA VS MTA使用ApartmentState - 因为它已经运行,到Main()执行时,太晚使用;所以想到的属性作为一个提示运行时设置公寓状态之前Main()被调用。



要知道的关键是STA通常与UI一起使用,需要消息循环(.Net WinForms为您提供); STA代码永远不应该与Sleep()或类似的阻塞,否则你的UI也会阻塞。另一方面,MTA被设计用于工作者使用 - 后台任务,下载文件或在后台执行计算,例如,一般不应该拥有UI。你可以使用COM从这些,但它可能取决于COM对象正在做什么或从哪里得到它。如果它是一个UI组件,可能你想要使用它从一个STA线程;另一方面,如果它是下载或执行计算的组件,则通常使用MTA线程。



上面的Update 1基本上是说。



上面的Update 2基本上是说,因为ThreadPool线程是MTA(MTA)你不应该改变它),你应该只使用它们做后台操作,而不是用于UI任务。



更新3是说新线程,你可以选择MTA VS STA - 与更新1相同,只是更加明确的API。



整个MTA和STA的东西可以变得相当复杂,建议请阅读本文作为起点。但是,大图总的来说是记住STA =单线程和UI; MTA =多线程,后台/工作任务。 (STA vs MTA也适用于对象,而不仅仅是线程,COM在幕后做了一大堆工作,让不同类型的线程使用不同类型的对象。当它工作得很好时,你不会意识到它,可以幸运地忽略它;但是当你遇到限制或限制,它往往是棘手的弄清楚发生了什么。)


i know that a requirement of COM that every thread call CoInitialize before interacting with the COM system.

.NET exposes some items that internally operate on threads, e.g.:

If i am going to be interacting with a COM object from a thread, do i need to call CoInitialize first?

i ask because there may be some more magic that automagically calls it for me - i don't know.


Bonus Reading

Managed and Unmanaged Threading

For interoperability, the common language runtime creates and initializes an apartment when calling a COM object. A managed thread can create and enter a single-threaded apartment (STA) that contains only one thread, or a multi-threaded apartment (MTA) that contains one or more threads. When a COM apartment and a thread-generated apartment are compatible, COM allows the calling thread to make calls directly to the COM object. If the apartments are incompatible, COM creates a compatible apartment and marshals all calls through a proxy in the new apartment.

The runtime calls CoInitializeEx to initialize the COM apartment as either an MTA or an STA apartment.

Update Two:

Looks like you should not use COM from any kind of thread that .NET can provide:

The Managed Thread Pool

There are several scenarios in which it is appropriate to create and manage your own threads instead of using thread pool threads:

  • You require a foreground thread.

  • You require a thread to have a particular priority.

  • You have tasks that cause the thread to block for long periods of time. The thread pool has a maximum number of threads, so a large number of blocked thread pool threads might prevent tasks from starting.

  • You need to place threads into a single-threaded apartment. All ThreadPool threads are in the multithreaded apartment.

  • You need to have a stable identity associated with the thread, or to dedicate a thread to a task.

Update Three:

Looks like you can set the threading model of unmanged threads:

Managed and Unmanaged Threading in Microsoft Windows

A managed thread can be marked to indicate that it will host a single-threaded or multithreaded apartment. The GetApartmentState, SetApartmentState, and TrySetApartmentState methods of the Thread class return and assign the apartment state of a thread. If the state has not been set, GetApartmentState returns ApartmentState.Unknown.

The property can be set only when the thread is in the ThreadState.Unstarted state; it can be set only once for a thread.

If the apartment state is not set before the thread is started, the thread is initialized as a multithreaded apartment (MTA).

Lot of conflicting information.

Which is why we'll use whatever the guy on Stackoverflow said as the true answer.

解决方案

The information here isn't actually conflicting - it's just not necessarily super clear if you're new to COM.

Short answer:

  • .Net threads are always already CoInitialized for you - you don't have to (and should not!) call it yourself.
  • ThreadPool threads (and therefore anything that uses ThreadPool threads, like asynchronous delegates and so on) are always initialized MTA. The only option for creating an STA thread is either adding the [STAThread] attribute to Main() to request that the runtime initializes the main thread as STA, or using thread.SetApartmentState(ApartmentState.STA) on a new thread you create before calling thread.Start() - otherwise they are MTA by default. In any case, the thread apartment model cannot be modified once the thread is started and running.

Longer answer: there are two ways to call CoInitialize - you can use it to initialize your thread as a Single-Threaded Apartment thread (STA), or as a Multi-Threaded Apartment thread (MTA). What the text above is saying is that by default, new threads and threadpool threads are automatically pre-CoInitialized as MTA-flavor. But with a new thread, you can use ApartmentState to specifiy STA-flavor, if you do so before actually starting the thread. It's always CoInitialized one way or the other by the time it's started anyhow.

Note that Main() on UI-based programs is marked with the [STAThread] attribute to ensure that it's STA-based; while on a console app, lack of [STAThread] means it's CoInited as MTA. The reason for this attribute, by the way, is that the thread that calls Main() is the one thread you can't specify STA vs MTA using ApartmentState - because it's already running and by the time Main() executes, so too late to use that; so think of the attribute as a hint to the runtime to set the apartment state before Main() is called.

The key thing to be aware of is that STA is usually used with UI and requires a message loop (which .Net WinForms provides for you); STA code should never block with Sleep() or similar, else your UI will also block. MTA, on the other hand, is designed for worker usage - background tasks, downloading files or doing computations in the background, for example, and generally should not own UI. You can use COM from either of these, but it may depend on what the COM object is doing or where you got it from. If it's a UI component, likely you'd want to use it from a STA thread; on the other hand, if it's a component for downloading or doing computations, you'd typically use it from an MTA thread.

Update 1 above is basically saying that the .Net runtime always calls CoInitialize for you - but lets you chose STA vs MTA, with MTA being the default.

Update 2 above is basically saying that since ThreadPool threads are MTA (and you don't get to change that), you should only use them for doing background operations, and not use them for UI tasks.

Update 3 is saying that for new threads, you can chose MTA vs STA - same as update 1, just being more explicit about the APIs.

The whole MTA vs STA thing can get quite complex, suggest reading this article as a starting point. The big picture, though, is mostly summarized by remembering that STA = single thread and UI; MTA = multiple threads, background/worker tasks. (STA vs MTA also applies to objects, not just threads, and COM does a whole bunch of work behind the scenes to let the different types of threads use the different types of objects. When it works well, you don't realize it and can blissfully ignore it; but when you hit a restriction or limitation, it can often be tricky to figure out just what's going on.)

这篇关于在.NET中与COM交互之前,我需要调用CoInitialize吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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