COM Interop挂起冻结整个COM系统。如何取消COM通话

时间:2012-04-25 18:21:52

标签: c# .net com interop

我正在使用通过COM Interop包装器公开的第三方dll。但是,其中一个COM调用经常冻结(至少不会返回)。为了尝试至少使我的代码更加健壮,我以异步方式包装了调用(_getDeviceInfoWaiterManualResetEvent

var backgroundWorker = new BackgroundWorker();
      backgroundWorker.DoWork += 
        (sender, eventArgs) =>
          {
            var deviceInfo = _myCom.get_DeviceInfo(0);
            _serialNumber = deviceInfo.SerialNumber;
            _getDeviceInfoWaiter.Set();
          };
      backgroundWorker.RunWorkerAsync();
      var waitFifteenSecondsForGetInfo = new TimeSpan(0, 0, 0, 15);
      _getDeviceInfoWaiter.WaitOne(waitFifteenSecondsForGetInfo, true);
      if(String.IsNullOrEmpty(_serialNumber))
        throw new ArgumentNullException("Null or empty serial number. " +
            "This is most likely due to the get_DeviceInfo(0) COM call freezing.");

然而,对任何COM组件的下一次调用将冻结代码。有什么我没有想到的,或者有什么方法可以防止我的主线死亡?

更新

基本上,这是一个COM调用,只要将新设备插入PC就会调用它,以便我们可以适当地记录信息。但是,正如我所说的, ANY COM组件将在此等待时冻结(如果第三方锁定,我们自己锁定的自定义COM)

更新2

以上代码可以工作,并延迟UI线程的挂起,直到下一次COM调用。尝试解决此问题的原因是因为var deviceInfo = _myCom.get_DeviceInfo(0);已经锁定了UI线程。但是,此信息并不重要,仅用于记录,因此这种方法允许“放弃并在15秒后继续”方案

这里的另一个解决方法是找到一种在x秒后取消COM调用的方法吗?

2 个答案:

答案 0 :(得分:3)

更新 - 从OP的第二次更新

之后

如果您有一些有问题的组件,您可以使用以下方法使您的使用更加健壮:

创建一个进程(EXE),它包装该组件的用法并公开API(例如通过任何IPC机制)。然后,您可以将EXE作为一个单独的进程(来自您的主EXE)启动并使用它...如果您需要在一定时间后杀死该组件和/或满足某些条件,您可以始终杀死“包装器EXE”来自你的主要EXE ......根据具体的组件,它甚至可能有助于在“包装器EXE”中实现一些特殊的“清理代码”(可能在一个单独的线程中),当你需要杀死那个“包装器EXE”时它会被执行”

由于您在.NET中实现此功能,您甚至可以将“wrapper EXE”作为“嵌入式资源”放在主可执行文件中,甚至可以从RAM启动它而无需将其写入文件系统...

答案 1 :(得分:1)

第三方DLL内部存在某种无限期的等待,循环或死锁。试图像这样解决它是行不通的。你可能已经对工作线程进行了挂起调用,但该线程并没有消失;它一直挂在那个电话里。

对COM组件的下一次调用最有可能冻结,因为前一个组件冻结了。也许它试图获得前一个在挂起之前获得的锁。或者它可能因为完全相同的原因而悬挂,而不是依赖原因。

更好地联系第三方的开发商/供应商,并询问他们是否以某种方式滥用它。是否有一些缺失的前提条件。一些未执行的初始化。一些必要的配置等。