防止Excel退出

我缺less一个Excel.Application.Quit或一个Excel.Application.BeforeQuit事件。 有没有人知道模拟这些事件的解决方法?

我通过COM Interop从C#WinForms应用程序访问Excel。 给定一个Excel.Application对象,我怎么能:

  1. 最好防止Excel退出?
  2. 如果这是不可能的,我怎么能至less注意到 Excel退出?

请注意:因为我有一个Excel的应用程序的COM引用,当用户退出 Excel时, Excel进程不会退出 。 虽然这听起来是矛盾的,但事实就是如此。 通过“退出”,我的意思是用户点击窗口右上angular的“退出”或“十字button”。 窗口closures,文件被卸载,加载项被卸载,以及Excel除了我不知道的东西之外的任何东西。 但是我仍然可以使用Application对象来“恢复”进程并使Excel重新可见,尽pipe加载项然后丢失了,而且我还不确定尚未定义的状态是什么。

为了摆脱这个问题,我希望在一开始就取消退出(如果存在的话,可以考虑BeforeQuit Cancel = true ),或者至less在Excel退出时通知,这样我就可以释放COM对象使stream程真正退出,下一次我再次需要Excel时,我会知道我需要先启动它。

不幸的是,这是一个恶性循环: 只要Excel运行,我需要COM对象 。 所以我不能 Excel退出处理它们。 另一方面,只要COM对象存在,即使Excel假装退出,进程也不会退出,所以我不能等待进程退出事件或类似事件。

我有一种令人不快的感觉,就是我要把头撞到一堵砖墙上。

请注意,我没有试过这个。

BeforeClose创build一个包含代码的工作簿。
例如

 Option Explicit Private Sub Workbook_BeforeClose(Cancel As Boolean) Cancel = True End Sub 

与其他工作簿一起打开此工作簿,您不必将其隐藏(如果整个应用程序不可见)。

因此,如果您尝试退出Excel实例,它将强制closures此隐藏的工作簿,这将引发其BeforeClose事件,您可以编写代码以阻止其closures。

请注意,上面的代码是在VB6(VBA),它将需要转换成C#。
发表评论,如果你发现任何困难转换。

如果你想隐藏一个工作簿,你可以这样做

 Workbooks("my workbook").Windows(1).Visible = False 

注意:工作簿具有Windows集合。 上面的代码试图隐藏第一个窗口。
我不知道,一个工作簿可以有多个窗口吗? 如果是的话,怎么样?

有一个知识库文章, 如何自动化Excel,然后知道用户closures它 ,在C + +中。 我没有把这个移植到C#,但它可能不是很多的工作。

这是一个黑客,当然,但不能使用Windows SetWindowsHookEx API与WH_SHELL或WH_CBT至less得到Excel的主窗口被通知被销毁?

注意:这当然有安全隐患,即需要一些pipe理权限来执行跨进程的魔法。

你在这里试图解决的问题不会通过监视程序退出来解决。 在你说我没有回答你的问题之前,你在问题中说明,即使在用户退出excel之后,你也可以恢复excel。 因此,excel.exe进程仍在运行,因为你有一个.net对象,其中有一个对excel.application的com互操作引用。

所以你有三个select:

  1. 避免用户退出Excel。 正如你所说的保持Excel不退出,但是我不知道一种方法,你可以防止用户导致Excel退出,因此正如你已经正确地指出卸载你的和任何其他插件,等等。不要忘记,微软专门devise用户以这种方式交互,他们希望用户有能力closures他们的应用程序。 你的插件需要能够处理这个,如果不能,我会说你的插件不是Excel的问题。 我可能错了,因为我对应用程序的要求不够了解。

  2. 清理所有非托pipe资源在用户退出之前。 你需要做的是在用户手动退出Excel之前,清除对alll Excel和Office非托pipe资源的引用,这样当他们退出应用程序代码时,不会留下任何现在指向excel实例的剩余资源有加载等加载。 步骤(a)应该一直执行,一旦你不再需要某个特定的资源,或者甚至在重用其他东西时(例如Excel.Rangetypes),步骤(b)应该被使用的次数更less,但是如果一个赢的应用程序,而不是一个插件,可能更频繁,这一切都取决于你的应用程序和oppurtunity窗口,你有(时间)之前,用户可能会完成任务closures。 显然,使用外挂程序,您可以将其放入关机事件中,或者在代码中进行任意处理。

    一个。 正如Otaku指出的那样,在每个使用后的非托pipe资源上使用Marshal.FinalReleaseCOMObject!= null。

      if (ComObject != null) { Marshal.FinalReleaseComObject(ComObject); ComObject = null; } 

    湾 为COM资源使用GC清理模式。

      GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers(); 
  3. 重新加载插件如果由于任务的复杂性,时间限制(尽pipe我推荐它),您不想对所有非托pipe资源进行完全跟踪和卸载感兴趣,那么您可以查看重新加载大概已经知道的所有必需插件你的环境。 这只有在你控制环境时才有效。 有手动加载Excel和COM加载项的技术。 至于其他的东西,我不知道这一点,但也许是可能的,如果你在启动/ XLSTART目录中使用XLL或XLT,但反正会加载。

你为什么不执行一个System.Diagnostics.Process.Start(@"SomeWorkbook.xlsx"); 确保Excel已启动。 如果它已经开始,那么这将不会创build一个新的过程。

为什么不直接使用Application.ApplicationExit事件来了解它何时closures?