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



我调试的一些代码遇到了问题。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();
}

最新更新