2

我正在开发一个用 Lisp 编写的应用程序。我正在使用 Franz OLE 启动该过程。它打开excel很好,但是当我以交互方式关闭excel时,这个过程仍然存在。当我以交互方式关闭 excel 窗口时,我不确定如何终止该进程。有什么建议吗?

谢谢

4

1 回答 1

1

当您通过自动化启动 Excel 时,只要它被引用1 ,它就会一直保持活动状态。以交互方式关闭它并不一定会退出应用程序,在这种情况下,因为您的ole:remote-autotoolfor Excel 尚未发布。

让 Excel 退出的一种方法是去掉 autotool 包装器,例如,如果您有一个存储在变量或对象的插槽中,请将其值设置为nil

(let ((excel-app (ole:ask-for-autotool "Excel.Application"
                                       ole:CLSCTX_LOCAL_SERVER)))
  ;; ...
  ;; Break the reference to all autotool wrappers you no longer need
  (setf excel-app nil))

在 Allegro CL 的OLE 接口IUnknown中,客户端包装器的创建注册了一个终结,该终结在它被垃圾收集时释放底层接口指针。

自动工具是另一个包装器,它包含一个IDispatch客户端包装器(它继承自IUnknown,就像所有 COM 接口一样),以与脚本语言相同的方式简化它的使用,即COM 自动化中的后期绑定。当您停止引用自动工具时,底层IDispatch/IUnknown客户端包装器可能会被垃圾收集,从而被释放。

但是,Excel 可能不会以这种方式立即退出,除非您期望或强制进行垃圾回收2。如果您希望 Excel 在没有交互的情况下立即退出,您应该将QuitExcelDisplayAlerts设置为 false,然后设置ole:release您的 autotool 对象(注意:我没有彻底测试过这个):

(let ((excel-app (ole:ask-for-autotool "Excel.Application"
                                       ole:CLSCTX_LOCAL_SERVER)))
  ;; ...
  ;; Disable prompts asking to save unsaved workbooks
  ;; They will not be saved
  (setf (ole:auto-getf excel-app "DisplayAlerts") nil)
  (ole:auto-method excel-app "Quit")
  ;; Manually release all autotool wrappers you no longer need
  (ole:release excel-app))

自动工具的预定完成在我们手动发布后不会失败。它检查底层接口指针包装器是否已被释放,可能通过检查其类现在是否为ole::released-IUnknown3,因为它被记录在ole:release (ole:IUnknown-Client).

还有一种蛮力方式使用ole:release-process-client-interfaces,但您应该确保您不会访问到目前为止在当前 lisp 进程(线程)中创建的任何 OLE 对象:

(mp:process-run-function
 "Excel worker"
 #'(lambda ()
     (ole:start-ole)
     (unwind-protect
         (let ((excel-app (ole:ask-for-autotool "Excel.Application"
                                                 ole:CLSCTX_LOCAL_SERVER)))
           ;; ...
           ;; Disable prompts asking to save unsaved workbooks
           ;; They will not be saved
           (setf (ole:auto-getf excel-app "DisplayAlerts") nil)
           (ole:auto-method excel-app "Quit")
           ;; Make sure this is the last thing you do, the wrappers
           ;; created in the current process will become invalid
           (ole:release-process-client-interfaces))
       ;; Given this call, the brute force doesn't make much sense anyway
       (ole:stop-ole))))

1.只要持有任何注册工厂的锁或保留对由 excel.exe 创建的任何对象的引用,它就应该继续运行。这对于进程外服务器来说是正常的。

2.如果您的 autotool 实例已使用tenured,则需要对它的生成进行垃圾收集,这通常可以通过全局 GC 来实现,然后最终确定并释放。

3.在 Common Lisp 中,您可以更改对象的类。

于 2012-10-30T17:48:39.123 回答