COM 互操作挂起会冻结整个 COM 系统.如何取消 COM 调用

本文关键字:COM 何取消 取消 调用 系统 挂起 互操作 冻结 | 更新日期: 2023-09-27 18:32:10

我正在使用通过 COM 互操作包装器公开的第三方 dll。但是,其中一个 COM 调用经常冻结(至少从不返回)。为了至少让我的代码更健壮一点,我异步包装了调用(_getDeviceInfoWaiter是一个ManualResetEvent

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时都会调用该调用,以便我们可以适当地记录信息。但是,正如我所说,如果这个组件正在等待,任何COM组件都会冻结(如果第三方锁定,我们自己的锁的自定义COM)

更新 2

上面的代码确实有效,并将 UI 线程的挂起延迟到下一次 COM 调用。尝试此解决方法的原因是var deviceInfo = _myCom.get_DeviceInfo(0);已锁定 UI 线程。但是,此信息并不重要,仅用于日志记录,因此此方法允许"放弃并在 15 秒后继续"方案

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

COM 互操作挂起会冻结整个 COM 系统.如何取消 COM 调用

更新 - 在 OP 的第二次更新之后

如果你有一些有问题的组件,你总是可以通过使用以下方法使你的使用更加健壮:

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

由于您是在 .NET 中实现的,您甚至可以将"包装器 EXE"作为主可执行文件中的"嵌入式资源",甚至可以从 RAM 启动它而无需将其写入文件系统......

第三方 DLL 内部有某种无限期的等待、循环或死锁。尝试像这样解决它是行不通的。您可能已经将挂起的调用转移到工作线程,但该线程不会消失;它一直挂在那个电话里。

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

最好联系这个第三方事物的开发人员/供应商,并询问他们您是否以某种方式滥用它。是否缺少一些先决条件。一些未执行的初始化。一些必要的配置等。