注释
本文特定于 .NET Framework。 它不适用于 .NET 的较新版本实现,包括 .NET 6 及更高版本。
托管 invalidApartmentStateChange 调试助手(MDS)由以下两个问题之一激活:
尝试将 COM 已初始化的线程的 COM 单元状态更改为其他单元状态。
线程的 COM 单元状态意外更改。
症状
线程的 COM 单元状态不是所请求的状态。 这可能会导致代理用于具有与当前模型不同的线程模型的 COM 组件。 这反过来可能会导致 InvalidCastException 通过未为跨单元封送设置的接口调用 COM 对象时引发。
线程的 COM 单元状态与预期不同。 这可能会导致COMException对运行时InvalidCastException(RCW)进行调用时出现RPC_E_WRONG_THREAD 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);
}
}
}