等待shell命令完成

45

我在Excel VBA中运行一个简单的shell命令,它在指定的目录下运行一个批处理文件,就像下面这样:

Dim strBatchName As String
strBatchName = "C:\folder\runbat.bat"
Shell strBatchName

有时批处理文件在某些计算机上运行时间可能会更长,而且还有依赖于批处理文件完成运行的VBA代码。我知道你可以设置一个等待计时器,如下所示:

Application.Wait Now + TimeSerial(0, 0, 5)

但在一些计算机速度较慢的情况下,这可能不起作用。有没有一种方法可以系统地告诉Excel在shell运行完成之后再继续进行其余的VBA代码?


能否让BATCH在完成时创建一个文件,然后让VBA等待该文件的创建?或者让BATCH在完成时删除一个标志文件,然后让VBA等待标志文件被删除? - Magoo
请参考以下链接(WaitForSingleObject):https://dev59.com/PHM_5IYBdhLWcg3wTRLL#1439241 - Aprillion
7个回答

94

2
在.NET中,但不是在VBA中... - K_B
1
好的,已修改为使用 WScript.Shell。 - Nate Hekman
7
在Nate的回答中,这一行代码:wsh.Run("C:\folder\runbat.bat", windowStyle, waitOnReturn) 会出现编译错误:"Expected: "=". 当去掉括号后,它就能正常工作:wsh.Run "C:\folder\runbat.bat", windowStyle, waitOnReturn。我不确定它是否与此事有关,但我正在运行Win8和Excel 2013。 - user2946432
2
由于出现“对象'IWshShell3'的方法'Run'失败”的错误号码-2147024894,该程序对我不起作用。 - Qbik
2
可能是因为你的路径中有空格,所以它对你不起作用。@Qbik @Santosh 使用wsh.Run Chr(34) & YourPathWithSpaces & Chr(34) - J.Goddard
显示剩余7条评论

11

添加以下子程序:

Sub SyncShell(ByVal Cmd As String, ByVal WindowStyle As VbAppWinStyle)
VBA.CreateObject("WScript.Shell").Run Cmd, WindowStyle, True
End Sub

如果您添加对 C:\Windows\system32\wshom.ocx 的引用,则还可以使用以下内容:

Sub SyncShell(ByVal Cmd As String, ByVal WindowStyle As VbAppWinStyle)
Static wsh As New WshShell
wsh.Run Cmd, WindowStyle, True
End Sub

这个版本应该更加高效。


6

将批处理文件保存在“C:\WINDOWS\system32”上,并使用以下代码,它可以工作

   Dim wsh As Object
   Set wsh = VBA.CreateObject("WScript.Shell")
   Dim waitOnReturn As Boolean: waitOnReturn = True
   Dim windowStyle As Integer: windowStyle = 1
   Dim errorCode As Integer

   errorCode = wsh.Run("runbat.bat", windowStyle, waitOnReturn)

If errorCode = 0 Then
    'Insert your code here
Else
    MsgBox "Program exited with error code " & errorCode & "."
End If   

2

以下是我用来让VB在继续之前等待进程完成的方法。

这不是我写的,也不会署名。在其他开放的论坛中提供了这个方法,对我来说非常有效:

RunShell子程序需要以下声明:

Option Explicit

Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long

Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long

Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Private Const PROCESS_QUERY_INFORMATION = &H400

Private Const STATUS_PENDING = &H103&

'then in your subroutine where you need to shell:

RunShell (path and filename or command, as quoted text)

1
这段代码在VBA中无法工作,因为没有定义RunShell。 - Niall

2
您提出的在“运行”命令中更改括号的建议对我来说在VBA中很好地起作用了。
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
Dim errorCode As Integer
wsh.Run "C:\folder\runbat.bat", windowStyle, waitOnReturn

0

-5

Dim wsh as new wshshell

chdir "批处理文件目录"

wsh.run "批处理文件的完整路径",vbnormalfocus, true

完成了,孩子


不理解你的回答.... - Paul Lo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接