c# - 控制台应用程序 : Closing Window vs End of Program

标签 c# com console-application

我正在编写一个小型库来帮助管理 Excel 中的一些对象。我正在使用一个简单的控制台应用程序来测试这个 DLL,该应用程序调用该库,然后打印结果。然后,我可以以任何典型的方式结束程序,通常是通过按回车键(从而完成 ReadLine 调用)或按窗口的关闭按钮。 但是,根据程序退出的方式,对 Excel 实例的引用的行为有所不同。

在我的程序中,如果找不到对 Excel 的现有引用,我将使用以下行:

_app = new ExcelInterop.Application();

其中 _app 是静态或单例类中 Microsoft.Office.Interop.Excel.Application 的实例(我已经尝试过两者,两者都有相同的结果)。

假设程序创建了自己的实例(并且没有找到已打开的实例):

  • 如果通过单击关闭窗口按钮退出程序,实例将保持打开状态:
  • 如果程序通过到达 Main block 中的代码末尾而退出,则实例将被释放,并且不再出现在任务管理器中

有没有办法让所有程序端的行为都像后一种情况?此外,这个DLL将继续在WPF应用程序中使用,WPF中是否也有类似的问题? 甚至是逍遥法外?

也许最重要的是,这种行为的技术原因是什么?

最佳答案

控制台模式程序对于单元线程进程外 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 程序交谈时用户中止您的程序时,它将不起作用。最好避免控制台模式项目。

关于c# - 控制台应用程序 : Closing Window vs End of Program,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25042128/

相关文章:

com - MS Word 2007 加载项的 LoadBehavior 设置为 2

c# - 迭代元组中的项目

C# 数值数据类型命名

c# - 如何在执行其他函数时停止一个函数?

c++ - 正确扩展 COM 接口(interface) (IDL)

c++ - 使用没有功能的 extern "C"

c# - 为什么 Multiple await 需要像 Task.WhenAll() 一样的时间

c# - 在 Windows 10 中向 Text to Speech Engine 添加新声音

c# - 设置数据绑定(bind)后如何向列表框添加内容?

javascript - 从事件对象获取数据