问题描述
我在这里阅读了许多关于管理COM引用的其他线程,同时使用.Net-Excel互操作来确保Excel进程在退出时正确退出,到目前为止,技术一直工作得很好,但是我最近在现有的工作簿文件中添加新的工作表时遇到了一个问题。
I've read many of the other threads here about managing COM references while using the .Net-Excel interop to make sure the Excel process exits correctly upon exit, and so far the techniques have been working very well, but I recently came across a problem when adding new worksheets to an existing workbook file.
下面的代码留下了一个僵尸Excel进程。
The code below leaves a zombie Excel process.
如果我将工作表添加到新创建的工作簿文件中,则表示正常。如果我运行的代码不包括 .Add()
行,它退出正常。 (我正在读的现有文件是由注释掉的代码创建的空文件)
If I add a worksheet to a newly created workbook file, it exits fine. If I run the code excluding the .Add()
line, it exits fine. (The existing file I'm reading from is an empty file created by the commented out code)
任何想法?
//using Excel = Microsoft.Office.Interop.Excel;
//using System.Runtime.InteropServices;
public static void AddTest()
{
string filename = @"C:\addtest.xls";
object m = Type.Missing;
Excel.Application excelapp = new Excel.Application();
if (excelapp == null) throw new Exception("Can't start Excel");
Excel.Workbooks wbs = excelapp.Workbooks;
//if I create a new file and then add a worksheet,
//it will exit normally (i.e. if you uncomment the next two lines
//and comment out the .Open() line below):
//Excel.Workbook wb = wbs.Add(Excel.XlWBATemplate.xlWBATWorksheet);
//wb.SaveAs(filename, m, m, m, m, m,
// Excel.XlSaveAsAccessMode.xlExclusive,
// m, m, m, m, m);
//but if I open an existing file and add a worksheet,
//it won't exit (leaves zombie excel processes)
Excel.Workbook wb = wbs.Open(filename,
m, m, m, m, m, m,
Excel.XlPlatform.xlWindows,
m, m, m, m, m, m, m);
Excel.Sheets sheets = wb.Worksheets;
//This is the offending line:
Excel.Worksheet wsnew = sheets.Add(m, m, m, m) as Excel.Worksheet;
//N.B. it doesn't help if I try specifying the parameters in Add() above
wb.Save();
wb.Close(m, m, m);
//overkill to do GC so many times, but shows that doesn't fix it
GC();
//cleanup COM references
//changing these all to FinalReleaseComObject doesn't help either
while (Marshal.ReleaseComObject(wsnew) > 0) { }
wsnew = null;
while (Marshal.ReleaseComObject(sheets) > 0) { }
sheets = null;
while (Marshal.ReleaseComObject(wb) > 0) { }
wb = null;
while (Marshal.ReleaseComObject(wbs) > 0) { }
wbs = null;
GC();
excelapp.Quit();
while (Marshal.ReleaseComObject(excelapp) > 0) { }
excelapp = null;
GC();
}
public static void GC()
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
}
推荐答案
我没有代码手,但我也遇到了类似的问题。
如果我记得正确,我最终检索excel实例的进程标识,并杀死它(在适当的等待期之后,另一个方法失败)。
I don't have the code to hand, but I did run into a similar problem.If I recall correctly, I ended up retrieving the process id of the excel instance, and killing it (after a suitable wait period, and when the other method failed).
我认为我使用了:
GetWindowThreadProcessId
(通过P / Invoke)在excel对象hwnd属性获取进程ID,然后使用 Process.GetProcessById
获取进程对象。
一旦这样做,我会在进程中调用 Kill
。
GetWindowThreadProcessId
(via P/Invoke) on the excel object hwnd property to get the process id, and then used Process.GetProcessById
to get a process object.Once I'd done that, I'd call Kill
on the process.
编辑:我不得不承认,这不是理想的解决方案,但如果找不到没有被释放的流氓界面,那么这将会修复它在真正的蛋壳/大锤时尚。 ;)
I have to admit, this isn't the ideal solution, but if you can't find the rogue interface that isn't being released, then this will fix it in true eggshell/sledgehammer fashion. ;)
EDIT2:您不必在流程对象上立即致电终止
...您可以首先尝试调用关闭
,然后再使用 Kill
。
You don't have to call Kill
on the process object immediately... You could first try calling Close
before resorting to Kill
.
这篇关于C#interop:在现有文件中添加新工作表后,excel进程不退出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!