我正在编写一个小型库来帮助管理Excel中的某些对象。我正在使用一个简单的控制台应用程序来测试这个DLL,该应用程序调用库,然后输出结果。然后,我可以以任何典型的方式结束程序,通常是通过点击返回(从而完成ReadLine
调用)或点击窗口的关闭按钮。 但是,对Excel实例的引用会根据程序的退出方式而有所不同。
在我的程序中,如果找不到现有的Excel引用,我使用以下行:
_app = new ExcelInterop.Application();
其中_app
是静态或单例类中Microsoft.Office.Interop.Excel.Application
的实例(我已尝试过两者,两者都有相同的结果)。
假设程序创建了自己的实例(并且找不到已打开的实例):
Main
块中的代码末尾退出程序有没有让所有程序结束的行为与后一种情况相同?此外,这个DLL将继续在WPF应用程序中使用,在WPF中是否有类似的问题?< / strong>或者大概,甚至?
也许最重要的是,这种行为的技术原因是什么?
答案 0 :(得分:3)
对于公寓线程进程外COM服务器所需的COM互操作包装器对象,控制台模式程序是一个相当恶劣的地方。该计划证明了这个问题:
using System;
class Program {
static void Main(string[] args) {
var prg = new Program();
Console.ReadLine();
}
~Program() {
Console.WriteLine("Clean-up completed");
System.Threading.Thread.Sleep(1500);
}
}
按两种方式尝试,按Enter键并单击“关闭”按钮。你会看到终结器永远不会被执行。当您单击“关闭”按钮时,操作系统会在有机会正常关闭之前终止该过程。
与COM包装器的终结器相同的问题。它们无法执行,因此IUnknown :: Release()不会被调用,Office程序完全不知道客户端程序不再存在。 Windows对于已放弃的进程外服务器有自己的清理工作,但由于其他一些神秘的原因,这对Office程序不起作用。
这解释了它,修复它并不容易。单击“关闭”按钮时,您必须运行register a callback。如果必要,将 app 引用设置为null(如果它仍在范围内)并强制终结器与GC.Collect()+ GC.WaitForPendingFinalizers()一起运行。请记住,这只是一个创可贴,而不是一个修复。当您忙于与Office程序通信时,用户中止您的程序时,它将无法工作。最好避免使用控制台模式项目。