互操作后Excel过程仍然保持打开状态; 传统方法不起作用

我遇到了一些我正在调试的代码问题。 Excel interop用于从工作簿中提取某些值; 但是,程序退出后Excel仍保持打开状态。 我已经尝试了传统的解决方案,但它仍然在运行代码的所有机器上保持对Excel的引用

private void TestExcel() { Excel.Application excel = new Excel.Application(); Excel.Workbooks books = excel.Workbooks; Excel.Workbook book = books.Open("C:\\test.xlsm"); book.Close(); books.Close(); excel.Quit(); Marshal.ReleaseComObject(book); Marshal.ReleaseComObject(books); Marshal.ReleaseComObject(excel); } 

即使是这段简单的代码也可以使进程运行多个文件(xlsm,xlsx,xls)。 现在我们有一个解决方法来杀死我们已经打开的Excel进程,但我更愿意让这个工作为我自己的理智。

我应该补充一点,我把它缩小到Workbook变量。 如果我删除对books.Open()的调用以及对book所有引用,则它会成功关闭。

这对我来说很成功:

  xlApp.Quit(); //release all memory - stop EXCEL.exe from hanging around. if (xlWorkBook != null) { Marshal.ReleaseComObject(xlWorkBook); } //release each workbook like this if (xlWorkSheet != null) { Marshal.ReleaseComObject(xlWorkSheet); } //release each worksheet like this if (xlApp != null) { Marshal.ReleaseComObject(xlApp); } //release the Excel application xlWorkBook = null; //set each memory reference to null. xlWorkSheet = null; xlApp = null; GC.Collect(); 

我是一个COM业余爱好者,很久以前在一个项目中用它来做一件小事,但这里有一个我用过的片段。 我可能在网上找到它,不记得了。 无论如何,我把它贴满了它的光彩;)

 public static class ComBlackBox { public static void ReleaseObject(object obj) { try { System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); obj = null; } catch (ArgumentException ex) { obj = null; MessageBox.Show("Unable to release the Object " + ex.Message); } finally { GC.Collect(); } } } 

我现在无法尝试,但它可能有用(我真的不记得任何细节)。 也许它会帮助你。 随意指出这个代码的任何明显问题,我真的远没有COM识字;)

这就是我解决这个问题的方法:

 // Store the Excel processes before opening. Process[] processesBefore = Process.GetProcessesByName("excel"); // Open the file in Excel. Application excelApplication = new Application(); Workbook excelWorkbook = excelApplication.Workbooks.Open(Filename); // Get Excel processes after opening the file. Process[] processesAfter = Process.GetProcessesByName("excel"); // Now find the process id that was created, and store it. int processID = 0; foreach (Process process in processesAfter) { if (!processesBefore.Select(p => p.Id).Contains(process.Id)) { processID = process.Id; } } // Do the Excel stuff // Now close the file with the COM object. excelWorkbook.Close(); excelApplication.Workbooks.Close(); excelApplication.Quit(); // And now kill the process. if (processID != 0) { Process process = Process.GetProcessById(processID); process.Kill(); } 

这段代码适合我。

 //Declare separate object variables Excel.Application xlApp = new Excel.Application(); Excel.Workbooks xlWorkbooks = xlApp.Workbooks; Excel.Workbook xlWorkbook = xlWorkbooks.Add(Missing.Value); Excel.Worksheet xlWorksheet = (Excel.Worksheet)xlWorkbook.Worksheets.get_Item(1); //Create worksheet xlWorkbook.Close(false, Missing.Value, Missing.Value); xlWorkbooks.Close(); xlApp.Quit(); Marshal.FinalReleaseComObject(xlWorksheet); Marshal.FinalReleaseComObject(xlWorkbook); Marshal.FinalReleaseComObject(xlWorkbooks); Marshal.FinalReleaseComObject(xlApp); xlWorksheet = null; xlWorkbook = null; xlWorkbooks = null; xlApp = null; GC.Collect(); 

Microsoft的这篇文章提供了有关此问题的一些很好的信息。