2014-02-26 174 views
4

我正在使用interop库从excel文件的工作表中读取一些数据。我通过使用Microsoft.Office.Interop.Excel获得数据,然后读取表单中的所有数据。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(); 
+0

在看一看:http://stackoverflow.com/questions/9962157/safely-disposing-excel-interop-objects -in-c – CJBS

+0

你有没有试过这个:http://support.microsoft。com/kb/Q317109 –

+0

@CJBS他们也没有找到答案!但我会尝试实施其中的一个建议。谢谢! – rrh

回答

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); 
+0

我刚刚发现同样的问题,它的工作!谢谢。 – rrh

+0

不客气。 COM可能很混乱。 – CJBS

1

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

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

错误仍然弹出。它说“名称为...的文档已经打开” – rrh

0

互操作是出了名的越野车......我用我的节能工作簿,不再有使用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对象。

+0

这似乎也不起作用。我可以看到它现在是多么的怪异,这太令人讨厌了! – rrh

+0

在调用上面的代码之前,你正在保存并关闭你的东西吗? 我这样做: wb.SaveAs( \t _saveFile, \t Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookDefault, \t Type.Missing, \t Type.Missing, \t假, \t假的, \t Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, \t Type.Missing, \t Type.Missing, \t Type.Missing, \t Type.Missing, \t Type.Missing ); wb.Saved = true; – John

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 
} 

称为我的猜测是垃圾收集器还需要静静地清理堆内部创建的临时值(包括refs/pointers) - 一些我猜在这种情况下,它指向COM对象。

(只是需要的机器的源代码下面是如何工作的理解点点。)