在C#中通过COM RCW对象检测跨线程编组

Sco*_*t B 11 c# com multithreading .net-4.0 marshalling

我正在处理大型多线程C#应用程序处理COM互操作串.其他开发人员和我有充分的机会不小心从MTA线程调用单线程公寓(STA) COM对象,并从他们未创建的STA线程.性能低迷,跨线程编组是主要的嫌疑.

是否有一个很好的方法来测试跨公寓编组?更好的是,是否有一种防御性编程技术来测试给定的COM对象属于这个线程的公寓?

我最接近的是一个关于可疑代码的防御声明:

Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.STA);
suspiciousComInterface.SomeMethod();
Run Code Online (Sandbox Code Playgroud)

虽然如果我们的BackgroundWorker线程正在调用STA对象,这将警告我们,我特别担心STA线程正在使用在另一个STA线程中创建的COM运行时可调用包装器(RCW)对象.

一个在线源认为,这是不可能的(http://www.pcreview.co.uk/forums/detecting-cross-apartment-com-calls-t2450589.html),在CLR掩盖了太多的COM代理的使对象在高级别可访问的对象.

我无法相信这是唯一的答案.谢谢!

Bre*_*ell 12

您应该能够通过测试是否可以进入IMarshal接口来实现此目的,如果呼叫是跨公寓呼叫,则该接口应聚合到代理中.首先,您需要在项目的某个位置声明IMarshal:

  [System.Runtime.InteropServices.InterfaceTypeAttribute(1)]
  [System.Runtime.InteropServices.Guid("00000003-0000-0000-C000-000000000046")]
  public interface IMarshal
  {
     // no methods needed, just querying for the interface
  }
Run Code Online (Sandbox Code Playgroud)

然后,您可以像这样测试界面.

  if (suspiciousComInterface is IMarshal)
     // cross-apartment call
  else
     // direct call
Run Code Online (Sandbox Code Playgroud)

  • FWIW,这可能会使用自己实施IMarshal的对象返回误报.这并不常见; 大多数物体只是公主螺纹或自由螺纹,并留在那里,但有一些对象实现IMarshal自己 - 或[聚合自由螺纹Marshaller](http://msdn.microsoft.com/ en-us/library/windows/desktop/ms694500(v = vs.85).aspx)特别是这样他们避免被编组; 在这些情况下,您可能直接与对象交谈,但仍会看到IMarshal.所以这可能适用于您的情况,但通常不正确. (4认同)