如何检查COM对象是否仍存在

4
我基本了解在.NET中如何使用托管的RCW对象来包装COM对象。我的问题是当COM对象不存在时会发生什么。我知道RCW对象会增加引用计数,因此只要RCW对象存在,COM对象就不会被释放。但是如果从用户角度删除了COM对象怎么办?
比如我有一个PowerPoint幻灯片中的形状、Excel工作表或Word段落。我的应用程序创建了一个引用并保持一段时间。现在用户可能删除了PowerPoint幻灯片,关闭了Excel文件或删除了Word段落。如何正确地检测到这一点?
尝试后发现,当访问任何属性时,COM对象会抛出带有错误代码0x80004005的COMException,表示“对象不存在”。
但我想知道:这是一种可靠和安全的方法吗?COM对象是否真的会与RCW对象一起保留,还是Office可能将其从内存中删除?如果是这样,使用悬空引用是否危险,是否有更好的方法?

不,该对象并未从内存中移除,是的,引用此 COM 对象是危险的。但不幸的是,我还没有找到另一种方法…… - Ivan Sander de Jong
谢谢您确认了我的担忧。我想我应该考虑一个更好的方法。 - Paul B.
3个回答

4
你正在进行的操作本质上是有风险的。在用户与Office程序交互时使用自动化是棘手的,你必须仔细编码。特定的COM对象不会被删除,它们是引用计数的,你持有一个对它的引用。但是当用户将其从文档中移除时,只剩下一个内存中的对象,它当然不再是文档的一部分了。
尝试取消引用该对象的成员确实很可能失败。Office程序本身很可能已经删除了对象保留的任何内部引用。你得到的异常非常糟糕,这也不是不寻常的,0x80004005是E_FAIL,“未指定的错误”。这几乎不能称为错误,这只是对错误报告质量的教师评分。
理想情况下,你会收到一个事件,告诉你放弃你的对象引用。这很难实现,Office应用程序并不那么健谈。最好的办法是根本不持有引用,而是在需要时找回它。如果这不切实际,那么你就必须使用try/catch-em-all作为最后的备选方案。

谢谢您解释背景并提醒我。我会尝试绕过保留引用。例如,对于 PowerPoint,使用幻灯片和形状 ID 可能有效。事件确实很少见... - Paul B.

1

这是一种可靠且故障安全的方法吗?

是的,它是。处理COM对象没有更好的方法。当在代码中处理COM对象时,您需要处理异常。此外,我建议处理可以告诉您发生了什么事情的事件 - 是否删除了特定对象等。

COM对象是否真的会与RCW对象一起保留,或者Office可能会将其从内存中删除?

Office可以从内存中删除对象。我建议保留对象ID而不是保留直接引用。

在这种情况下,使用悬空引用是否危险,是否有更好的方法?

没有更好的方法。有关更多信息,请参阅我的先前答案。


感谢您的输入。我将尽可能使用ID。然而,即使在大文件和数千个对象的情况下,我也无法证明具有引用的对象被删除了。如果内存被释放,我会期望发生访问冲突,但这从未发生过。这也是Hans的答案所建议的。 - Paul B.
我认为 Hans 的说法是错误的,即特定的 COM 对象在减少引用计数之前不会被删除。但是,在使用 Marshal 类的 FinalReleaseComObject 方法的情况下,引用计数将被减少到 0,并且对象将被释放。无论您是否持有该引用,对象都将被删除。您可能会从编写不良的插件中期待这样的操作... - Eugene Astafiev

1
您可以像这样使用try-catch组合:
try
{               
    ProcessString(s);
}
catch (Exception e)
{
    Console.WriteLine("{0} Exception caught.", e);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接