关于VSTO调用Excel后进程无法退出的解决方案:
VSTO的Excel对象模型提供了托管代码对Excel的操作。但是它的实现时通过RCW(Runtime Com Wrapper)实现的,所以无法完全按照托管代码的运行方式操作。COM的资源释放时通过引用计数的方式实现,不同于CLR的GC机制,在引用计数没有设置为0的情况下,是不会回收资源的。所以,很多情况下,在操作Excel的时候,进程无法结束,其实就是因为Excel的COM计数器没有置0.
那么,如何才能正确地将计数器置0呢?简单代码如下。
//启动Excel的程序 Excel.Application app = new Excel.Application(); //获取Excel的所有工作簿,注意,不可以使用.net级联方式,即如app.Workbooks.Add() //必须每个变量都设置引用,这样才可以逐个释放变量,切记,重中之重 Excel.Workbooks wbs = app.Workbooks; //获取一个工作簿 Excel.Workbook wb = wbs.Add(); //获取当前工作表 Excel.Worksheet ws = wb.ActiveSheet; //声明一个表示Excel区域的变量,并利用其对Excel进行操作 Excel.Range rng; rng = ws.Range["A1"]; rng.Value2 = "Hello"; //将该变量引用的Com对象的计数器设置为0,并设置引用为null,释放对象 System.Runtime.InteropServices.Marshal.FinalReleaseComObject(rng); rng = null; //同上 rng = ws.Range["A2"]; rng.Value2 = "Again"; System.Runtime.InteropServices.Marshal.FinalReleaseComObject(rng); rng = null; //释放工作表 System.Runtime.InteropServices.Marshal.FinalReleaseComObject(ws); ws = null; //释放工作簿集合 System.Runtime.InteropServices.Marshal.FinalReleaseComObject(wbs); wbs = null; //保存文档 wb.SaveAs(@"d:\hello.xlsx"); //释放工作簿 System.Runtime.InteropServices.Marshal.FinalReleaseComObject(wb); wb = null; //通知Excel主机退出程序 app.Quit(); //最后,释放Excel主机的引用计数器 System.Runtime.InteropServices.Marshal.FinalReleaseComObject(app); app = null;
如此,进程中的Excel将自动退出,我们也就避免强制结束进程带来的Excel报错问题。
这里的要点就是:任何一个Com对象的引用在指向其他对象之前必须显示释放其对该Com的引用。最后,释放所有的Excel对象的引用计数!