且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在 VB6 中执行更多代码之前等待 shell 进程完成

更新时间:2021-11-23 00:39:50

做到这一点所需的秘诀是 WaitForSingleObject 函数,它会阻止应用程序进程的执行,直到指定进程完成(或超时).它是 Windows API 的一部分,可在向代码中添加适当的声明后轻松从 VB 6 应用程序调用.

The secret sauce needed to do this is the WaitForSingleObject function, which blocks execution of your application's process until the specified process completes (or times out). It's part of the Windows API, easily called from a VB 6 application after adding the appropriate declaration to your code.

该声明看起来像这样:

Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle _
                            As Long, ByVal dwMilliseconds As Long) As Long

它需要两个参数:要等待的进程的句柄,以及指示要等待的最长时间的超时间隔(以毫秒为单位).如果未指定超时间隔(值为零),则该函数不会等待并立即返回.如果您指定无限超时间隔,则该函数在进程发出已完成信号时返回.

It takes two parameters: a handle to the process that you want to wait on, and the time-out interval (in milliseconds) that indicates the maximum amount of time that you want to wait. If you do not specify a time-out interval (a value of zero), the function does not wait and returns immediately. If you specify an infinite time-out interval, the function returns only when the process signals that it has completed.

有了这些知识,剩下的唯一任务就是弄清楚如何处理您启动的流程.事实证明这非常简单,并且可以通过多种不同的方式完成:

Armed with that knowledge, the only task that remains is figuring out how to get a handle to the process that you started. That turns out to be pretty simple, and can be accomplished a number of different ways:

  1. 一种可能性(以及我的做法)是使用 ShellExecuteEx 函数,同样来自 Windows API,作为内置于 VB 6 中的 Shell 函数的替代品.这个版本是更加通用和强大,但使用适当的声明也很容易调用.

  1. One possibility (and the way I'd do it) is by using the ShellExecuteEx function, also from the Windows API, as a drop-in replacement for the Shell function that is built into VB 6. This version is far more versatile and powerful, yet just as easily called using the appropriate declaration.

它返回一个它创建的进程的句柄.您所要做的就是将该句柄作为 hHandle 参数传递给 WaitForSingleObject 函数,然后您就可以开展业务了.您的应用程序的执行将被阻止(挂起),直到您调用的进程终止.

It returns a handle to the process that it creates. All you have to do is pass that handle to the WaitForSingleObject function as the hHandle parameter, and you're in business. Execution of your application will be blocked (suspended) until the process that you've called terminates.

另一种可能性是使用 CreateProcess 函数(再次来自 Windows API).此函数在与调用进程(即您的 VB 6 应用程序)相同的安全上下文中创建一个新进程及其主线程.

Another possibility is to use the CreateProcess function (once again, from the Windows API). This function creates a new process and its primary thread in the same security context as the calling process (i.e., your VB 6 application).

Microsoft 发布了一篇知识库文章,详细介绍了这种方法,甚至提供了完整的示例实现.您可以在此处找到该文章:如何使用 32 位应用程序确定脱壳进程何时结束.

Microsoft has published a knowledge base article detailing this approach that even provides a complete sample implementation. You can find that article here: How To Use a 32-Bit Application to Determine When a Shelled Process Ends.

最后,也许最简单的方法是利用内置 Shell 函数的返回值是应用程序任务 ID 这一事实.这是一个唯一编号,用于标识您启动的程序,它可以传递给 OpenProcess 函数 获取可以传递给 WaitForSingleObject 函数的进程句柄.

Finally, perhaps the simplest approach yet is to take advantage of the fact that the built-in Shell function's return value is an application task ID. This is a unique number that identifies the program you started, and it can be passed to the OpenProcess function to obtain a process handle that can be passed to the WaitForSingleObject function.

然而,这种方法的简单性确实是有代价的.一个非常显着的缺点是它会导致您的 VB 6 应用程序完全没有响应.因为它不会处理 Windows 消息,所以它不会响应用户交互,甚至不会重绘屏幕.

However, the simplicity of this approach does come at a cost. A very significant disadvantage is that it will cause your VB 6 application to become completely unresponsive. Because it will not be processing Windows messages, it will not respond to user interaction or even redraw the screen.

VBnet 的好人在以下文章中提供了完整的示例代码:WaitForSingleObject:确定脱壳应用何时结束.
我希望能够在这里复制代码以帮助避免链接腐烂(VB 6 已经在几年内上升了;不能保证这些资源会永远存在),但是分发许可证中的代码本身似乎明确禁止这样做.

The good folks over at VBnet have made complete sample code available in the following article: WaitForSingleObject: Determine when a Shelled App has Ended.
I'd love to be able to reproduce the code here to help stave off link rot (VB 6 is getting up there in years now; there's no guarantee that these resources will be around forever), but the distribution license in the code itself appears to explicitly forbid that.