【问题标题】:How should I declare a Microsoft.Office.Interop.Excel.Worksheet so I can close it in C#?我应该如何声明 Microsoft.Office.Interop.Excel.Worksheet 以便可以在 C# 中关闭它?
【发布时间】:2016-04-25 14:51:15
【问题描述】:

我很难确保我的 COM 对象正在关闭,因此我不会让 EXCEL.EXE 进程在后台运行。我了解到声明的双点和链接是不好的,因为这可能会使 COM 对象悬而未决。

有谁知道如何修复这行代码,以便我可以正确关闭和释放工作表 COM 对象?

worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Sheets[strName];

编辑:当我完成执行此行以关闭打开的 Excel 对象时,我尝试使用 app.Quit(),但这不起作用。但是,如果我在此行之前调用 app.Quit() 就可以了。

【问题讨论】:

    标签: c# office-interop com-interop excel-interop


    【解决方案1】:

    首先,为了让 EXCEL.EXE 进程退出,您不必显式释放您使用的所有 COM 对象。当您获得对 COM 对象的另一个引用时,由 .NET 运行时为您隐式创建的运行时可调用包装器 (RCW) 由 GC 收集,这会释放底层 COM 对象。

    你所要做的就是调用 Quit 方法,释放 RCW 引用并让 GC 收集它们。

    //This runs the EXCEL.EXE process.
    Microsoft.Office.Interop.Excel.Application app = 
        new Microsoft.Office.Interop.Excel.Application();
    //This locks the excel file either for reading or writing 
    //depending on parameters.
    Microsoft.Office.Interop.Excel.Workbook book = app.Workbooks.Open(...);
    
    ...
    
    //Explicitly closing the book is a good thing. EXCEL.EXE is alive 
    //but the excel file gets released.
    book.Close();
    
    //This lets the EXCEL.EXE quit after you release all your references to RCWs
    //and let GC collect them and thus release the underlying COM objects. 
    //EXCEL.EXE does not close immediately after this though.
    app.Quit();
    app = null;
    

    其次,如果您保留所谓的双点代码行,则不会造成任何内存泄漏。垃圾收集器将收集 RCW 并在某个时间释放 COM 对象,即当它找到正确的时候。

    最后,如果您希望显式释放 RCW 和相应的 COM 对象以不惜一切代价最小化内存压力,您可以在释放对 RCW 的引用后显式调用 GC 来收集 RCW,甚至显式释放底层 COM GC 收集 RCW 之前的对象。不过要小心。最后一种方式让您对其余的 RCW 此后不再使用这一事实负责,否则您将遇到异常。

    using Microsoft.Office.Interop.Excel;
    using System.Runtime.InteropServices;
    
    Application app = new Application();
    Workbooks books = clsExcelApplication.Workbooks;
    Workbook book = books.Open("...");
    Sheets sheets = book.Sheets;
    Worksheet sheet = sheets["..."];
    
    ...
    
    //Trying to be as explicit as we can.
    book.Сlose();
    
    //Revese order. Using FinalReleaseComObject is even more dangerous. 
    //You might release an object used inside excel
    //code which might lead to some dreadful internal exceptions.
    int remainingRefCount;
    remainingRefCount = Marshal.ReleaseComObject(sheet);
    remainingRefCount = Marshal.ReleaseComObject(sheets);
    remainingRefCount = Marshal.ReleaseComObject(book);
    remainingRefCount = Marshal.ReleaseComObject(books);
    app.Quit();
    remainingRefCount = Marshal.ReleaseComObject(app);
    

    请记住。如果您手动释放 COM 引用,则 EXCEL.EXE 的生命周期不依赖于 RCW,您可以在需要时将其取消...

    sheet = null;
    sheets = null;
    book = null;
    books = null;
    app = null;
    

    在最明确的情况下,不要忘记检查 Marshal.ReleaseComObject 的返回。如果它不为零,那么除了你刚刚发布的 RCW 之外,其他人正在持有对底层 COM 对象的 COM 引用。

    【讨论】:

    • 我发现只要您确保关闭您处理的所有内容并发出 excelapp.Quit 就可以了 - 我确实在我找到的一些预制 exporttoexcel 代码中发现了一些问题,但也设置了 excelapp=null最后,这确保没有任何东西挂在任何东西上
    • GC 不释放 COM 组件。你必须明确地这样做。
    • @Enigmativity GC 不会释放通过某些 API 获得的纯 COM 对象,但它会释放通过 Runtime Callable Wrappers 获得的 COM 对象。在使用 excel 的情况下,它确实可以释放它们。
    • @BugFinder 将 excelapp 设置为 null 并没有太大变化。这只是释放您对与 excel 应用程序 COM 对象对应的 RCW 的引用。它不会影响 EXCEL.EXE 进程的结束,也不能确保您不持有对其他 RCW(COM 对象)的其他引用,例如工作簿或工作表。
    • 不,但我确实发现从长远来看它确实产生了实际影响,我从未调查过原因,但如果我评论该行,excel.exe 将保持打开状态。有了null,他们都走了。可靠准时。
    猜你喜欢
    • 1970-01-01
    • 2012-05-27
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    • 2014-06-29
    • 2010-11-07
    • 1970-01-01
    • 2015-09-17
    相关资源
    最近更新 更多