使用C#操作Excel的COM组件的过程中,最后把EXCEL进程关闭掉是十分重要的。网上有一些方法,我总结了其中两条,并测试通过。
首先第一种是利用.net的GC,即垃圾回收器。代码如下:
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Runtime.InteropServices;
5
6 namespace ExcelTest
7 {
8 class DataOutput
9 {
10 static void Main(string[] args)
11 {
12 Excel.Application app = new Excel.ApplicationClass();
13 Excel.Workbook wBook = app.Workbooks.Add(true);
14 Excel.Worksheet wSheet = wBook.Worksheets[1] as Excel.Worksheet;
15 app.Visible = true;
16
17 System.Runtime.InteropServices.Marshal.ReleaseComObject(wSheet);
18 System.Runtime.InteropServices.Marshal.ReleaseComObject(wBook);
19 System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
20 GC.Collect(); //显式调用GC
21
22 Console.Read();
23 }
24 }
25 }
关注后面四行,System.Runtime.InteropServices.Marshal类主要提供对非受托管内存的操作。对于函数ReleaseComObject,在MSDN上的解释是“该运行库可调用包装具有引用计数,每次将 COM 接口指针映射到该运行库可调用包装时,此引用计数都将递增。ReleaseComObject 方法递减运行库可调用包装的引用计数。当引用计数达到零时,运行库将释放非托管 COM 对象上的所有引用。”即断开对对象的引用,这样GC发现对象不会再被使用,那么就会回收它。
第二种方法是通过进程的ID号把进程kill掉。但第一种方法有网友说有时候不灵,因为本人只是简单地用控制台来测试,可能在其它情况下不一定行,所以推荐使用第二种方法。
1 namespace ExcelTest
2 {
3 class DataOutput
4 {
5 static void Main(string[] args)
6 {
7 Excel.Application app = new Excel.ApplicationClass();
8 Excel.Workbook wBook = app.Workbooks.Add(true);
9 Excel.Worksheet wSheet = wBook.Worksheets[1] as Excel.Worksheet;
10 app.Visible = true;
11
12 Kill(app);
13
14 Console.Read();
15 }
16
17 [DllImport("User32.dll", CharSet = CharSet.Auto)]
18 public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
19
20 public static void Kill(Excel.Application excel)
21 {
22 IntPtr t = new IntPtr(excel.Hwnd); //得到这个句柄,具体作用是得到这块内存入口
23
24 int k = 0;
25 GetWindowThreadProcessId(t, out k); //得到本进程唯一标志k
26 System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(k); //得到对进程k的引用
27 p.Kill(); //关闭进程k
28
29 }
30 }
31 }
GetWindowThreadProcessId函数是User32.dll中函数,作用是通过对象的句柄得到对象的进程ID。extern 修饰符用于声明在外部实现的方法。明白这点后,整个过程就很简单了:其实就是先获得Excel.Application实例app的句柄,再通过句柄得到进程ID,最后把该ID的进程Kill掉。