互操作后Excel进程保持打开状态;传统方法不起作用
本文关键字:状态 传统 方法 不起作用 Excel 进程 互操作 | 更新日期: 2023-09-27 18:21:15
我调试的一些代码遇到了问题。Excel互操作用于从工作簿中提取一些值;但是,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();
此代码适用于我。
//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();
这篇来自微软的文章提供了一些关于这个问题的好信息。
我是一个完全的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();
}