我在C#中编写了一个Excel包装器,以便允许在批处理过程中运行Excel工作簿(在JobScheduler下)。我的问题是......
如果代码运行时间过长或需要通过作业调度程序终止,则包装程序需要处理此终止事件。为此,我添加了
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
进入代码。在ConsoleCtrlCheck方法中,我调用一个公共出口例程(在正常或终止情况下使用)。根据MS建议,此路由执行以下操作。
关闭并发布工作簿
关闭并发布Excel
垃圾收集
然后退出并调用所调用的Excel方法的返回码(入口点)。 这很好用。
但是,如果VBA代码仍在运行,则Interop对象将不响应工作簿关闭或应用程序退出调用。这可能是因为一切都很慢或者因为发出了模态对话框。 为了解决这个问题,我在这个常见程序的开头添加了以下内容......
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流程的必要方式?
答案 0 :(得分:1)
您正在做的几乎是完全确保Excel退出的标准方法。鉴于涉及COM Interop,并且excel有一个离开孤儿实例的讨厌习惯,你遵循的方法几乎是万无一失的。
但是,如果您可以访问vba代码并且可以控制它,那么您可以执行一项基本操作来确保VBA代码允许其他代码运行。
DoEvents
根据我的经验,在运行大量计算之前和之后放置一行代码通常允许excel正确处理例程事件。虽然通常建议用于UI相关操作,但它也可以使工作表/应用程序事件正常工作。
希望这有帮助。
答案 1 :(得分:0)
是否有可能用EPPLUS等第三方库替换VBA逻辑?那会更快......