在C#中安全地configurationExcel互操作对象?

我正在一个winforms c#visual studio 2008应用程序。 该应用程序会谈excel文件,我正在使用Microsoft.Office.Interop.Excel; 去做这个。

我想知道如何确保即使有错误,对象也被释放?

这是我的代码:

 private void button1_Click(object sender, EventArgs e) { string myBigFile=""; OpenFileDialog openFileDialog1 = new OpenFileDialog(); DialogResult result = openFileDialog1.ShowDialog(); // Show the dialog. if (result == DialogResult.OK) // Test result. myBigFile=openFileDialog1.FileName; Excel.Application xlApp; Excel.Workbook xlWorkBook; Excel.Worksheet xlWorkSheet; Excel.Range range; string str; int rCnt = 0; int cCnt = 0; xlApp = new Excel.ApplicationClass(); xlWorkBook = xlApp.Workbooks.Open(myBigFile, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", true, false, 0, true, 1, 0); xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1); range = xlWorkSheet.UsedRange; /* for (rCnt = 1; rCnt <= range.Rows.Count; rCnt++) { for (cCnt = 1; cCnt <= range.Columns.Count; cCnt++) { str = (string)(range.Cells[rCnt, cCnt] as Excel.Range).Value2; MessageBox.Show(str); } } */ xlWorkSheet..EntireRow.Delete(Excel.XLDirection.xlUp) xlWorkBook.SaveAs(xlWorkBook.Path + @"\XMLCopy.xls", Excel.XlFileFormat.xlXMLSpreadsheet, Type.Missing, Type.Missing, false, false, Excel.XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); xlWorkBook.Close(true, null, null); xlApp.Quit(); releaseObject(xlWorkSheet); releaseObject(xlWorkBook); releaseObject(xlApp); } private void releaseObject(object obj) { try { System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); obj = null; } catch (Exception ex) { obj = null; MessageBox.Show("Unable to release the Object " + ex.ToString()); } finally { GC.Collect(); } } 

我怎样才能确保,即使我打开工作簿后,我得到一个错误,我确保处置的对象:

 Excel.Application xlApp; Excel.Workbook xlWorkBook; Excel.Worksheet xlWorkSheet; Excel.Range range; 

换句话说,不pipe我需要下面几行来运行

 xlWorkBook.Close(true, null, null); xlApp.Quit(); releaseObject(xlWorkSheet); releaseObject(xlWorkBook); releaseObject(xlApp); 

请注意,我也试过这个,导致同样的问题

 xlWorkBook.Close(false, System.Reflection.Missing.Value, System.Reflection.Missing.Value); xlApp.Quit(); Marshal.ReleaseComObject(xlWorkSheet); Marshal.ReleaseComObject(xlWorkBook); Marshal.ReleaseComObject(xlApp); xlWorkSheet = null; xlWorkBook = null; xlApp = null; GC.GetTotalMemory(false); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.GetTotalMemory(true); 

我也这样做了:

 GC.Collect() ; GC.WaitForPendingFinalizers(); GC.Collect() ; GC.WaitForPendingFinalizers(); Marshal.FinalReleaseComObject(xlWorkSheet); xlWorkBook.Close(Type.Missing, Type.Missing, Type.Missing); Marshal.FinalReleaseComObject(xlWorkBook); xlApp.Quit(); Marshal.FinalReleaseComObject(xlApp); 

在这一点上,我不认为有可能从Visual Studio 2008closuresExcel。它一定是一个错误或什么的,但我已经尝试了前20名的网站,并得到相同的结果:Excel的是由于某种原因打开两个实例当我做垃圾收集等(或不)它closures只是一个实例。

当我尝试打开文件时,它说有错误或已损坏。

当我去任务pipe理器并杀死Excel的过程中,文件将打开没有问题。]

有没有办法closuresExcel的Visual Studio 2008? 如果是这样,请给我提供指导或解决scheme

首先我将介绍一个修改的releaseObject ,然后我将提供一个模式来使用它。

 using Marshal = System.Runtime.InteropServices.Marshal; private void releaseObject(ref object obj) // note ref! { // Do not catch an exception from this. // You may want to remove these guards depending on // what you think the semantics should be. if (obj != null && Marshal.IsComObject(obj)) { Marshal.ReleaseComObject(obj); } // Since passed "by ref" this assingment will be useful // (It was not useful in the original, and neither was the // GC.Collect.) obj = null; } 

现在,使用一个模式:

 private void button1_Click(object sender, EventArgs e) { // Declare. Assign a value to avoid a compiler error. Excel.Application xlApp = null; Excel.Workbook xlWorkBook = null; Excel.Worksheet xlWorkSheet = null; try { // Initialize xlApp = new Excel.ApplicationClass(); xlWorkBook = xlApp.Workbooks.Open(myBigFile, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", true, false, 0, true, 1, 0); // If the cast fails this like could "leak" a COM RCW // Since this "should never happen" I wouldn't worry about it. xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1); ... } finally { // Release all COM RCWs. // The "releaseObject" will just "do nothing" if null is passed, // so no need to check to find out which need to be released. // The "finally" is run in all cases, even if there was an exception // in the "try". // Note: passing "by ref" so afterwords "xlWorkSheet" will // evaluate to null. See "releaseObject". releaseObject(ref xlWorkSheet); releaseObject(ref xlWorkBook); // The Quit is done in the finally because we always // want to quit. It is no different than releasing RCWs. if (xlApp != null) { xlApp.Quit(); } releaseObject(ref xlApp); } } 

这种简单的方法可以扩展/嵌套在大多数情况下。 我使用一个实现了IDisposable的自定义包装类来使这个任务更容易。

确认您在代码中看到两个问题:

  • 当程序closuresExcel时仍然是一个正在运行的过程
  • 当你打开Excel文件时,你的程序会创build你在Excel中看到一个错误,说这个文件已经损坏或者其他的错误

我把你编辑的问题中的button1 click处理程序和pst的releaseObject方法复制到一个干净的VS2008,C#3.5 Winform应用程序中,并做了一些小的修改,以消除上面列出的两个问题。

要修复不从内存中卸载的Excel,请在您创build的range对象上调用releaseObject 。 在调用releaseObject(xlWorkSheet);之前执行此操作releaseObject(xlWorkSheet); 记住所有这些引用使得COM Interop编程非常有趣。

要修复损坏的Excel文件问题,请使用WorkBook.SaveAs更新您的WorkBook.SaveAs方法调用以replace第二个参数( Excel.XlFileFormat.xlXMLSpreadsheet )。 SaveAs方法将默认正确处理这个。

我确定你在问题中发布的代码被简化,可以帮助你debugging你遇到的问题。 你应该使用try..finally块pst演示。