我知道了 需求 每个线程调用的COM CoInitialize
在与COM系统交互之前。
.NET暴露了一些内部在线程上运行的项目,例如:
如果我要从一个线程与一个COM对象进行交互,我是否需要调用 CoInitialize
第一?
我问,因为可能有一些 更多魔法自动称呼它为我 - 我不知道。
奖金阅读
对于互操作性,公共语言运行库创建和
在调用COM对象时初始化公寓。托管线程
可以创建并输入包含的单线程单元(STA)
只有一个线程,或包含一个的多线程单元(MTA)
或更多线程。当COM公寓和线程生成的公寓
兼容,COM允许调用线程直接进行调用
到COM对象。如果公寓不兼容,COM会创建一个
兼容的公寓和警察通过新的代理通过所有电话
公寓。
运行时调用CoInitializeEx将COM单元初始化为
无论是MTA还是STA公寓。
更新二:
看起来你不应该使用.NET提供的任何类型的线程中的COM:
有几种情况适合创建和
管理自己的线程而不是使用线程池线程:
这里的信息实际上并没有冲突 - 如果你是COM的新手,那就不一定非常清楚了。
简短回答:
- .Net线程总是已经为您进行了CoInitialized - 您不必(也不应该!)自己调用它。
- ThreadPool线程(因此任何使用ThreadPool线程的东西,比如异步委托等)都是 总是 初始化的MTA。创建STA线程的唯一选择是添加
[STAThread]
属性为 Main()
请求运行时将主线程初始化为STA,或使用 thread.SetApartmentState(ApartmentState.STA) 在调用之前创建的新线程上 thread.Start()
- 否则它们默认为MTA。无论如何,一旦线程启动并运行,就无法修改线程单元模型。
更长的答案:有两种方法可以调用CoInitialize - 您可以使用它来将线程初始化为单线程单元线程(STA),或者作为多线程单元线程(MTA)。上面的文字说的是默认情况下,新线程和线程池线程自动被预先CoInitialized为MTA-flavor。但是使用新线程,如果在实际启动线程之前执行此操作,则可以使用ApartmentState来指定STA风格。无论如何,在它开始的时候,它总是以某种方式被初始化。
请注意,基于UI的程序上的Main()标有[STAThread]属性,以确保它是基于STA的;在控制台应用程序上,缺少[STAThread]意味着它被作为MTA CoInited。顺便说一下,这个属性的原因是调用Main()的线程是你不能使用ApartmentState指定STA vs MTA的一个线程 - 因为它已经运行并且在Main()执行时,所以太晚了使用它;所以将属性视为运行时的提示,以便在调用Main()之前设置单元状态。
需要注意的关键是STA通常与UI一起使用,需要一个消息循环(.Net WinForms为您提供); STA代码永远不应该使用Sleep()或类似代码阻止,否则您的UI也会阻塞。另一方面,MTA是为工作人员使用而设计的 - 例如,后台任务,下载文件或在后台进行计算,并且通常不应该拥有UI。您可以使用其中任何一个中的COM,但这可能取决于COM对象正在执行的操作或从何处获取它。如果它是一个UI组件,可能你想从STA线程中使用它;另一方面,如果它是用于下载或进行计算的组件,则通常从MTA线程使用它。
上面的更新1基本上是说.Net运行时总是为你调用CoInitialize - 但是让你选择STA vs MTA,MTA是默认值。
上面的更新2基本上是说由于ThreadPool线程是MTA(并且你不能改变它),你应该只使用它们来进行后台操作,而不是将它们用于UI任务。
更新3说,对于新线程,您可以选择MTA与STA - 与更新1相同,只是更明确地了解API。
阅读建议,整个MTA与STA之间的关系会非常复杂 本文 作为一个起点。不过,大局主要通过记住STA =单线程和UI来总结; MTA =多个线程,后台/工作人员任务。 (STA vs MTA也适用于对象,而不仅仅是线程,COM在幕后做了大量的工作,让不同类型的线程使用不同类型的对象。当它运行良好时,你没有意识到它和可以幸福地忽略它;但是当你遇到限制或限制时,弄清楚发生了什么通常是很棘手的。)
这里的信息实际上并没有冲突 - 如果你是COM的新手,那就不一定非常清楚了。
简短回答:
- .Net线程总是已经为您进行了CoInitialized - 您不必(也不应该!)自己调用它。
- ThreadPool线程(因此任何使用ThreadPool线程的东西,比如异步委托等)都是 总是 初始化的MTA。创建STA线程的唯一选择是添加
[STAThread]
属性为 Main()
请求运行时将主线程初始化为STA,或使用 thread.SetApartmentState(ApartmentState.STA) 在调用之前创建的新线程上 thread.Start()
- 否则它们默认为MTA。无论如何,一旦线程启动并运行,就无法修改线程单元模型。
更长的答案:有两种方法可以调用CoInitialize - 您可以使用它来将线程初始化为单线程单元线程(STA),或者作为多线程单元线程(MTA)。上面的文字说的是默认情况下,新线程和线程池线程自动被预先CoInitialized为MTA-flavor。但是使用新线程,如果在实际启动线程之前执行此操作,则可以使用ApartmentState来指定STA风格。无论如何,在它开始的时候,它总是以某种方式被初始化。
请注意,基于UI的程序上的Main()标有[STAThread]属性,以确保它是基于STA的;在控制台应用程序上,缺少[STAThread]意味着它被作为MTA CoInited。顺便说一下,这个属性的原因是调用Main()的线程是你不能使用ApartmentState指定STA vs MTA的一个线程 - 因为它已经运行并且在Main()执行时,所以太晚了使用它;所以将属性视为运行时的提示,以便在调用Main()之前设置单元状态。
需要注意的关键是STA通常与UI一起使用,需要一个消息循环(.Net WinForms为您提供); STA代码永远不应该使用Sleep()或类似代码阻止,否则您的UI也会阻塞。另一方面,MTA是为工作人员使用而设计的 - 例如,后台任务,下载文件或在后台进行计算,并且通常不应该拥有UI。您可以使用其中任何一个中的COM,但这可能取决于COM对象正在执行的操作或从何处获取它。如果它是一个UI组件,可能你想从STA线程中使用它;另一方面,如果它是用于下载或进行计算的组件,则通常从MTA线程使用它。
上面的更新1基本上是说.Net运行时总是为你调用CoInitialize - 但是让你选择STA vs MTA,MTA是默认值。
上面的更新2基本上是说由于ThreadPool线程是MTA(并且你不能改变它),你应该只使用它们来进行后台操作,而不是将它们用于UI任务。
更新3说,对于新线程,您可以选择MTA与STA - 与更新1相同,只是更明确地了解API。
阅读建议,整个MTA与STA之间的关系会非常复杂 本文 作为一个起点。不过,大局主要通过记住STA =单线程和UI来总结; MTA =多个线程,后台/工作人员任务。 (STA vs MTA也适用于对象,而不仅仅是线程,COM在幕后做了大量的工作,让不同类型的线程使用不同类型的对象。当它运行良好时,你没有意识到它和可以幸福地忽略它;但是当你遇到限制或限制时,弄清楚发生了什么通常是很棘手的。)
要回答你的第一个问题,如果我正确地记住了我的Don Box,每个线程都必须调用CoInitialize。没有例外。
至于自动部分,我不知道。