【问题标题】:Release COM Object in C#在 C# 中释放 COM 对象
【发布时间】:2012-03-05 00:42:41
【问题描述】:

我知道这已经在前面讨论过,但我找不到满意的答案。

我有一个电子邮件文件 (.msg),如下所示打开,然后调用 Display。

oApp = new Microsoft.Office.Interop.Outlook.Application();
mail = (Microsoft.Office.Interop.Outlook.MailItem)oApp.Session.OpenSharedItem(fileName);
mail.Display(false);
oApp = null; // do I need to release this object ?

用户可以关闭它并重新打开它。在他们单击“重新打开”之前,我检查窗口是否仍然存在,如果是..然后只需向该窗口发送 SetForeground(hwnd)。如果不是,则表示用户将其关闭,因此只需释放 mailItem 对象并再次打开。

 public static void ReleaseCOMObject(Microsoft.Office.Interop.Outlook.MailItem item) {
        int r = System.Runtime.InteropServices.Marshal.ReleaseComObject(item);
        while (r != 0) {
            r = System.Runtime.InteropServices.Marshal.ReleaseComObject(item);
        }
    }

如果我再次尝试打开同一个文件。它“有时”会引发“文件正在使用异常”所以,我认为即使我正在释放 MailItem .. 它也没有被正确释放。

我能做些什么来确保它正确发布。关闭和重新打开文件是一种非常常见的情况。

任何指针都会很有帮助。

【问题讨论】:

  • 只有在增加引用计数器时才应该“释放”,“释放”其他人的引用会导致问题。

标签: c# com outlook


【解决方案1】:

如果您正在使用 .NET 的 COM 互操作功能(您是),那么您不必担心这一点。

COM 跟踪引用计数 - 当引用计数达到 0 时,COM 对象会自动释放 - 并且 .NET 会为您使用标准的 COM 引用计数机制。

如果您是 P/Invoking 到 C 库中,情况可能会有所不同 - 但在像您这样的标准场景中,您不必担心。

【讨论】:

  • 不知道我做错了什么。我注意到一旦我得到“文件使用异常”重新启动我的 Outlook 就可以了。我需要对“oApp = new Microsoft.Office.Interop.Outlook.Application();”进行什么样的清理?
  • 它现在可以工作了 -> 有另一个模块保留了 MailItem 并且没有释放它。
  • 顺便说一句,只是想让你知道我仍然需要“ReleaseCOMObject”才能使其工作。
  • @karephul - 我不同意 Nanhydrin 的观点,即“尽早处置,经常处置”始终是一个好主意,无论情况如何。如果某些东西是 IDisposable 它应该被包装在 using 语句中或在一次性类中使用并在主类被释放时被释放。但是,除非有特殊情况,否则您不必手动调用 ReleaseCOMObject。 blogs.msdn.com/b/visualstudio/archive/2010/03/01/…
【解决方案2】:

做这样的事情:

mail = (Microsoft.Office.Interop.Outlook.MailItem)oApp.Session.OpenSharedItem(fileName);

即使调用 ReleaseComObject 也会导致引用不被释放,因为对子对象的引用没有被正确释放。

你应该这样调用:

session = oApp.Session;
mail = (Microsoft.Office.Interop.Outlook.MailItem)session.OpenSharedItem(fileName);

您应该依次处理每个子对象,例如会话。

【讨论】:

  • 我注意到如果 Outlook 没有在我的机器上运行 .. 关闭和重新打开(我之前描述的方式)工作正常。我认为一些前景如何持有对该文件的引用。那里有任何指示吗?我也尝试单独释放 Session 对象(不起作用)
  • 您是在获取邮件的同一方法中调用 Marshal.ReleaseComObject 方法,还是在某些 onclose 事件处理程序或类似的方法中调用?
  • 在用户打开邮件之前,我们检查是否有一个标题相同的窗口。如果没有,则 ReleaseComObject(mailItem) .. 并再次打开。 [用户本可以关闭电子邮件窗口] .. 基本上我会尽可能长时间地持有 MailItem,以便我可以定期保存它。
  • 顺便说一句,我可以在不同的线程中 ReleaseComObject(item) 吗?喜欢在后台?我注意到即使“ReleaseComObject”能够释放对象也需要很多时间(**只有一个参考)
  • 你不能依赖垃圾收集器在你处理完它们后立即将它们捡起来,所以通常最好在你处理完它们后立即处理掉它们。我希望您可以在任何地方释放 COM 对象,但个人而言,我更喜欢在我使用它们的相同方法中释放 COM 对象,或者如果范围超出当前方法,则在适当的时候尽快释放它们,这降低了可能性我会错过一个对象并最终会打开一些东西。
猜你喜欢
  • 2015-09-25
  • 2012-09-17
  • 2014-02-14
  • 2015-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-02
相关资源
最近更新 更多