Excel进程仍在后台运行

时间:2014-02-26 18:44:31

标签: c# .net excel

我正在使用互操作库从一张excel文件中读取一些数据。我通过使用Microsoft.Office.Interop.Excel然后读取表格中的所有数据来获得数据。

Application ExcelApp = new Excel.Application();
Workbook excelWorkbook = ExcelApp2.Workbooks.Open(excelFileNamePath);
_Worksheet excelWorksheet = excelWorkbook.Sheets[excelSheetName];
Range excelRange = excelWorksheet.UsedRange;
//...for loops for reading data
ExcelApp.Quit();

但是在我的应用程序终止后,我尝试编辑我的excel文件并在打开时遇到一些问题。显然,即使我调用ExcelApp.Quit(),excel进程仍在后台运行。有没有办法正确关闭应用程序使用的excel文件?我是c#的新手,所以我可能在这里遗漏了一些东西。

编辑:解决了!显然有一个rule的com对象不鼓励使用2个点。

Excel.Application ExcelApp2 = new Excel.Application();
Excel.Workbooks excelWorkbooks = ExcelApp2.Workbooks;
Excel.Workbook excelWorkbook = excelWorkbooks.Open(excelFileName);
Excel._Worksheet excelWorksheet = excelWorkbook.Sheets[excelSheetName];
//...
excelWorkbook.Close();       
Marshal.ReleaseComObject(excelWorkbook);
Marshal.ReleaseComObject(excelWorksheet);
Marshal.ReleaseComObject(excelRange);
ExcelApp2.Quit();

5 个答案:

答案 0 :(得分:9)

还有另一个类似的问题 - 并回答(https://stackoverflow.com/a/17367570/3063884),其中解决方案是避免使用双点表示法。相反,为沿途使用的每个对象定义变量,并在每个对象上单独使用Marshal.ReleaseComObject

直接从链接的解决方案中复制:

var workbook = excel.Workbooks.Open(/*params*/)

--->而是使用 - >

var workbooks = excel.Workbooks;
var workbook = workbooks.Open(/*params*/)

然后,完成后,释放每个COM对象:

Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excel);

答案 1 :(得分:1)

您没有关闭工作簿。关闭它,然后在退出Excel应用程序之前将其释放:

excelWorkbook.close();
Marshal.ReleaseComObject(excelWorkbook);
ExcelApp.Quit();

答案 2 :(得分:1)

很久没有回答,但对我有用的是调用GC.Collect();来自来电者,

即。而不是

main()
{
    ...
    doexcelstuff();
    ...
}

void doexcelstuff()
{
    Excel.Application ExApp2 = new Excel.Application();
    Excel.Workbook excelWb = ExApp2 .Workbooks.Open(excelFName);
    Excel._Worksheet excelWorksheet = excelWb.Sheets[excelSName];
    //...
    excelWb.Close();
    ExApp2.Quit();     
    Marshal.ReleaseComObject(excelWb);
    Marshal.ReleaseComObject(excelWorksheet);
    Marshal.ReleaseComObject(ExApp2);
    excelWb = null;
    excelWorksheet= null;
    ExApp2= null;
    GC.Collect();
}

使用上面的Excel不会死亡

但是从

调用GC的位置变化非常小
main()
{
    ...
    doexcelstuff();
    GC.Collect();      // <<-- moved the GC to here (the caller)
    ...
}

void doexcelstuff()
{
    Excel.Application ExApp2 = new Excel.Application();
    Excel.Workbook excelWb = ExApp2 .Workbooks.Open(excelFName);
    Excel._Worksheet excelWorksheet = excelWb.Sheets[excelSName];
    //...
    excelWb.Close();
    ExApp2.Quit();     
    Marshal.ReleaseComObject(excelWb);
    Marshal.ReleaseComObject(excelWorksheet);
    Marshal.ReleaseComObject(ExApp2);
    excelWb = null;
    excelWorksheet= null;
    ExApp2= null;
    // removed the GC from here
}

我的猜测是垃圾收集器还需要从堆中安静地清理内部创建的临时值(包括引用/指针) - 其中一些我想在这种情况下指向COM对象。

(只需了解机器如何在源代码下工作。)

答案 3 :(得分:1)

这对我来说很有效!

//Initializing
Application excelApp = new Application();
Workbook excelWorkbook = excelApp.Workbooks.Open(pathExcelFile, 0, true, 5, "", "", 
                               true, XlPlatform.xlWindows, "\t", false, false, 0, 
                               true, 1, 0);
Worksheet excelWorksheet = (Worksheet)excelWorkbook.Sheets[1];

//closing
excelWorksheet = null;

excelWorkbook.Close();
excelWorkbook = null;

excelApp.Quit();
excelApp = null;

答案 4 :(得分:0)

Interop是出了名的错误...我保存工作簿后使用以下方法,退出应用程序时Excel不再存在问题:

while (Marshal.ReleaseComObject(wb) > 0);
while (Marshal.ReleaseComObject(xl) > 0);

wb = null;
xl = null;

GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

wb是我的工作簿对象,xl是我的Excel.Application对象。