互操作后Excel流程仍然开放;传统方法不起作用

时间:2012-01-23 19:39:57

标签: c# .net com excel-interop

我遇到了一些我正在调试的代码问题。 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的所有引用,则会成功关闭。

4 个答案:

答案 0 :(得分:12)

这对我来说很成功:

        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();

答案 1 :(得分:3)

我是一个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文化;)

答案 2 :(得分:2)

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

// 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();
}

答案 3 :(得分:2)

此代码适用于我。

//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();

This article from Microsoft有关此问题的一些很好的信息。