我正在设计一个WPF应用程序,我打开一个excel文件,然后在其中写入一些数据然后关闭它。现在我还需要发送电子邮件到我需要附加此excel文件的电子邮件地址。但是在附加它时抛出了一个异常,即该文件被另一个进程使用。我查看了任务管理器,发现Microsoft excel正在后台运行。
我寻找了一些可用的解决方案并编辑了如下代码:
xlWorksheet.SaveAs("C:\\Data.xlsx");
Marshal.FinalReleaseComObject(xlWorksheet);
xlWorkbook.Close();
Marshal.FinalReleaseComObject(xlWorkbook);
xlApp.Quit();
Marshal.FinalReleaseComObject(xlApp);
现在这似乎有效,因为它关闭了微软excel。但结束需要花费很多时间。有时它立即关闭excel但有时需要3-5分钟才能关闭excel。因为我需要在excel中保存数据后发送电子邮件,然后如何处理这种情况。在我的应用程序中,用户将按下按钮并执行以下任务:
现在在附件中,它失败了,因为excel在后台打开所以它显示错误。如何立即关闭excel表。有没有替代方案的解决方案。
答案 0 :(得分:3)
使用Excel互操作时,您必须超级按钮。我不会重新发布SO上已有的所有内容,但这里是我的ExcelInterfacer类的介绍注释:
/*
General rules on working with interop COM objects boil down to "Never use 2 dots" (always hold a named
reference to all COM objects so that you can explicitely release them via Marshal.FinalReleaseComObject()):
https://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects/1307180#1307180
Also, don't force the GC to cleanup in the same method where objects are used (or debugging breaks):
https://stackoverflow.com/questions/17130382/understanding-garbage-collection-in-net/17131389#17131389
(We initiate our GC calls when disposing.)
*/
How do I properly clean up Excel interop objects?
Understanding garbage collection in .NET
在我的程序中,我只在必要时打开Excel,并且总是将ExcelInterfacer类包装在using块中。为此,你必须实现IDisposable,但这很容易。这样做,我的Excel进程在它们不再使用后很快就会关闭,但是你仍然是垃圾收集的奴隶 - 除非你立刻强制它,我猜。
在using()块之后的下一个代码语句中,我从未尝试过使用Excel文档。您可能想要检查要邮寄的隐藏的〜$版本的Excel文件是否仍然存在或已关闭。这将清楚地表明该文件是可访问的。
我的建议:
从那里开始:)作为参考,来自我的Excel界面类的IDisposable代码:
// Properly clean up Excel on quitting. See:
// https://stackoverflow.com/questions/2260990/com-object-that-has-been-separated-from-its-underlying-rcw-cannot-be-used
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (m_Disposed)
return;
// I know this looks like total overkill, but per http://www.xtremevbtalk.com/tutors-corner/160433-automating-office-programs-vb-net-com-interop.html
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
if (disposing)
{
// Free managed objects
CloseWorkbook();
if (m_Application != null)
{
m_Application.Quit();
Marshal.FinalReleaseComObject(m_Application);
}
m_Application = null;
}
m_Disposed = true;
}
~ExcelInterfacer()
{
Dispose(false);
}
答案 1 :(得分:1)
我想建议尝试使用EPPLUS?它将帮助您分离需要安装机器的EXCEL Api,以及具有更清晰(更清洁)的API(无编组/ com等...)来处理 - 换句话说,释放你的EXCEL INTEROP 以及它的 COM 复制的API(双关语)。
EPPLUS会很好地处理您的用例,因为无法打开Excel流程,因此在将文件附加到您的电子邮件时,这不再是一个问题因为excel进程不与文件绑定。您可以使用EPPLUS控制流程。
因此,除非您需要在Excel中进行非常具体的 API调用,但正如我看到您只是添加数据我觉得您不会需要非常具体的Excel功能 - 我感觉EPPLUS总是一个更好,更清洁的选择。
检查https://www.nuget.org/packages/EPPlus和http://epplus.codeplex.com/documentation 以下是一些示例用法:
using(var package = new ExcelPackage(new FileInfo(@"c:\temp\tmp.xlsx")))
{
// calculate all formulas in the workbook
package.Workbook.Calculate();
// calculate one worksheet
package.Workbook.Worksheets["my sheet"].Calculate();
// calculate a range
package.Workbook.Worksheets["my sheet"].Cells["A1"].Calculate();
// create a new sheet and write and manipulate cells on it
var ws = package.Workbook.Worksheets.Add("new sheet");
ws.Cells["B1"].Value = "some data";
ws.Cells["C1"].Value = "some more data";
ws.Cells["B1:E1"].Style.Font.Bold = true;
// Save your EXCEL sheet, the using statement will close all references afterwards - since it EPPLUS neatly provides the IDisposable pattern around an excel file (aka ExcelPackage).
package.Save();
}