注释
本文特定于 .NET Framework。 它不适用于 .NET 的较新版本实现,包括 .NET 6 及更高版本。
托管 invalidApartmentStateChange 调试助手(MDS)由以下两个问题之一激活:
尝试将 COM 已初始化的线程的 COM 单元状态更改为其他单元状态。
线程的 COM 单元状态意外更改。
症状
线程的 COM 单元状态不是所请求的状态。 这可能会导致代理用于具有与当前模型不同的线程模型的 COM 组件。 这反过来可能会导致 InvalidCastException 通过未为跨单元封送设置的接口调用 COM 对象时引发。
线程的 COM 单元状态与预期不同。 这可能会导致COMException对运行时可调用包装器(RCW)进行调用时出现RPC_E_WRONG_THREAD InvalidCastException HRESULT。 这也可能导致多个线程同时访问一些单线程 COM 组件,这可能会导致损坏或数据丢失。
原因
该线程以前初始化为不同的 COM 单元状态。 请注意,线程的公寓状态可以显式或隐式设置。 显式操作包括 Thread.ApartmentState 属性和 SetApartmentState 方法和 TrySetApartmentState 方法。 使用该方法创建的 Start 线程将隐式设置为 MTA ,除非 SetApartmentState 在线程启动之前调用。 应用程序的主线程也隐式初始化为 MTA ,除非在 STAThreadAttribute main 方法上指定了属性。
在
CoUninitialize线程上调用具有不同并发模型的方法(或CoInitializeEx方法)。
解决方案
在线程开始执行之前设置线程的公寓状态,或将 STAThreadAttribute 属性或 MTAThreadAttribute 属性应用于应用程序的主要方法。
对于第二个原因,最好修改调用 CoUninitialize 方法的代码,以延迟调用,直到线程即将终止,并且没有 RCW 及其基础 COM 组件仍在线程使用。 但是,如果无法修改调用 CoUninitialize 该方法的代码,则不应从以这种方式未初始化的线程使用 RCW。
对运行时的影响
此 MDA 对 CLR 没有影响。
输出
当前线程的 COM 单元状态,以及代码尝试应用的状态。
配置
<mdaConfig>
<assistants>
<invalidApartmentStateChange />
</assistants>
</mdaConfig>
示例
下面的代码示例演示了可激活此 MDA 的情况。
using System.Threading;
namespace ApartmentStateMDA
{
class Program
{
static void Main(string[] args)
{
Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
}
}
}