Don't know exactly hot this works but it does.
This is the entire code of a class I use (inherited from somebody).
Would welcome comments and an explanation of how this works exactly.
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 Sub Sleep Lib "KERNEL32" (ByVal dwMilliseconds As Long)
Dim mnExitCode As Long
Public Property Get ExitCode() As Long
ExitCode = mnExitCode
End Property
Public Function ShellOut(ByVal sShellArg As String, _
Optional nTimeOutMinutes As Long = 20) As Boolean
Dim nTask As Double
Dim nProc As Long
Dim nResult As Long
Dim nTimeStart As Long
Dim nTimeNow As Long
Dim nExitCode As Long
ShellOut = False
nTask = Shell(sShellArg, vbNormalFocus)
If nTask = 0 Then Exit Function
nProc = OpenProcess(&H400 Or &H1, 0, CDbl(nTask))
nTimeStart = (Val(Format(Time, "hh"

) * 60) + Val(Format(Time, "mm"

)
DoEvents
Do
nResult = GetExitCodeProcess(nProc, nExitCode)
If nExitCode <> &H103 Or nResult = 0 Then
Exit Do
End If
nTimeNow = (Val(Format(Time, "hh"

) * 60) + Val(Format(Time, "mm"

)
If nTimeNow - nTimeStart > nTimeOutMinutes Then
Debug.Print "nTimeNow - nTimeStart > nTimeOutMinutes", nTimeNow - nTimeStart > nTimeOutMinutes
Exit Do
End If
Sleep 250
DoEvents
Sleep 250
DoEvents
Loop
mnExitCode = nExitCode
ShellOut = nExitCode = 0
End Function