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

时间:2011-08-31 03:41:06

标签: c# com .net-4.0 marshalling multithreading

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

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

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

Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.STA);
suspiciousComInterface.SomeMethod();

虽然这会警告我们,如果我们的BackgroundWorker线程正在调用STA对象,我特别担心STA线程正在使用在另一个STA线程中创建的COM Runtime Callable Wrapper(RCW)对象。

一位在线消息人士建议,这是不可能的(http://www.pcreview.co.uk/forums/detecting-cross-apartment-com-calls-t2450589.html),CLR会掩盖过多的COM代理对象,使其无法在高级别访问。

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

1 个答案:

答案 0 :(得分: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
  }

然后,你可以像这样测试界面。

  if (suspiciousComInterface is IMarshal)
     // cross-apartment call
  else
     // direct call