运行代码时,退出Interop控制的Excel

我已经在C#中为Excel编写了一个包装器,以允许在批处理过程中(在JobScheduler下)运行Excel工作簿。 我的问题是这个…

如果代码运行时间过长或需要通过作业调度程序终止,则包装程序需要处理此终止事件。 为此我补充说

SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true); 

进入代码。 在ConsoleCtrlCheck方法中,我调用一个公共的出口例程(在正常或终止的情况下使用)。 根据MSbuild议,此路由select会执行以下操作。

closures并发布工作簿
closures并发布Excel
垃圾收集

然后用被调用的Excel方法(入口点)的返回码退出。 这很好。

但是,如果VBA代码仍在运行,Interop对象将不会响应工作簿closures或应用程序退出调用。 这可能是因为一切正在缓慢或由于模态对话已经发出。 为了应付这个问题,我在这个常见的例行程序中join了以下内容:

  • 创build新的线程来运行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进程的方式?

你所做的几乎是完全确保Excel退出的标准方式。 考虑到有COM Interop的参与,并且Excel有一个离开孤儿实例的恶劣习惯,你遵循的方法是非常简单的。

但是,如果您有权访问vba代码并可以对其进行控制,则可以执行一项基本的操作来确保VBA代码确实允许其他代码运行。

 DoEvents 

根据我的经验,在运行大量计算之前和之后放置这一行代码通常可以让excel正确处理例行事件。 虽然这通常build议用于与UI相关的操作,但它也适用于让Worksheet / Application事件正常工作。

希望这可以帮助。

有没有可能用EPPLUS等第三方库replaceVBA逻辑? 这将是更大的幅度….