http://blog.bossma.cn/dotnet/csharp-exorpt-excel-process-kill/
C#导出Excel后关闭进程(EXCEL.EXE)释放资源的解决方案
一年前,从网上找到一些C#导出MS Excel的例子,但是都不能彻底销毁其所创建的Excel进程,典型的就是进程中的EXCEL.EXE不能关掉。
网上的解决方案大部分是kill掉所有的Excel进程,偶一直感觉不爽。最近,做了几个月的WinForm,接触了一些进程、句柄方面的知识。于是试着解决一下,没想到成功了,创建的Excel进程被成功Kill掉了,而其它Excel进程则相安无事。
关键代码:
public void KillSpecialExcel() |
GetWindowThreadProcessId( new IntPtr(m_objExcel.Hwnd), out lpdwProcessId); |
System.Diagnostics.Process.GetProcessById(lpdwProcessId).Kill(); |
Console.WriteLine( "Delete Excel Process Error:" + ex.Message); |
操作生成Excel的全部代码:
using System.Collections.Generic; |
using System.Runtime.InteropServices; |
namespace VeryCodes.Common.MyExcel |
this .m_objExcel = new Microsoft.Office.Interop.Excel.Application(); |
public MSExcel(Microsoft.Office.Interop.Excel.Application objExcel) |
this .m_objExcel = objExcel; |
private string [] ALists = new string [] { |
"A" , "B" , "C" , "D" , "E" , "F" , "G" , "H" , "I" , "J" , "K" , "L" , "M" , "N" , "O" , "P" , "Q" , "R" , "S" , "T" , "U" , "V" , "W" , "X" , "Y" , "Z" , |
"AA" , "AB" , "AC" , "AD" , "AE" , "AF" , "AG" , "AH" , "AI" , "AJ" , "AK" , "AL" , "AM" , "AN" , "AO" , "AP" , "AQ" , "AR" , "AS" , "AT" , "AU" , "AV" , "AW" , "AX" , "AY" , "AZ" , |
"BA" , "BB" , "BC" , "BD" , "BE" , "BF" , "BG" , "BH" , "BI" , "BJ" , "BK" , "BL" , "BM" , "BN" , "BO" , "BP" , "BQ" , "BR" , "BS" , "BT" , "BU" , "BV" , "BW" , "BX" , "BY" , "BZ" , |
"CA" , "CB" , "CC" , "CD" , "CE" , "CF" , "CG" , "CH" , "CI" , "CJ" , "CK" , "CL" , "CM" , "CN" , "CO" , "CP" , "CQ" , "CR" , "CS" , "CT" , "CU" , "CV" , "CW" , "CX" , "CY" , "CZ" , |
"DA" , "DB" , "DC" , "DD" , "DE" , "DF" , "DG" , "DH" , "DI" , "DJ" , "DK" , "DL" , "DM" , "DN" , "DO" , "DP" , "DQ" , "DR" , "DS" , "DT" , "DU" , "DV" , "DW" , "DX" , "DY" , "DZ" , |
"EA" , "EB" , "EC" , "ED" , "EE" , "EF" , "EG" , "EH" , "EI" , "EJ" , "EK" , "EL" , "EM" , "EN" , "EO" , "EP" , "EQ" , "ER" , "ES" , "ET" , "EU" , "EV" , "EW" , "EX" , "EY" , "EZ" , |
"FA" , "FB" , "FC" , "FD" , "FE" , "FF" , "FG" , "FH" , "FI" , "FJ" , "FK" , "FL" , "FM" , "FN" , "FO" , "FP" , "FQ" , "FR" , "FS" , "FT" , "FU" , "FV" , "FW" , "FX" , "FY" , "FZ" , |
"GA" , "GB" , "GC" , "GD" , "GE" , "GF" , "GG" , "GH" , "GI" , "GJ" , "GK" , "GL" , "GM" , "GN" , "GO" , "GP" , "GQ" , "GR" , "GS" , "GT" , "GU" , "GV" , "GW" , "GX" , "GY" , "GZ" , |
"HA" , "HB" , "HC" , "HD" , "HE" , "HF" , "HG" , "HH" , "HI" , "HJ" , "HK" , "HL" , "HM" , "HN" , "HO" , "HP" , "HQ" , "HR" , "HS" , "HT" , "HU" , "HV" , "HW" , "HX" , "HY" , "HZ" , |
"IA" , "IB" , "IC" , "ID" , "IE" , "IF" , "IG" , "IH" , "II" , "IJ" , "IK" , "IL" , "IM" , "IN" , "IO" , "IP" , "IQ" , "IR" , "IS" , "IT" , "IU" , "IV" |
public string GetAix( int x, int y) |
if (x > 256) { return "" ; } |
s = s + ALists[x - 1].ToString(); |
public void setValue( int y, int x, string align, string text) |
Microsoft.Office.Interop.Excel.Range range = sheet.get_Range( this .GetAix(x, y), miss); |
range.set_Value(miss, text); |
if (align.ToUpper() == "CENTER" ) |
range.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter; |
if (align.ToUpper() == "LEFT" ) |
range.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignLeft; |
if (align.ToUpper() == "RIGHT" ) |
range.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignRight; |
public void setValue( int y, int x, string text) |
Microsoft.Office.Interop.Excel.Range range = sheet.get_Range( this .GetAix(x, y), miss); |
range.set_Value(miss, text); |
public void setValue( int y, int x, string text, System.Drawing.Font font, int color) |
this .setValue(x, y, text); |
Microsoft.Office.Interop.Excel.Range range = sheet.get_Range( this .GetAix(x, y), miss); |
range.Font.Size = font.Size; |
range.Font.Bold = font.Bold; |
range.Font.Color = ColorTranslator.ToOle(ColorTranslator.FromWin32(color)); |
range.Font.Name = font.Name; |
range.Font.Italic = font.Italic; |
range.Font.Underline = font.Underline; |
public void setValue( int y, int x, string text, System.Drawing.Font font, int color, string align) |
this .setValue(x, y, text); |
Microsoft.Office.Interop.Excel.Range range = sheet.get_Range( this .GetAix(x, y), miss); |
range.Font.Size = font.Size; |
range.Font.Bold = font.Bold; |
range.Font.Color = ColorTranslator.ToOle(ColorTranslator.FromWin32(color)); |
range.Font.Name = font.Name; |
range.Font.Italic = font.Italic; |
range.Font.Underline = font.Underline; |
if (align.ToUpper() == "CENTER" ) |
range.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter; |
if (align.ToUpper() == "LEFT" ) |
range.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignLeft; |
if (align.ToUpper() == "RIGHT" ) |
range.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignRight; |
public void insertRow( int y) |
Microsoft.Office.Interop.Excel.Range range = sheet.get_Range(GetAix(1, y), GetAix(255, y)); |
range.Insert(Microsoft.Office.Interop.Excel.XlDirection.xlDown, miss); |
range.get_Range(GetAix(1, y), GetAix(255, y)); |
string s = "a,b,c,d,e,f,g" ; |
sheet.Paste(sheet.get_Range( this .GetAix(10, 10), miss), s); |
public void setBorder( int x1, int y1, int x2, int y2, int Width) |
Microsoft.Office.Interop.Excel.Range range = sheet.get_Range( this .GetAix(x1, y1), this .GetAix(x2, y2)); |
range.Borders.Weight = Width; |
public void mergeCell( int x1, int y1, int x2, int y2) |
Microsoft.Office.Interop.Excel.Range range = sheet.get_Range( this .GetAix(x1, y1), this .GetAix(x2, y2)); |
public Microsoft.Office.Interop.Excel.Range getRange( int x1, int y1, int x2, int y2) |
Microsoft.Office.Interop.Excel.Range range = sheet.get_Range( this .GetAix(x1, y1), this .GetAix(x2, y2)); |
private object miss = Missing.Value; |
private Microsoft.Office.Interop.Excel.Application m_objExcel; |
private Microsoft.Office.Interop.Excel.Workbooks m_objBooks; |
private Microsoft.Office.Interop.Excel.Workbook m_objBook; |
private Microsoft.Office.Interop.Excel.Worksheet sheet; |
public Microsoft.Office.Interop.Excel.Worksheet CurrentSheet |
public Microsoft.Office.Interop.Excel.Workbooks CurrentWorkBooks |
public Microsoft.Office.Interop.Excel.Workbook CurrentWorkBook |
public void OpenExcelFile( string filename) |
m_objExcel.Workbooks.Open(filename, miss, miss, miss, miss, miss, miss, miss, |
miss, miss, miss, miss, miss, miss, miss); |
m_objBooks = (Microsoft.Office.Interop.Excel.Workbooks)m_objExcel.Workbooks; |
m_objBook = m_objExcel.ActiveWorkbook; |
sheet = (Microsoft.Office.Interop.Excel.Worksheet)m_objBook.ActiveSheet; |
public void UserControl( bool usercontrol) |
if (m_objExcel == null ) { return ; } |
m_objExcel.UserControl = usercontrol; |
m_objExcel.DisplayAlerts = usercontrol; |
m_objExcel.Visible = usercontrol; |
public void CreateExceFile() |
m_objBooks = (Microsoft.Office.Interop.Excel.Workbooks)m_objExcel.Workbooks; |
m_objBook = (Microsoft.Office.Interop.Excel.Workbook)(m_objBooks.Add(miss)); |
sheet = (Microsoft.Office.Interop.Excel.Worksheet)m_objBook.ActiveSheet; |
public void SaveAs( string FileName) |
m_objBook.SaveAs(FileName, miss, miss, miss, miss, |
miss, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, |
Microsoft.Office.Interop.Excel.XlSaveConflictResolution.xlLocalSessionChanges, |
public void ReleaseExcel() |
System.Runtime.InteropServices.Marshal.ReleaseComObject(( object )m_objExcel); |
System.Runtime.InteropServices.Marshal.ReleaseComObject(( object )m_objBooks); |
System.Runtime.InteropServices.Marshal.ReleaseComObject(( object )m_objBook); |
System.Runtime.InteropServices.Marshal.ReleaseComObject(( object )sheet); |
public bool KillAllExcel() |
System.Runtime.InteropServices.Marshal.ReleaseComObject(m_objExcel); |
foreach (System.Diagnostics.Process theProc in System.Diagnostics.Process.GetProcessesByName( "EXCEL" )) |
if (theProc.CloseMainWindow() == false ) |
#region Kill Special Excel Process |
[DllImport( "user32.dll" , SetLastError = true )] |
static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); |
public void KillSpecialExcel() |
GetWindowThreadProcessId( new IntPtr(m_objExcel.Hwnd), out lpdwProcessId); |
System.Diagnostics.Process.GetProcessById(lpdwProcessId).Kill(); |
Console.WriteLine( "Delete Excel Process Error:" + ex.Message); |
最关键的就是KillSpecialExcel()这个方法,找到Excel的进程ID,然后杀死这个进程。
断断续续找了很久,终于发现了这个方法。
看一个例子:
protected void Button1_Click( object sender, EventArgs e) |
MSExcel mexc = new MSExcel(); |
int col = (256 * 256 * 255) + (256 * 192) + 192; |
mexc.setValue(1, 1, "Demo" , new Font( "Arial" , 18), col, "center" ); |
mexc.mergeCell(1, 1, 4, 1); |
for ( int i = 2; i <= 101; i++) |
for ( int j = 1; j <= 4; j++) |
mexc.setValue(i, j, i + "--" + j); |
mexc.SaveAs( @"d:\demo.xls" ); |
其它方面还没有测试,有兴趣的话可以自己试试。
这似乎是一个完美的解决方案了,但是速度实在不敢保证,而且耗费的内存和CPU资源也比较多。
对于用户少较少的应用还可以凑合,并发多了,真不敢想象。
以前还用过生成csv文件的方法,但是格式没办法设置;
我想能不能直接构建excel的代码格式,然后保存成.xls,但是一直还没有成功。