在Windows服务中从C#中删除EXCEL.exe进程

我有一个Windows服务,通过Microsoft.Office.Interop.Excel.Application对象打开Excel电子表格。

Application xlApp = new Application(); Workbook workbook = xlApp.Workbooks.Open(fileName, 2, false); ... ... workbook.Close(); xlApp.Quit(); 

我想杀死EXCEL.exe进程,在完成工作簿的工作后仍然运行。

我试过以下没有成功…

 // This returns a processId of 0 IntPtr processId; GetWindowThreadProcessId(new IntPtr(xlApp.Hwnd), out processId); Process p = Process.GetProcessById(processId.ToInt32()); p.Kill(); 

任何人有任何想法,我怎样才能通过Windows服务做到这一点?

正确地closures打开的Excel工作簿并退出应用程序是非常困难的。 如果我能find链接,我将发布它们,但基本上你必须清除所有对你创build的COM对象的引用 。 这包括ODBCConnections(数据连接),工作表,工作簿和Excel应用程序的所有内容。 我得到的组合涉及垃圾收集和System.Runtime.InteropServices.Marshal对象:

 // Garbage collecting GC.Collect(); GC.WaitForPendingFinalizers(); // Clean up references to all COM objects // As per above, you're just using a Workbook and Excel Application instance, so release them: workbook.Close(false, Missing.Value, Missing.Value); xlApp.Quit(); Marshal.FinalReleaseComObject(workbook); Marshal.FinalReleaseComObject(xlApp); 

就像你提到的那样,循环和杀死每个Excel进程通常不是一个好主意,因为如果你将它作为一个Windows应用运行,你可以在用户上closuresExcel,或者在一个服务中closures正在运行的Excel实例通过其他程序。

编辑:看到这个问题的更多信息。

经过多less阅读和挫折,我find了解决办法!

所有功劳都归功于dotNetkow , nightcoder和Mike Rosenblum在这篇文章中的解决scheme: 我如何正确清理Excel互操作对象?

