正确关闭 C# excel COM 对象
Posted
技术标签:
【中文标题】正确关闭 C# excel COM 对象【英文标题】:Closing C# excel COM object properly 【发布时间】:2013-09-23 00:27:40 【问题描述】:我正在尝试正确关闭 excel COM 对象,例如 excel 应用程序工作簿和工作表。我已经浏览了这个站点和其他站点上的所有解决方案。没有任何效果。唯一的方法是运行一个循环来杀死或超越进程。有没有更好的方法或方法可以只杀死单个 excel 文件进程?
#region VARIABLE
int nColumn = 0;
int nIMPORT = 1;
int endofsheet = 0;
string IMPORTfilepath = null;
string nsheet = null;
string nCell = null;
string lastfilename = "";
double rRFDS = 0;
double cRFDS = 0;
List<String> filename = new List<String>();
object misValue1 = System.Reflection.Missing.Value;
//Opening Central DB
Excel.Application CentralDB;
Excel.Workbook CentralDBWorkBook;
Excel.Worksheet CentralDBWorkSheet;
Excel.Range CentralDBrange;
//Opening RFDS
Excel.Application IMPORT;
Excel.Workbook IMPORTWorkBook;
Excel.Worksheet IMPORTWorkSheet;
//Excel.Range RFDSrange;
Excel.Range CellAddress;
#endregion
CentralDB = new Microsoft.Office.Interop.Excel.Application();
CentralDBWorkBook = CentralDB.Workbooks.Open(Odl1.FileName, 0, false, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
CentralDBWorkSheet = CentralDB.Worksheets.get_Item(1);
IMPORT = new Microsoft.Office.Interop.Excel.Application();
IMPORTfilepath = Odl2.FileNames[nIMPORT];
IMPORTWorkBook = IMPORT.Workbooks.Open(IMPORTfilepath, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
IMPORTWorkSheet = IMPORT.Worksheets.get_Item(1);
CentralDBrange = CentralDBWorkSheet.UsedRange;
filename = Odl2.FileNames.ToList();
endofsheet = CentralDBrange.Rows.Count;
foreach(string fn in filename)
try
IMPORTWorkBook = IMPORT.Workbooks.Open(fn, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
CentralDBWorkSheet.Cells[nIMPORT + endofsheet, 1] = IMPORTWorkBook.Name;
for (nColumn = 3; nColumn <= CentralDBrange.Columns.Count; nColumn++)
nsheet = (string)(CentralDBrange.Cells[2, nColumn].Value2);
foreach (Excel.Worksheet ws in IMPORTWorkBook.Sheets)
if (ws.Name.Equals(nsheet))
IMPORTWorkSheet = IMPORTWorkBook.Worksheets.get_Item(nsheet);
nCell = (string)(CentralDBrange.Cells[3, nColumn].Value2);
CellAddress = CentralDBWorkSheet.get_Range(nCell, nCell);
rRFDS = CellAddress.Row;
cRFDS = CellAddress.Column;
CentralDBWorkSheet.Cells[nIMPORT + endofsheet, nColumn] = IMPORTWorkSheet.Cells[rRFDS, cRFDS];
label4.Text = nIMPORT.ToString() + "/" + Convert.ToString(Odl2.FileNames.Count());
nIMPORT++;
nColumn = 3;
CentralDBWorkBook.Save();
IMPORTWorkBook.Close(false, null, null);
catch (System.Exception ex)
MessageBox.Show("Unable to release the Object " + ex.ToString());
lastfilename = fn;
CentralDB.Quit();
releaseObject(CentralDBWorkSheet);
releaseObject(CentralDBWorkBook);
releaseObject(CentralDB);
IMPORT.Quit();
releaseObject(IMPORTWorkSheet);
releaseObject(IMPORTWorkBook);
releaseObject(IMPORT);
GC.Collect();
private void releaseObject(object obj)
try
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
catch (System.Exception ex)
obj = null;
MessageBox.Show("Unable to release the Object " + ex.ToString());
finally
GC.Collect();
【问题讨论】:
也许之前的question 可以帮到你。 提示:尽可能少地使用对 Excel 的引用,并且尽量不要将其存储在本地/临时变量中。我还会考虑为 Excel 实例制作单例模式。 【参考方案1】:试试这个顺序(加上.Visible = false
):
releaseObject(CentralDBWorkSheet);
releaseObject(CentralDBWorkBook);
releaseObject(IMPORTWorkSheet);
releaseObject(IMPORTWorkBook);
CentralDB.Visible = false;
IMPORT.Visible = false;
CentralDB.Quit();
IMPORT.Quit();
releaseObject(CentralDB);
releaseObject(IMPORT);
【讨论】:
使用该订单不走运【参考方案2】:除了我的评论... 我使用它并且工作得很好......但同样,我没有到处都有参考资料。
private void DoReleaseCOMObject(object obj)
int refCounter = Marshal.ReleaseComObject(obj);
while (refCounter > 0)
refCounter = Marshal.ReleaseComObject(obj);
System.Diagnostics.Debug.WriteLine("ReleaseCOM ref: " + refCounter);
obj = null;
private void DoFinalReleaseCOMObject(object obj)
int refCounter = Marshal.FinalReleaseComObject(obj);
System.Diagnostics.Debug.WriteLine("FinalReleaseComObject ref: " + refCounter);
obj = null;
public void Dispose()
System.Diagnostics.Debug.WriteLine("In Dispose");
this.Dispose(false); // because we are doing unmanaged
GC.Collect();
GC.SuppressFinalize(this);
protected virtual void Dispose(bool disposing)
System.Diagnostics.Debug.WriteLine("In Dispose (" + disposing + ")");
if (!disposing) // unmanaged
#region COM Cleanup
this.DoFinalReleaseCOMObject(this.headerStartCell);
this.DoFinalReleaseCOMObject(this.headerEndCell);
this.DoFinalReleaseCOMObject(this.headerWriteRange);
this.DoFinalReleaseCOMObject(this.startCell);
this.DoFinalReleaseCOMObject(this.endCell);
this.DoFinalReleaseCOMObject(this.writeRange);
this.DoFinalReleaseCOMObject(this.ws);
this.DoFinalReleaseCOMObject(this.wb);
this.DoFinalReleaseCOMObject(this.wbs);
this.DoFinalReleaseCOMObject(this.excelApp);
System.Diagnostics.Debug.WriteLine("I've tried to clean");
#endregion
// no need for else condition if dispose is true as we are not dealing with managed objects
是的,我实现了 IDisposable 接口。我还引用了一些全局引用/持有的 Excel 对象(相同的实例),这就是我退出 Excel 后要清理的内容
【讨论】:
以上是关于正确关闭 C# excel COM 对象的主要内容,如果未能解决你的问题,请参考以下文章