以前研究过的问题,最近有朋友问,这里再总结下作一个笔记。服务器
咱们在应用程序里面经过建立Excle应用对象打开Excle的状况下,若是不注意几个问题,可能没法完全关闭Excle进程,来考察下面的几种状况:ui
public static void startexcel() { var excel = new Microsoft.Office.Interop.Excel.Application(); excel.Visible = true; var book= excel.Application.Workbooks.Open("D:\\Book1.xlsx"); }
上面的代码打开了一个工做簿,Excel启动了一个独立进程而且呈现界面给用户,不会再犯方法结束后关闭Excel。这种状况下本意是为了让用户决定什么时候关闭工做簿。spa
结果,当用户手工关闭工做簿后,Excle进程没有关闭,这是由于咱们的.NET 托管代码打开的Excle的非托管代码,.NET运行时没有释放相关的句柄,须要加上下面几行代码来释放:excel
public static void startexcel() { var excel = new Microsoft.Office.Interop.Excel.Application(); excel.Visible = true; var book= excel.Application.Workbooks.Open("D:\\Book1.xlsx"); System.Runtime.InteropServices.Marshal.ReleaseComObject(excel); excel = null; GC.Collect(); }
上面的代码,Marshal.ReleaseComObject 会释放COM组件对象,这里是excel,而后,代码设置 excel=null,这样紧接着执行垃圾回收才有效,不然,没法回收excel句柄。code
注意,执行上面的代码并不会关闭了Excel进程,它只是释放了Excle进程句柄与.NET运行时的关系。对象
当用户在外面手工关闭Excle窗体后,Excle进程才会真正从任务管理器消失。blog
有朋友可能说,我没有加上面三行代码也可以关闭Excle进程啊。进程
没错,上面的代码只不过是当即释放了Excle这种非托管资源。注意到咱们的 excle对象是一个局部对象,因此当方法结束后,excle对象已经在方法堆栈上被清空了,只须要在外面合适的时候调用下垃圾回收,便可实现完全关闭Excle进程的效果:事件
startexcel(); GC.Collect(); Console.WriteLine("excel close ok.");
若是咱们的Excel进程不是由用户关闭而是要程序自动关闭怎么办?资源
这个时候只须要调用Excle应用程序对象的关闭方法便可。
完整的代码以下,而且下面的代码演示了Excle进程打开一个宏文件,而后再打开工做簿,处理事件,最后关闭Excle窗体,关闭进程清理资源的功能。
Excle的工做簿保存和关闭事件有时候比较有用,好比保存工做簿的时候就上传一份工做簿副本到服务器。
public static void startexcel() { var excel = new Microsoft.Office.Interop.Excel.Application(); excel.Visible = true; excel.Workbooks.Open("C:\\A1000.xla"); var book= excel.Application.Workbooks.Open("D:\\Book1.xlsx"); excel.WorkbookBeforeSave += Excel_WorkbookBeforeSave; excel.WorkbookBeforeClose += Excel_WorkbookBeforeClose; book.Close(); excel.Quit(); System.Runtime.InteropServices.Marshal.ReleaseComObject(excel); excel = null; GC.Collect(); } private static void Excel_WorkbookBeforeClose(Workbook Wb, ref bool Cancel) { Console.WriteLine("Excel 关闭,title:" + Wb.Title); } private static void Excel_WorkbookBeforeSave(Workbook Wb, bool SaveAsUI, ref bool Cancel) { Console.WriteLine("Excel保存,title:"+Wb.Title); }
注:
本文的作法,也适用于关闭Word等其它Office程序。