这是我做的…
1.将项目的构build模式更改为“释放”(在DEBUG模式下,COM对象很难处理其引用。
2.删除所有的双点expression式(所有的COM对象应该绑定到一个variables,以便他们可以被释放)
3.在finally块中显式调用GC.Collect(),GC.WaitForPendingFinalizers()和Marshal.FinalReleaseComObject()

这是我正在使用的acutal代码:

 Application xlApp = null; Workbooks workbooks = null; Workbook workbook = null; Worksheet sheet = null; Range r = null; object obj = null; try { xlApp = new Application(); xlApp.DisplayAlerts = false; xlApp.AskToUpdateLinks = false; workbooks = xlApp.Workbooks; workbook = workbooks.Open(fileName, 2, false); sheet = workbook.Worksheets[1]; r = sheet.get_Range("F19"); obj = r.get_Value(XlRangeValueDataType.xlRangeValueDefault); } finally { GC.Collect(); GC.WaitForPendingFinalizers(); if (value != null) Marshal.FinalReleaseComObject(value); if (r != null) Marshal.FinalReleaseComObject(r); if (sheet != null) Marshal.FinalReleaseComObject(sheet); if (workbooks != null) Marshal.FinalReleaseComObject(workbooks); if (workbook != null) { workbook.Close(Type.Missing, Type.Missing, Type.Missing); Marshal.FinalReleaseComObject(workbook); } if (xlApp != null) { xlApp.Quit(); Marshal.FinalReleaseComObject(xlApp); } } 

您需要检查文件句柄并获取PID,然后按进程打开,然后将其终止。 它为我工作。

 private void genExcel( { int pid = -1; //Get PID xlApp = new Excel.Application(); HandleRef hwnd = new HandleRef(xlApp, (IntPtr)xlApp.Hwnd); GetWindowThreadProcessId(hwnd, out pid); . . . . //Finally KillProcess(pid,"EXCEL"); } [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern int GetWindowThreadProcessId(HandleRef handle, out int processId); private void KillProcess(int pid, string processName) { // to kill current process of excel System.Diagnostics.Process[] AllProcesses = System.Diagnostics.Process.GetProcessesByName(processName); foreach (System.Diagnostics.Process process in AllProcesses) { if (process.Id == pid) { process.Kill(); } } AllProcesses = null; } 

我不知道我的答案是不是你正在寻找…如果是这样告诉我,我会删除它。 无论如何,我用这个:

 Application xlApp = new Application(); xlApp.DisplayAlerts = false; xlApp.Visible = true; // Only for debug purposes Workbook workbook = xlApp.Workbooks.Open(filename, 2, false); ... ... workbook.Close(); xlApp.Quit(); 

closures工作簿并退出xlApp从我的电脑内存中删除EXCEL.EXE。
我正在使用Windows XP 32位和Microsoft Office 2007。

我也尝试在使用这个testing应用程序之前打开另一个excel文件:第二个EXCEL.EXE被打开并且(使用Quit)在最后被closures,保持第一个实例不变。

我用了一个简单而有效的解决scheme

 finally { GC.Collect(); GC.WaitForPendingFinalizers(); if (xlApp != null) { xlApp .Quit(); int hWnd = xlApp .Application.Hwnd; uint processID;GetWindowThreadProcessId((IntPtr)hWnd, out processID); Process[] procs = Process.GetProcessesByName("EXCEL"); foreach (Process p in procs) { if (p.Id == processID) p.Kill(); } Marshal.FinalReleaseComObject(xlApp ); } } 

find所有Excell.exe进程。 然后获得我的Excel应用程序的进程ID。 杀死只有id匹配的进程。 用于在类中声明GetWindowThreadProcessId:

 [DllImport("user32.dll")] private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); 

我的解决scheme

 [DllImport("user32.dll")] static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId); private void GenerateExcel() { var excel = new Microsoft.Office.Interop.Excel.Application(); int id; // Find the Process Id GetWindowThreadProcessId(excel.Hwnd, out id); Process excelProcess = Process.GetProcessById(id); try { // Your code } finally { excel.Quit(); // Kill him ! excelProcess.Kill(); } 

下面是打开和删除Excel实例的代码。 我们只需要确保所有与Excel相关的对象都closures。

  string strFilePath = @"C:\Sample.xlsx"; try { Excel.Application excelApp = null; Excel.Workbook excelWorkbook = null; Excel.Sheets excelSheets = null; Excel.Worksheet excelWorksheet = null; Excel.Workbooks excelWorkbooks = null; Excel.Range excelUsedRange = null; excelApp = new Microsoft.Office.Interop.Excel.Application(); int nData = excelApp.Hwnd; // excelApp = new Excel.ApplicationClass(); //excelApp.Visible = true; excelWorkbooks = excelApp.Workbooks; excelWorkbook = excelWorkbooks.Add(System.Reflection.Missing.Value); excelWorkbook = excelApp.Workbooks.Open(strFilePath, 2, false); //excelWorkbook = excelApp.Workbooks.Open(strFilePath, // Type.Missing, Type.Missing, // Type.Missing, Type.Missing, // Type.Missing, Type.Missing, // Type.Missing, Type.Missing, // Type.Missing, Type.Missing, // Type.Missing, Type.Missing, // Type.Missing, Type.Missing); excelSheets = excelWorkbook.Worksheets; // excelWorksheet = (Excel.Worksheet)excelSheets.get_Item(1); excelWorksheet = (Excel.Worksheet)excelWorkbook.Worksheets["Dem0_1"]; excelUsedRange = excelWorksheet.UsedRange; //Excel.Range lastCell = usedRange.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing); //int lastRow = lastCell.Row; //int lastCol = lastCell.Column; //int rowMin = lastRow + 1; //int colMin = lastCol + 1; int nRowsCount = excelUsedRange.Rows.Count; int nColCount = excelUsedRange.Columns.Count; int N_Quality_Header = -1; int N_Measurement_Name = -1; int N_Lower_Tolerance = -1; int N_Upper_Tolerance = -1; //Read the Columns Index for (int nColIndex = 1; nColIndex <= nColCount; nColIndex++) { Excel.Range cell = usedRange.Cells[1, nColIndex] as Excel.Range; String strCellValue = cell.Value2.ToString(); if (strCellValue == "Quality Header") N_Quality_Header = nColIndex; else if (strCellValue.IndexOf("Measurement Name", StringComparison.OrdinalIgnoreCase) > -1) N_Measurement_Name = nColIndex; else if (strCellValue.IndexOf("Lower Tolerance", StringComparison.OrdinalIgnoreCase) > -1) N_Lower_Tolerance = nColIndex; else if (strCellValue.IndexOf("Upper Tolerance", StringComparison.OrdinalIgnoreCase) > -1) N_Upper_Tolerance = nColIndex; } //Read all rows to get the values for (int nRowIndex = 2; nRowIndex <= nRowsCount; nRowIndex++) { Excel.Range cellQualityHeader = usedRange.Cells[nRowIndex, N_Quality_Header] as Excel.Range; String strValue = cellQualityHeader.Value2.ToString(); if (strValue == String_Empty) continue; } } catch (Exception oException) { } finally { excelUsedRange.Clear(); //excelWorkbook.Save(); excelWorkbook.Close(false, System.Reflection.Missing.Value, System.Reflection.Missing.Value); excelWorkbooks.Close(); excelApp.Quit(); Marshal.ReleaseComObject(excelUsedRange); Marshal.ReleaseComObject(excelWorksheet); Marshal.ReleaseComObject(excelSheets); Marshal.ReleaseComObject(excelWorkbooks); Marshal.ReleaseComObject(excelWorkbook); Marshal.ReleaseComObject(excelApp); excelUsedRange = null; excelWorksheet = null; excelSheets = null; excelWorkbooks = null; excelWorkbook = null; excelApp = null; GC.GetTotalMemory(false); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.GetTotalMemory(true); } 

我会使用Process.GetProcess并寻找在那里的exe我不会相信任何事情与服务世界中的窗口,因为我认为窗口创build在您无法访问的deskstation上。

我在用:

 Process[] AllProcesses = Process.GetProcessesByName("EXCEL.EXE"); 

让这个过程死亡。

也许它不是很优雅,但我最终结合了公认的解决scheme和Safrin的解决scheme。 所以首先,我试图做到这一点,如果它失败,我使用蛮力。 原因是代码是批处理程序的一部分,即使在一个Excel刷新操作失败时也必须能够继续执行。 我的问题是,有些故障与PowerPivot模型中的故障有关,它带来了一个带有错误信息的对话框。 这个对话框是不可见的,因为它作为后台进程运行,看起来Excel不会closures,我的进程不会继续,直到closures对话框(?!)。 所以开始在一个单独的线程与超时机制的过程,并杀死Excel处理我的工作对象,如果quiting不起作用是唯一的解决scheme,我能想到的(那工程)…

  public void Dispose() { GC.Collect(); GC.WaitForPendingFinalizers(); if (workbook != null) { try { workbook.Close(false); Marshal.FinalReleaseComObject(workbook); } catch { } } if (excel != null) { try { excel.Quit(); } catch { int hWnd = excel.Application.Hwnd; uint processID; GetWindowThreadProcessId((IntPtr)hWnd, out processID); Process[] procs = Process.GetProcessesByName("EXCEL"); foreach (Process p in procs) { if (p.Id == processID) p.Kill(); } } Marshal.FinalReleaseComObject(excel); } } 

这是我的代码杀死所有未使用的Excel进程

 Process[] process = Process.GetProcessesByName("excel"); foreach (Process excel in process) { if (excel.HasExited) { excel.Kill(); } } process = null;