如何在Silverlight 4中释放COM对象

在Office中使用COM Interop(通常是Excel)时,我总是小心地确保在每个引用上都调用Marshal.ReleaseComObject ,以避免在本KB知识库文章中描述的Excel未退出的问题。

当我从OOB Silverlight应用程序(使用AutomationFactory.CreateObject )使用Interop时,如何确保Excel退出?

Silverlight没有Marshal.ReleaseComObject方法,甚至调用GC.CollectGC.WaitForPendingFinalizers也没有帮助。

毫无疑问,微软没有将这个功能添加到Silverlight,而没有发布COM引用的机制? 这对我来说似乎是自动化进程外COM服务器(如Excel)的不二之选。

作为Pete Brown在他的书“Silverlight 4 in Action”第5.5节中的一个令人惊讶的遗漏,甚至可以说AutomationFactory.CreateObject

此功能的主要目的是允许其他应用程序(包括Microsoft Office)的自动化。

更新回应汉斯的评论。

我不相信在典型的Office应用程序自动化中存在“无声刺客”问题。 常见的用法可能如下所示,我曾在WinForms应用程序中反复使用过,但没有遇到Hans链接的文章中描述的“中毒RCW”:

  • 创建一个Excel.Application实例
  • 打开或创建工作簿
  • 将数据写入工作簿
  • 如果一切顺利,则显示Excel,关闭工作簿,如果不是,则调用Application.Quit。
  • 调用Marshal.ReleaseComObject以释放所有Excel对象引用。
  • 按照Hans的建议,如果未能调用Marshal.ReleaseComObject,将会使Excel.exe运行多个副本,如上面提到的知识库文章中所述 - 这是非常不可取的。

    更新2

    我正在使用的示例是Pete Brown的Silverlight 4的源代码样本,该页面上有一个下载链接。 示例解决方案AutomatingExcel位于Ch05.zip / 5.03中。 重现:

  • 确保没有Excel实例正在运行
  • 运行AutomatingExcel示例
  • Excel工作簿已打开
  • 关闭Excel
  • 使用任务管理器观察Excel仍在运行。
  • 将所有动态变量设置为null并调用GC.Collect()似乎可以像AnthonyWJones的答案中指出的那样工作。

    更新2

    Otaku的答案是我正在寻找的 - 通过在using语句中包装引用,COM引用被释放而不需要调用GC.Collect。 有一些实验表明,与上面引用的知识库文章中描述的标准Marshal.ReleaseComObject解决方案不同,它更容易处理每一个引用。

    确切地说必须处理的是确保发布所有Excel参考文献的权威性内容会很有趣。


    您可以实现IDisposable接口。 我见过的最好的例子是http://csfun.blog49.fc2.com/blog-entry-79.html。 博客文章是日文的,但是在Chrome中打开,如果你没有阅读日文,让Google为你做页面翻译。

    另外,如果您只是想直接使用COM包装器的源代码示例,则可以下载它的示例应用程序:SilverOffice。


    看看这个代码: -

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            dynamic app = AutomationFactory.CreateObject("Excel.Application");
            dynamic book = app.Workbooks.Add();
            dynamic sheet = app.ActiveSheet();
    
            sheet = null;
            book.Close(false);
            book = null;
            app.Quit();
            app = null;
    
            GC.Collect();
        }
    

    Excel进程出现然后消失。 删除GC并且Excel过程将继续。 如果你逐字复制这段代码,你会得到相同的结果吗? 如果是这样,那么它会建议你的代码中的某个地方对Excel对象的引用仍然可以从线程堆栈或静态字段之一访问。

    你曾经在一个领域(而不是本地变量)拥有一个excel对象吗?

    你是否拥有一个看起来可变的excel对象,但是被用作事件处理程序的动态委托或lambda引用?

    您是否将事件处理程序附加到寿命较短的对象的长寿命对象? 如果是这样,你确保你正确地从这些处理程序分离?

    这些东西中的许多可以吸引开发者离开他们认为可以用于GC的对象,但是GC发现它们是可访问的,因此不是用于收集的候选者。

    如果上面的代码行为不一样,那么我们完全在寻找另一个问题。 我在最新的SL 4运行时使用Server 2008 R2上的Office 2007。 但是,如果我们因为设置而出现变化,那么我们就处于非常不稳定的状态。

    编辑

    通过一些测试,这似乎是有效的: -

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            using (dynamic app = AutomationFactory.CreateObject("Excel.Application"))
            {
                using (dynamic book = app.Workbooks.Add())
                {
                    using (dynamic sheet = app.ActiveSheet())
                    {
    
                    }
                    book.Close();
                }
                app.Quit();
            };
    
            GC.Collect();
        }
    

    然而,离开GC,最终会导致不需要的Excel进程保持运行。


    我会考虑在WCF服务中构建Excel文件。 你可以在那里做所有的清理工作。 发送到您的Silverlight应用程序的字节,并使用SaveFileDialog将它们发送给用户。

    Silverlight对访问客户端文件系统有限制。 操作客户端系统上的Excel文件,或者甚至假定客户端安装了Excel似乎违反了此规定。

    链接地址: http://www.djcxy.com/p/35675.html

    上一篇: How to release COM objects in Silverlight 4

    下一篇: Opening an Excel application client