我在 C# 中为 Excel 编写了一个包装器,以便允许在批处理过程中运行 Excel 工作簿(在 JobScheduler 下)。我的问题是这个...
如果代码运行时间过长或需要通过作业调度程序终止,则包装器需要处理此终止事件。为此,我添加了
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
进入代码。在 ConsoleCtrlCheck 方法中,我调用了一个通用退出例程(在正常或终止情况下使用)。此路由根据 MS 建议执行以下操作。
关闭并释放 Workbooks
关闭并释放 Excel
垃圾收集
然后以调用的 Excel 方法的返回码(入口点)退出。这很好用。
但是,如果 VBA 代码仍在运行,则 Interop 对象将不会响应工作簿关闭或应用程序退出调用。这可能是因为一切进展缓慢或已发出模式对话框。为了解决这个问题,我在这个常见例程的开头添加了以下内容......
- 创建新线程以运行 KillExcel 方法
- KillExcel 方法休眠指定时间(因此正常退出代码有机会工作)然后终止进程
- 如果正常代码有效,它会在线程上调用 Abort
private static void Cleanup()
{
// Give this X seconds then terminate
mKillThread = new Thread(KillExcel);
mKillThread.IsBackground = false;
mKillThread.Start();
...
// close the workbooks and excel application
// Marshal.FinalReleaseComObject etc
GC.Collect();
GC.WaitForPendingFinalizers();
// Not sure if necessary but makes sure Process gone
try
{
Process p = Process.GetProcessById(mExcelPid);
p.WaitForExit();
}
catch(ArgumentException)
{}
mKillThread.Abort();
}
private static void KillExcel()
{
Thread.Sleep(Settings.Default.KillWaitMilliSeconds);
if (mLog.IsInfoEnabled)
mLog.Info(string.Format("Waited {0} seconds, killing Excel process [{1}]",Settings.Default.KillWaitMilliSeconds/1000, mExcelPid));
try
{
Process p = Process.GetProcessById(mExcelPid);
if (!p.HasExited)
p.Kill();
}
catch(ArgumentException)
{
}
}
我的问题是,有没有更好的方法来解决这个问题,或者为了确保在工作终止事件中删除 excel 进程而必须这样做?