2012-04-25 57 views
1

我正在使用通过COM Interop包装器公开的第三方dll。但是,其中一个COM调用通常会冻结(永远不会返回)。为了尽量至少使我的代码更健壮,我包的异步调用(_getDeviceInfoWaiterManualResetEventCOM Interop hang冻结整个COM系统。如何取消COM调用

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组件第二天通话将冻结代码。有没有我没有想到的东西,或者有什么方法可以防止我的主线死亡?

UPDATE

基本上,这是一个COM调用每当一个新的设备插入到PC,使我们可以适当地将这些信息记录时调用。然而,正如我所说,任何 COM组件将如果这个人是等待(我们自己锁自定义COM如果第三方锁定)

更新2

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

这里的另一个解决方法是找到一种方法来取消COM x秒后通话?

回答

3

更新 - 从OP第二更新后

如果你有一些问题的组件,你可以随时让你对它的使用更强大的使用以下方法:

创建过程( EXE),它包装了该组件的使用并公开了一个API(例如通过任何IPC机制)。然后,您可以将该EXE作为一个独立的进程(从主EXE)启动并使用它...如果您需要在特定时间后和/或遇到某种情况时杀死该组件,则始终可以杀死该“包装EXE”从你的主EXE ...根据具体的组件,它可能甚至是有用的执行一些特殊的“清理代码”(可能在一个单独的线程)在“包装EXE”,当你需要杀死“包装EXE” ”。

既然你是在.NET实现这一点,你甚至可以有“包装EXE”在你的主执行“嵌入的资源”,并从RAM甚至启动它,而不将其写入到文件系统...

+0

我已更新我的问题以提供更多详细信息。让我知道,如果你仍然需要更多 – 2012-04-25 19:37:37

+0

@JustinPihony我用一种方法更新了我的答案,这将有助于您的方案... – Yahia 2012-04-25 21:09:04

+0

嗯,这听起来像这是最好的方式...不漂亮,但它应该工作。我非常感谢帮助 – 2012-04-25 21:20:13

1

的第三方DLL有一些不确定的等待,循环或死锁。尝试像这样解决它是行不通的。你可能已经对工作者线程进行了悬挂调用,但该线程不会消失;它一直挂在那个电话里。

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

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