如何在Silverlight 4中释放COM对象
当与Office(通常是Excel)使用COM互操作时,我总是小心地确保对每个引用调用如何在Silverlight 4中释放COM对象,silverlight,com,interop,Silverlight,Com,Interop,当与Office(通常是Excel)使用COM互操作时,我总是小心地确保对每个引用调用Marshal.ReleaseComObject,以避免Excel不退出的问题 当我从OOB Silverlight应用程序(使用AutomationFactory.CreateObject)使用互操作时,如何确保Excel退出 Silverlight没有封送.ReleaseComObject方法,甚至调用GC.Collect和GC.WaitForPendingFinalizers都没有帮助 如果没有发布COM
Marshal.ReleaseComObject
,以避免Excel不退出的问题
当我从OOB Silverlight应用程序(使用AutomationFactory.CreateObject
)使用互操作时,如何确保Excel退出
Silverlight没有封送.ReleaseComObject
方法,甚至调用GC.Collect
和GC.WaitForPendingFinalizers
都没有帮助
如果没有发布COM引用的机制,微软肯定没有向Silverlight添加此功能吗?在我看来,这似乎是自动化进程外COM服务器(如Excel)的一个障碍
一个令人惊讶的任务,尤其是皮特·布朗在其著作《Silverlight 4 in Action》的第5.5节中谈到了AutomationFactory.CreateObject
,即:
此功能的主要目的是实现其他应用程序(包括Microsoft Office)的自动化
针对Hans的评论进行更新
我不相信“沉默刺客”问题存在于典型的办公应用程序自动化中。一个常见的用法可能类似于以下内容,我在WinForms应用程序中看到过多次使用,但从未遇到Hans链接的文章中描述的“有毒RCW”:
- 创建一个Excel.Application实例
- 打开或创建工作簿
- 将数据写入工作簿
- 显示Excel如果一切顺利,请关闭工作簿并调用应用程序。否则请退出
- 调用Marshal.ReleaseComObject以释放所有Excel对象引用
- 确保没有Excel实例正在运行
- 运行AutomatingExcel示例
- 此时将打开Excel工作簿
- 关闭Excel
- 使用任务管理器观察Excel是否仍在运行
Marshal.ReleaseComObject
解决方案不同,它更能容忍无法处理每个引用
<> P>一个权威的解决方案就是要确保所有Excel引用都被释放。 < P>我会考虑在WCF服务中构建Excel文件。你可以在那里做所有的清理工作。将字节发送到Silverlight应用程序,并使用SaveFileDialog将其发送给用户
Silverlight对访问客户端文件系统有限制。在客户端系统上操作Excel文件,甚至假设客户端安装了Excel,似乎都违反了这一点。请查看以下代码:-
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运行时的Office2007。然而,如果我们有一个变化,因为设置,然后我们在非常不稳定的地面上
编辑
通过一些测试,这似乎是有效的:-
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进程继续运行 您可以实现
IDisposable
接口。我见过的最好的例子是在。博客条目是日文的,但在Chrome中打开,如果你不懂日文,可以让谷歌为你翻译网页
另外,如果您只想直接获得COM包装器的源代码示例,您可以下载它附带的示例应用程序:
通过在using语句中包装引用,COM引用被释放
请注意:在finally子句中,using语句只是try/catch/finally与Dispose()的语法糖
此外,大多数应用程序不允许在这种情况下使用语句,因为COM对象的创建和清理分布在不同的位置/方法中
此处需要的临界线如下:
((IDisposable)_excel).Dispose(); // Release COM Interface
这假定:
dynamic _excel = AutomationFactory.CreateObject("Excel.Application");
@Hans:Silverlight的可能副本在
封送
类中没有这两个方法。@Anthony-这解释了为什么这两个方法都不是好主意。“沉默刺客”链接非常相关。@Hans——“它解释了为什么这两种方法都不是好主意”——你能支持吗