如何从 Excel / VBA 调用长时间运行的外部程序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/135158/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 09:56:46  来源:igfitidea点击:

How can I call a long-running external program from Excel / VBA?

windowsexcelexcel-vbaspreadsheetvba

提问by David Nehme

What is the best way to run an external program from excel. It might run for several minutes. What's the best-practice about how to to this. Ideally,

从 excel 运行外部程序的最佳方法是什么。它可能会运行几分钟。关于如何做到这一点的最佳实践是什么。理想情况下,

  1. A model dialog box that let's the user know that the process is executing.
  2. If the executable fails, the user should receive a notification.
  3. A timeout should be enforced.
  4. A cancel button should be on the dialog box.
  1. 一个模型对话框,让用户知道进程正在执行。
  2. 如果可执行文件失败,用户应该收到通知。
  3. 应该强制执行超时。
  4. 对话框上应该有一个取消按钮。

But any best-practices are welcome. I'm interested in solutions with calling either a .dll or an .exe. Preferably something that works with Excel '03 or earlier, but I'd love to hear a reason to move to a later version as well.

但欢迎任何最佳实践。我对调用 .dll 或 .exe 的解决方案感兴趣。最好是适用于 Excel '03 或更早版本的东西,但我也很想听听移动到更高版本的理由。

回答by Bill

You should check out these two Microsoft KB articles

您应该查看这两篇 Microsoft KB 文章

How to launch a Win32 Application from Visual Basicand

如何从 Visual Basic

How To Use a 32-Bit Application to Determine When a Shelled Process Ends

如何使用 32 位应用程序确定脱壳进程何时结束

They both quickly give you the framework to launch a process and then check on its completion. Each of the KB articles have some additional references that may be relevant.

它们都可以快速为您提供启动流程的框架,然后检查其完成情况。每篇知识库文章都有一些可能相关的附加参考资料。

The latter knowledgebase article assumes that you want to wait for an infinite amount of time for your shell process to end.

后一篇知识库文章假设您希望等待无限长的时间让您的 shell 进程结束。

You can modify the ret& = WaitForSingleObject(proc.hProcess, INFINITE) function call to return after some finite amount of time in milliseconds--replace INFINITE with a positive value representing milliseconds and wrap the whole thing in a Do While loop. The return value tells you if the process completed or the timer ran out. The return value will be zero if the process ended.

您可以修改 ret& = WaitForSingleObject(proc.hProcess, INFINITE) 函数调用以在以毫秒为单位的有限时间后返回 - 用代表毫秒的正值替换 INFINITE 并将整个事物包装在 Do While 循环中。返回值告诉您进程是否已完成或计时器是否已用完。如果进程结束,返回值将为零。

If the return value is non-zero then the process is still running, but control is given back to your application. During this time while you have positive control of your application, you can determine whether to update some sort of UI status, check on cancellation, etc. Or you can loop around again and wait some more.

如果返回值不为零,则进程仍在运行,但控制权已交还给您的应用程序。在这段时间内,当您对应用程序有积极的控制时,您可以决定是否更新某种 UI 状态、检查取消等。或者您可以再次循环并等待更多时间。

There are even additional options if the program you are shelling to is something that you wrote. You could hook into one of its windows and have the program post messages that you can attach to and use as status feedback. This is probably best left for a separate item if you need to consider it.

如果您要脱壳的程序是您编写的,则甚至还有其他选项。您可以连接到它的一个窗口,让程序发布消息,您可以将其附加并用作状态反馈。如果您需要考虑,这可能最好留给单独的项目。

You can use the process structure to get a return value from the called process. Your process does need to return a value for this to be useful.

您可以使用进程结构从被调用进程中获取返回值。您的流程确实需要返回一个值才能有用。

My general approach to this kind of need is to:

我对这种需求的一般方法是:

  1. give the user a non-modal status dialog at the start of the process with a cancel button, which when clicked will set a flag to be checked later. Providing the user with any status is most likely impossible, so giving them an elapsed time or one of those animated GIFs might be helpful in managing expectations.
  2. Start the process
  3. Wait for the process to complete, allowing cancellation check every 500ms
  4. If the process is complete close the dialog and continue along.
  5. If the process is not complete, see if the user hit cancel and if so send a close message to the process' window. This may not work and terminating the process might be required--careful if you do this. Your best bet may be to abandon the process if it won't close properly. You can also check for a timeout at this point and try to take the same path as if the user hit cancel.
  1. 在流程开始时为用户提供一个带有取消按钮的非模态状态对话框,单击该按钮时将设置一个标志以供稍后检查。为用户提供任何状态很可能是不可能的,因此给他们一个经过的时间或其中一个动画 GIF 可能有助于管理期望。
  2. 启动流程
  3. 等待进程完成,允许每 500 毫秒取消检查一次
  4. 如果该过程完成,请关闭对话框并继续。
  5. 如果进程未完成,查看用户是否点击取消,如果是,则向进程窗口发送关闭消息。这可能不起作用,并且可能需要终止该过程——如果您这样做,请小心。如果该过程无法正常关闭,您最好的选择可能是放弃该过程。您还可以在此时检查超时并尝试采用与用户点击取消相同的路径。

Hope this helps, Bill.

希望这会有所帮助,比尔。