【问题标题】:Error handling when excel process is closed externally外部关闭excel进程时的错误处理
【发布时间】:2016-05-05 23:26:02
【问题描述】:

我正在编写一个与 excel 交互的程序。当excel被任务管理器杀死时,我在关闭我的应用程序时遇到了一些问题。

当我的程序启动时,它设置Excel.Application ObjApp = new Excel.Application();

当它关闭时,它以

结束
if (ObjApp != null)
{
    ObjApp = null;
}
GC.Collect();
GC.WaitForPendingFinalizers();
ObjApp.Quit();

Environment.Exit(0);

但是,如果 excel 通过任务管理器被杀死并且我退出,我会得到这个

“NullReferenceException 未被用户代码处理”ObjApp.Quit();

基本上我需要弄清楚的是怎么说

“如果 ObjApp(我的 Excel 实例)仍然可用,请退出,否则不要。” 我该如何解决这个问题?

【问题讨论】:

    标签: c# excel


    【解决方案1】:

    你不应该担心你无法控制的事情。用户是否决定终止您的程序正在使用的 Excel 应用程序不是您应该尝试弄清楚的(没有安全的方法来确定是否是这种情况,您可以总是以竞争条件结束,但我们不要偏离轨道)。

    那你该怎么办?实现代码来处理您的应用程序可以处理的任何合理的故障场景。失败的确切原因无关紧要,它可以是任何东西:它可能是用户关闭应用程序,但也可能是一些模糊的 Excel 错误导致应用程序崩溃,一个 操作系统打嗝,硬件故障,你有什么问题。

    你是怎么做到的?好吧,使用exception handling

    try
    {
         //Normal code path goes here. Assume appObj is running;
         ObjApp.Quit();
    }
    //optional catch clauses here
    finally
    {
        //Safe clean up you want running in normal execution or any managable
        //scenario. By safe I mean you shouldn't be handling/saving/modifying
        //any sensitive data, you should just clean up your COM objects.
        //Anything potentially unsafe should be handled in specific catch
        //clauses where you know the nature of the exception and you can take
        //specific measures to recover or shut down safely.
    
        //In some unrecoverable scenarios this might not even run.
        Marshal.FinalReleaseComObject(ObjApp);
    }
    

    您可以为特定的异常类型添加catch 子句,用于登录或通知用户发生了意外情况; COMException 是一个不错的选择,任何其他异常都应该向上传递到调用堆栈,让其他知道的人更好地处理它。

    【讨论】:

    • 实际上刚刚完成调查,刚刚了解到我的代码中可以有多个捕获来覆盖多个异常。我已经包含了一个 NullReferenceexception 和一个 COMException 捕获,它将继续关闭代码,不包括 ObjApp.Quit();部分。现在似乎工作得很好。
    • @DDuffy 很高兴为您提供帮助!关于您的评论,NullReferenceException 是,正如 Eric Lippert 先生所说的,boneheaded 例外。您根本没有理由处理这个异常,这是您的实现中的一个错误,而不是您的应用程序可能采用的*异常*代码路径。
    • 正如用户“blogprogramisty.net”指出的那样,我认为 NullReferenceException 在我“取消”它之后试图退出 ObjApp 时被抛出。我可能没有那个捕获。
    【解决方案2】:

    第一

    GC.WaitForPendingFinalizers() 将为objects 运行析构函数。

    例如,当ObjApp == null 时,GC 可能会破坏对象ObjApp。然后ObjApp 将为空。

    ObjApp.Quit() 必须在GC.WaitForPendingFinalizers() 之前调用

    第二您将ObjApp 设置为null 值,然后调用ObjApp.Quit()。如果Quit() 方法是非静态的,那么程序会抛出NullReferenceException 并且是预期的。

    试试这个:

    ObjApp.Quit();
    
    if (ObjApp != null)
    {
        ObjApp = null;
    }
    GC.Collect();
    GC.WaitForPendingFinalizers();
    
    Environment.Exit(0);
    

    当我关闭 Excel 文件时,我会这样做:

                ...//
    
                this.workbook.Close();
                this.application.Workbooks.Close();
                this.application.Quit();
            }
            finally
            {
                Marshal.FinalReleaseComObject(this.autoFitRange);
                GC.Collect();
                Marshal.ReleaseComObject(this.numberFormatRange);
                GC.Collect();
                Marshal.ReleaseComObject(this.range);
                GC.Collect();
                Marshal.ReleaseComObject(this.workbook);
                GC.Collect();
                Marshal.ReleaseComObject(this.sheet);
                GC.Collect();
                Marshal.ReleaseComObject(this.workbooks);
                GC.Collect();
                Marshal.ReleaseComObject(this.application);
                GC.Collect();
    

    如您所见,我为使用COM excel 库期间创建的所有对象运行ReleaseComObject。如果我这样做,我会成功关闭 Excel,该过程将从任务管理器中消失。

    愿这对你有所帮助。

    【讨论】:

    • 在 ObjApp.Quit(); 上仍然出现错误,这次它的“COMException 未被用户代码处理”。
    • 好的,但是现在其他地方的问题。 ObjApp.Quit() 很重要吗?
    • 据我所知。我还是 CSharp 的菜鸟,边走边学。 Objapp 是我的 excel 实例,我相信我需要在退出程序时退出该实例才能正确清理。
    • 我为此添加了我的解决方案
    • 谢谢你,我曾经打电话给元帅,不记得我为什么停下来。但是,这并不能真正解决问题,因为 Quit() 出现在这些问题之前,这就是向我抛出错误的原因。基本上我需要弄清楚的是怎么说“如果 ObjApp(我的 Excel 实例)仍然可用,退出它,否则不要。”
    猜你喜欢
    • 1970-01-01
    • 2011-02-22
    • 2014-10-17
    • 1970-01-01
    • 2011-04-22
    • 2017-03-23
    • 2016-07-31
    • 2012-03-14
    • 2015-01-11
    相关资源
    最近更新 更多