【发布时间】:2009-06-24 22:05:45
【问题描述】:
我正在尝试通过 C# 实现 Excel 自动化。我已按照 Microsoft 的所有说明执行此操作,但我仍在努力放弃对 Excel 的最终引用以关闭它并让 GC 收集它。
下面是代码示例。当我注释掉包含类似于以下行的代码块时:
Sheet.Cells[iRowCount, 1] = data["fullname"].ToString();
然后文件保存并退出 Excel。否则,文件将保存,但 Excel 仍作为进程运行。下次运行此代码时,它会创建一个新实例并最终建立起来。
感谢任何帮助。谢谢。
这是我的代码的准系统:
Excel.Application xl = null;
Excel._Workbook wBook = null;
Excel._Worksheet wSheet = null;
Excel.Range range = null;
object m_objOpt = System.Reflection.Missing.Value;
try
{
// open the template
xl = new Excel.Application();
wBook = (Excel._Workbook)xl.Workbooks.Open(excelTemplatePath + _report.ExcelTemplate, false, false, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt);
wSheet = (Excel._Worksheet)wBook.ActiveSheet;
int iRowCount = 2;
// enumerate and drop the values straight into the Excel file
while (data.Read())
{
wSheet.Cells[iRowCount, 1] = data["fullname"].ToString();
wSheet.Cells[iRowCount, 2] = data["brand"].ToString();
wSheet.Cells[iRowCount, 3] = data["agency"].ToString();
wSheet.Cells[iRowCount, 4] = data["advertiser"].ToString();
wSheet.Cells[iRowCount, 5] = data["product"].ToString();
wSheet.Cells[iRowCount, 6] = data["comment"].ToString();
wSheet.Cells[iRowCount, 7] = data["brief"].ToString();
wSheet.Cells[iRowCount, 8] = data["responseDate"].ToString();
wSheet.Cells[iRowCount, 9] = data["share"].ToString();
wSheet.Cells[iRowCount, 10] = data["status"].ToString();
wSheet.Cells[iRowCount, 11] = data["startDate"].ToString();
wSheet.Cells[iRowCount, 12] = data["value"].ToString();
iRowCount++;
}
DirectoryInfo saveTo = Directory.CreateDirectory(excelTemplatePath + _report.FolderGuid.ToString() + "\\");
_report.ReportLocation = saveTo.FullName + _report.ExcelTemplate;
wBook.Close(true, _report.ReportLocation, m_objOpt);
wBook = null;
}
catch (Exception ex)
{
LogException.HandleException(ex);
}
finally
{
NAR(wSheet);
if (wBook != null)
wBook.Close(false, m_objOpt, m_objOpt);
NAR(wBook);
xl.Quit();
NAR(xl);
GC.Collect();
}
private void NAR(object o)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(o);
}
catch { }
finally
{
o = null;
}
}
更新
无论我尝试什么,“干净”方法或“丑陋”方法(请参阅下面的答案),只要点击此行,excel 实例仍然会挂起:
wSheet.Cells[iRowCount, 1] = data["fullname"].ToString();
如果我注释掉该行(以及它下面的其他类似行,显然),Excel 应用程序将正常退出。只要取消注释上述每一行,Excel 就会继续存在。
我想我必须在分配 xl 变量之前检查是否有一个正在运行的实例,然后改为挂钩。我忘了说这是一个 Windows 服务,但这不重要,不是吗?
【问题讨论】:
-
在你完全正确之前,你不会让“丑陋”的方法起作用。没有折衷办法,因为只要有任何 COM 引用未发布,Excel 就会继续存在。请发布您的“丑陋”代码,以便我们发现错误 - 我可以保证会有一个。请注意,在发布的代码中,您在主块中将 wb 设置为 null,因此 防止 它在您的 finally 块中正确释放。但这只是一个问题(我们在下面讨论了 Workbooks 对象和 Range 对象)。
-
我不得不提一下(尽管它与讨论不是特别相关)你的 NAR 方法可能没有按照你的想法做。行“o = null;”在 finally 块中将局部参数变量 o 设置为 null,但这对调用方法中的变量没有影响。所以在 NAR(xl) 之后,变量 xl 不会为空!话虽如此,无论如何都不需要将变量设置为 null - 除非您对此感到迷信。
-
我刚刚注意到您提到它作为 Windows 服务运行。它不应该与手头的问题有任何关系,但让我给你一个提示。我的应用程序(或其中的一部分)运行 Windows 服务,并且在 Windows XP 或 Windows 2003 Server 下运行良好,但我在 Vista 上遇到了问题,并且完全无法让它在 Windows Server 2008 下运行。只是想我要提一下,如果您的开发机器是 XP,而您的目标平台是 Vista/2008...
-
如果您仍然对此感到疑惑(我非常怀疑,希望不会),我遇到了this post by Hans Passant,其中 (a) 解释了为什么
GC.Collect是这样做的正确方法,并且( b) 为什么它可能看起来在调试器中运行时工作。如果这些年前我们有汉斯来帮忙就好了:-) -
很好的发现——你是对的,我很久以前就不再想它了:) 我会读一下那个链接,谢谢。不断学习总是好的。
标签: c# excel automation