Excel进程未关闭
本文关键字:进程 Excel | 更新日期: 2023-09-27 18:27:09
我有一个C#程序,它从不关闭Excel进程。基本上,它可以查找字符串在Excel中某个范围内出现的实例数。我试过各种各样的方法,但都不起作用。有一个Form正在调用这个方法,但这不应该改变流程没有关闭的原因。我看过汉斯·帕桑特的建议,但都没有奏效。
编辑:我试过上面提到的东西,但还是关不上。这是我更新的代码。编辑:尝试了整个Process.Kill(),它确实有效,但对于一些应该有效的东西来说,这似乎有点像黑客。
public class CompareHelper
{
// Define Variables
Excel.Application excelApp = null;
Excel.Workbooks wkbks = null;
Excel.Workbook wkbk = null;
Excel.Worksheet wksht = null;
Dictionary<String, int> map = new Dictionary<String, int>();
// Compare columns
public void GetCounts(string startrow, string endrow, string columnsin, System.Windows.Forms.TextBox results, string excelFile)
{
results.Text = "";
try
{
// Create an instance of Microsoft Excel and make it invisible
excelApp = new Excel.Application();
excelApp.Visible = false;
// open a Workbook and get the active Worksheet
wkbks = excelApp.Workbooks;
wkbk = wkbks.Open(excelFile, Type.Missing, true);
wksht = wkbk.ActiveSheet;
...
}
catch
{
throw;
}
finally
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (wksht != null)
{
//wksht.Delete();
Marshal.FinalReleaseComObject(wksht);
wksht = null;
}
if (wkbks != null)
{
//wkbks.Close();
Marshal.FinalReleaseComObject(wkbks);
wkbks = null;
}
if (wkbk != null)
{
excelApp.DisplayAlerts = false;
wkbk.Close(false, Type.Missing, Type.Missing);
Marshal.FinalReleaseComObject(wkbk);
wkbk = null;
}
if (excelApp != null)
{
excelApp.Quit();
Marshal.FinalReleaseComObject(excelApp);
excelApp = null;
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
/*
Process[] processes = Process.GetProcessesByName("EXCEL");
foreach (Process p in processes)
{
p.Kill();
}
*/
}
}
}
以下是一个有趣的知识库,主题是在.NET应用程序断开连接后,办公应用程序保持打开状态。
从Visual Studio.NET客户端自动化后,Office应用程序不会退出
代码示例都在链接中(vb.net抱歉)。基本上,它向你展示了如何正确设置和拆除办公应用程序,以便在你完成它时关闭。
System.Runtime.InteropServices.Marshal.FinalReleaseComObject
是魔法发生的地方。
编辑:您需要为您创建的每个excel对象调用FinalReleaseComObject。
if (excelWorkSheet1 != null)
{
Marshal.FinalReleaseComObject(excelWorkSheet1);
excelWorkSheet1 = null;
}
if (excelWorkbook != null)
{
Marshal.FinalReleaseComObject(excelWorkbook);
excelWorkbook = null;
}
if (excelApp != null)
{
Marshal.FinalReleaseComObject(excelApp);
excelApp = null;
}
我终于把它关闭了。您需要为Workbooks集合添加一个变量,然后使用FinalReleaseComObject,如其他答案中所述。我想你使用的每一个可能的ExcelCOM对象都必须以这种方式处理。
try
{
// Create an instance of Microsoft Excel and make it invisible
excelApp = new Excel.Application();
excelApp.DisplayAlerts = false;
excelApp.Visible = false;
// open a Workbook and get the active Worksheet
excelWorkbooks = excelApp.Workbooks;
excelWorkbook = excelWorkbooks.Open(excelFile, Type.Missing, true);
excelWorkSheet1 = excelWorkbook.ActiveSheet;
}
catch
{
throw;
}
finally
{
NAR( excelWorkSheet1 );
excelWorkbook.Close(false, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
NAR(excelWorkbook);
NAR(excelWorkbooks);
excelApp.Quit();
NAR(excelApp);
}
}
private void NAR(object o)
{
try
{
System.Runtime.InteropServices.Marshal.FinalReleaseComObject( o );
}
catch { }
finally
{
o = null;
}
}
DotNet只有在释放了所有句柄之后才释放COM对象。我所做的就是把所有的东西都评论出来,然后再加回来一部分。看看它是否发布Excel。如果不遵守以下规则。当它发布时,添加更多的代码,直到它不再发布为止。
1) 创建Excel变量时,将所有值设置为空(这样可以避免未启动的错误)
2) 在未首先发布Marshal.FinalReleaseComObject
的情况下,不要重复使用变量
3) 请勿双点(a.b = z)
。dotNet创建一个临时变量,该变量不会被释放。
c = a.b;
c = z;
Marshal.FinalReleaseComObject(c);
4) 发布所有excel变量。越快越好。
5) 将其设置回NULL。
将文化设置为"en-US"。有一个错误使Excel与某些区域性崩溃。这确保了它不会。
以下是您的代码应该如何结构化的想法:
thisThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
InteropExcel.Application excelApp = null;
InteropExcel.Workbooks wkbks = null;
InteropExcel.Workbook wkbk = null;
try
{
excelApp = new InteropExcel.Application();
wkbks = excelApp.Workbooks;
wkbk = wkbks.Open(fileName);
...
}
catch (Exception ex)
{
}
if (wkbk != null)
{
excelApp.DisplayAlerts = false;
wkbk.Close(false);
Marshal.FinalReleaseComObject(wkbk);
wkbk = null;
}
if (wkbks != null)
{
wkbks.Close();
Marshal.FinalReleaseComObject(wkbks);
wkbks = null;
}
if (excelApp != null)
{
// Close Excel.
excelApp.Quit();
Marshal.FinalReleaseComObject(excelApp);
excelApp = null;
}
// Change culture back from en-us to the original culture.
thisThread.CurrentCulture = originalCulture;
}