pro*_*ton 28 c# excel-interop winforms
我遇到了Excel Interop的问题.
即使我重新发布实例,Excel.exe也不会关闭.
这是我的代码:
using xl = Microsoft.Office.Interop.Excel;
xl.Application excel = new xl.Application();
excel.Visible = true;
excel.ScreenUpdating = false;
if (wordFile.Contains(".csv") || wordFile.Contains(".xls"))
{
//typeExcel become a string of the document name
string typeExcel = wordFile.ToString();
xl.Workbook workbook = excel.Workbooks.Open(typeExcel,
oMissing, oMissing, oMissing, oMissing,
oMissing, oMissing, oMissing, oMissing,
oMissing, oMissing, oMissing, oMissing,
oMissing, oMissing);
object outputFileName = null;
if (wordFile.Contains(".xls"))
{
outputFileName = wordFile.Replace(".xls", ".pdf");
}
else if (wordFile.Contains(".csv"))
{
outputFileName = wordFile.Replace(".csv", ".pdf");
}
workbook.ExportAsFixedFormat(XlFixedFormatType.xlTypePDF, outputFileName,
XlFixedFormatQuality.xlQualityStandard, oMissing,
oMissing, oMissing, oMissing, oMissing, oMissing);
object saveChanges = xl.XlSaveAction.xlDoNotSaveChanges;
((xl._Workbook)workbook).Close(saveChanges, oMissing, oMissing);
Marshal.ReleaseComObject(workbook);
workbook = null;
}
Run Code Online (Sandbox Code Playgroud)
我看到它,Marshal.RealeaseComObject
它应该是工作,但没有.我怎样才能解决这个问题?
谢谢.
Dzm*_*voi 67
简单规则:避免使用双点调用表达式,例如:
var workbook = excel.Workbooks.Open(/*params*/)
Run Code Online (Sandbox Code Playgroud)
...因为通过这种方式,您不仅可以创建RCW对象workbook
,而且还可以创建Workbooks
它,并且您也应该释放它(如果不维护对象的引用,这是不可能的).
所以,正确的方法是:
var workbooks = excel.Workbooks;
var workbook = workbooks.Open(/*params*/)
//business logic here
Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excel);
Run Code Online (Sandbox Code Playgroud)
qJa*_*ake 20
这是我写的一段代码,因为我遇到了和你一样的问题.基本上,您需要关闭工作簿,退出应用程序,然后释放所有COM对象(而不仅仅是Excel应用程序对象).最后,调用垃圾收集器以获得良好的测量.
/// <summary>
/// Disposes the current <see cref="ExcelGraph" /> object and cleans up any resources.
/// </summary>
public void Dispose()
{
// Cleanup
xWorkbook.Close(false);
xApp.Quit();
// Manual disposal because of COM
while (Marshal.ReleaseComObject(xApp) != 0) { }
while (Marshal.ReleaseComObject(xWorkbook) != 0) { }
while (Marshal.ReleaseComObject(xWorksheets) != 0) { }
while (Marshal.ReleaseComObject(xWorksheet) != 0) { }
while (Marshal.ReleaseComObject(xCharts) != 0) { }
while (Marshal.ReleaseComObject(xMyChart) != 0) { }
while (Marshal.ReleaseComObject(xGraph) != 0) { }
while (Marshal.ReleaseComObject(xSeriesColl) != 0) { }
while (Marshal.ReleaseComObject(xSeries) != 0) { }
xApp = null;
xWorkbook = null;
xWorksheets = null;
xWorksheet = null;
xCharts = null;
xMyChart = null;
xGraph = null;
xSeriesColl = null;
xSeries = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
Run Code Online (Sandbox Code Playgroud)
规则 - 永远不要再使用那一个点
- 一个点
var range = ((Range)xlWorksheet.Cells[rowIndex, setColumn]);
var hyperLinks = range.Hyperlinks;
hyperLinks.Add(range, data);
Run Code Online (Sandbox Code Playgroud)
- 两个或多个点
(Range)xlWorksheet.Cells[rowIndex, setColumn]).Hyperlinks.Add(range, data);
Run Code Online (Sandbox Code Playgroud)
- 例子
using Microsoft.Office.Interop.Excel;
Application xls = null;
Workbooks workBooks = null;
Workbook workBook = null;
Sheets sheets = null;
Worksheet workSheet1 = null;
Worksheet workSheet2 = null;
workBooks = xls.Workbooks;
workBook = workBooks.Open(workSpaceFile);
sheets = workBook.Worksheets;
workSheet1 = (Worksheet)sheets[1];
// removing from Memory
if (xls != null)
{
foreach (Microsoft.Office.Interop.Excel.Worksheet sheet in sheets)
{
ReleaseObject(sheet);
}
ReleaseObject(sheets);
workBook.Close();
ReleaseObject(workBook);
ReleaseObject(workBooks);
xls.Application.Quit(); // THIS IS WHAT IS CAUSES EXCEL TO CLOSE
xls.Quit();
ReleaseObject(xls);
sheets = null;
workBook = null;
workBooks = null;
xls = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
Run Code Online (Sandbox Code Playgroud)
摆脱所有引用是很棘手的,因为你必须猜测是否有如下调用:
var workbook = excel.Workbooks.Open("")
Run Code Online (Sandbox Code Playgroud)
创建一个Workbooks
您没有引用的实例.
甚至参考如下:
targetRange.Columns.AutoFit()
Run Code Online (Sandbox Code Playgroud)
将.Columns()
在您不知道并且未正确发布的情况下创建实例.
我最后写了一个包含对象引用列表的类,它可以按相反的顺序处理所有对象.
Add()
当您使用返回对象本身的Excel互操作时,该类具有您引用的任何对象和函数的列表:
public List<Object> _interopObjectList = new List<Object>();
public Excel.Application add(Excel.Application obj)
{
_interopObjectList.Add(obj);
return obj;
}
public Excel.Range add(Excel.Range obj)
{
_interopObjectList.Add(obj);
return obj;
}
public Excel.Workbook add(Excel.Workbook obj)
{
_interopObjectList.Add(obj);
return obj;
}
public Excel.Worksheet add(Excel.Worksheet obj)
{
_interopObjectList.Add(obj);
return obj;
}
public Excel.Worksheets add(Excel.Worksheets obj)
{
_interopObjectList.Add(obj);
return obj;
}
public Excel.Sheets add(Excel.Sheets obj)
{
_interopObjectList.Add(obj);
return obj;
}
public Excel.Workbooks add(Excel.Workbooks obj)
{
_interopObjectList.Add(obj);
return obj;
}
Run Code Online (Sandbox Code Playgroud)
然后取消注册对象我使用了以下代码:
//Release all registered interop objects in reverse order
public void unregister()
{
//Loop object list in reverse order and release Office object
for (int i=_interopObjectList.Count-1; i>=0 ; i -= 1)
{ ReleaseComObject(_interopObjectList[i]); }
//Clear object list
_interopObjectList.Clear();
}
/// <summary>
/// Release a com interop object
/// </summary>
/// <param name="obj"></param>
public static void ReleaseComObject(object obj)
{
if (obj != null && InteropServices.Marshal.IsComObject(obj))
try
{
InteropServices.Marshal.FinalReleaseComObject(obj);
}
catch { }
finally
{
obj = null;
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
Run Code Online (Sandbox Code Playgroud)
然后原则是创建类并捕获这样的引用:
//Create helper class
xlsHandler xlObj = new xlsHandler();
..
//Sample - Capture reference to excel application
Excel.Application _excelApp = xlObj.add(new Excel.Application());
..
//Sample - Call .Autofit() on a cell range and capture reference to .Columns()
xlObj.add(_targetCell.Columns).AutoFit();
..
//Release all objects collected by helper class
xlObj.unregister();
Run Code Online (Sandbox Code Playgroud)
也许不是美丽的代码,但可能激发一些有用的东西.
在您的代码中,您有:
excel.Workbooks.Open(...)
Run Code Online (Sandbox Code Playgroud)
excel.Workbooks
正在创建一个COM对象.然后,您Open
将从该COM对象调用该函数.但是,在完成后,您不会释放COM对象.
处理COM对象时,这是一个常见问题.基本上,表达式中不应该有多个点,因为在完成后需要清理COM对象.
这个话题太大了,无法在答案中完全探索,但我认为你会发现Jake Ginnivan关于这个主题的文章非常有用:VSTO和COM Interop
如果您厌倦了所有这些ReleaseComObject调用,您可能会发现这个问题很有用:
如何在C#,2012版中正确清理Excel互操作对象
正如其他答案中所述,使用两个点将创建无法由Marshal.FinalReleaseComObject
. 我只是想分享我的解决方案,它消除了记忆的需要Marshal.FinalReleaseComObject
——它真的很容易错过,而且很难找到罪魁祸首。
我使用了一个通用的 IDisposable 包装类,它可以用于任何 COM 对象。它的作用就像一个魅力,它让一切都保持干净整洁。我什至可以重用私有字段(例如this.worksheet
)。由于 IDisposable 的性质(Dispose 方法作为 运行finally
),它还会在出现错误时自动释放对象。
using Microsoft.Office.Interop.Excel;
public class ExcelService
{
private _Worksheet worksheet;
private class ComObject<TType> : IDisposable
{
public TType Instance { get; set; }
public ComObject(TType instance)
{
this.Instance = instance;
}
public void Dispose()
{
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(this.Instance);
}
}
public void CreateExcelFile(string fullFilePath)
{
using (var comApplication = new ComObject<Application>(new Application()))
{
var excelInstance = comApplication.Instance;
excelInstance.Visible = false;
excelInstance.DisplayAlerts = false;
try
{
using (var workbooks = new ComObject<Workbooks>(excelInstance.Workbooks))
using (var workbook = new ComObject<_Workbook>(workbooks.Instance.Add()))
using (var comSheets = new ComObject<Sheets>(workbook.Instance.Sheets))
{
using (var comSheet = new ComObject<_Worksheet>(comSheets.Instance["Sheet1"]))
{
this.worksheet = comSheet.Instance;
this.worksheet.Name = "Action";
this.worksheet.Visible = XlSheetVisibility.xlSheetHidden;
}
using (var comSheet = new ComObject<_Worksheet>(comSheets.Instance["Sheet2"]))
{
this.worksheet = comSheet.Instance;
this.worksheet.Name = "Status";
this.worksheet.Visible = XlSheetVisibility.xlSheetHidden;
}
using (var comSheet = new ComObject<_Worksheet>(comSheets.Instance["Sheet3"]))
{
this.worksheet = comSheet.Instance;
this.worksheet.Name = "ItemPrices";
this.worksheet.Activate();
using (var comRange = new ComObject<Range>(this.worksheet.Range["A4"]))
using (var comWindow = new ComObject<Window>(excelInstance.ActiveWindow))
{
comRange.Instance.Select();
comWindow.Instance.FreezePanes = true;
}
}
if (this.fullFilePath != null)
{
var currentWorkbook = (workbook.Instance as _Workbook);
currentWorkbook.SaveAs(this.fullFilePath, XlFileFormat.xlWorkbookNormal);
currentWorkbook.Close(false);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
throw;
}
finally
{
// Close Excel instance
excelInstance.Quit();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
49820 次 |
最近记录: |