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


我正在处理大型多线程C#应用程序处理COM互操作串。其他开发者和我有充分的机会不小心打电话 单线程公寓(STA) 来自MTA线程的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代理对象,使它们在高级别可访问。

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


8801
2017-08-31 03:41


起源

您是否可以访问COM组件代码? - sharptooth
不,COM组件是一个可爱的小黑盒子。 - Scott B
使用regedit从HKCR \ Interface注册表项中删除代理。当试图在公寓之间编组时,这将导致代码与E_NOINTERFACE一起轰炸。 - Hans Passant


答案:


您应该能够通过测试是否可以访问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

12
2017-08-31 15:10



如果那是有用的那么强大! - tcarvin
它适用于我的盒子 - 感谢布伦特! - Scott B
大。我不知道它可以做得那么优雅。 - sharptooth
FWIW,这可能会使用自己实施IMarshal的对象返回误报。这并不常见;大多数物体只是公主 - 螺纹或自由螺纹,并留在那,但有一些对象实现IMarshal自己 - 或 聚集自由螺纹的Marshaller 特别是这样他们避免被编组;在这些情况下,您可能直接与对象交谈,但仍会看到IMarshal。所以这可能适用于您的情况,但通常不正确。 - BrendanMcK