1

I understand how to use ShellExecute in VBA (for my Outlook macros) but I'm looking to be able to use ShellExecuteEx to wait for the executed program in my script. Does anyone have an example of how to do this? Currently I have this code:

Const SW_SHOW = 1
Const SW_SHOWMAXIMIZED = 3

Public Declare Function ShellExecute _
    Lib "shell32.dll" _
        Alias "ShellExecuteA" ( _
            ByVal Hwnd As Long, _
            ByVal lpOperation As String, _
            ByVal lpFile As String, _
            ByVal lpParameters As String, _
            ByVal lpDirectory As String, _
            ByVal nShowCmd As Long) _
As Long

'// Properties API
Private Type SHELLEXECUTEINFO
    cbSize       As Long
    fMask        As Long
    Hwnd         As Long
    lpVerb       As String
    lpFile       As String
    lpParameters As String
    lpDirectory  As String
    nShow        As Long
    hInstApp     As Long
    lpIDList     As Long
    lpClass      As String
    hkeyClass    As Long
    dwHotKey     As Long
    hIcon        As Long
    hProcess     As Long
End Type

Private Declare Function ShellExecuteEx _
    Lib "shell32.dll" ( _
        Prop As SHELLEXECUTEINFO) _
As Long

Public Function fnGetPropDlg(strFilepath As String) As Long
Dim Prop As SHELLEXECUTEINFO

With Prop
    .cbSize = Len(Prop)
    .fMask = &HC
    .Hwnd = 0&
    .lpVerb = "properties"
    .lpFile = strFilepath
End With

fnGetPropDlg = ShellExecuteEx(Prop)

End Function

and then my code calling the actual program (with ShellExecute):

RetVal = ShellExecute(0, "open", "C:\Documents and Settings\my\Desktop\zipTools.hta", "", "", SW_SHOWMAXIMIZED)

can anyone offer any help with switching this around so I can use ShellExecuteEx to wait for the closure of my HTA before my script execution continues?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
thepip3r
  • 2,855
  • 6
  • 32
  • 38
  • so i've got shellexecuteex running with a string (absolute path) as an argument but how do i make my script wait until that program is finished before moving on? Public Function fnRunFileWait(strFilepath As String) As Long Dim Prop As SHELLEXECUTEINFO With Prop .cbSize = Len(Prop) .fMask = &HC .Hwnd = 0& .lpVerb = "open" .lpFile = strFilepath End With fnRunFileWait = ShellExecuteEx(Prop) End Function – thepip3r Sep 03 '09 at 16:28

4 Answers4

3

Use CreateProcess() Windows API call instead.

For running a process and waiting until it finishes, use solution recommended by Microsoft which calls CreateProcessA(). Do not use ShellExecuteEx(). (You can also consider replacing your existing code.)

Reasons:

  1. It is recommended directly by manufacturer. There can be several reasons behind it including recent one:

  2. It is stable. ShellExecuteEx() is reported to throw exception after recent (2015) Windows updates when it is called from VBA.

In the answer to the above linked question, the code from Microsoft article is ready-to-use as separate VBA module.

Community
  • 1
  • 1
miroxlav
  • 11,796
  • 5
  • 58
  • 99
3

Old question but here's a much simpler answer:

VBA Shell & Wait: the easy way!

Sub ShellAndWait(pathFile As String)
    With CreateObject("WScript.Shell")
        .Run pathFile, 1, True
    End With
End Sub

(You could even squish it to one line, but this is easier to read.)


Example Usage:

Sub demo_Wait()
    ShellAndWait ("notepad.exe")
    Beep 'this won't run until Notepad window is closed
    MsgBox "Done!"
End Sub

Adapted from (and more options at) Chip Pearson's site.

ashleedawg
  • 20,365
  • 9
  • 72
  • 105
0

If I am not mistaken, you need to set the

SEE_MASK_NOASYNC
bit in the fMask parameter.

Const SEE_MASK_NOASYNC As Long = &h0&
With Prop    
    .fMask = &HC Or SEE_MASK_NOASYNC
End With

Edit

Hmmm, I'm having trouble getting it to work too. Have you considered just GetFileInformationByHandle?

Oorang
  • 6,630
  • 1
  • 35
  • 52
  • i added the constant to the parameter you specified and it still continues code execution in my script. now out of curiosity (and possibly my ignorance), is this supposed to wait until the program is simply executed or does it wait for the executed program to close? – thepip3r Sep 03 '09 at 20:56
  • It was my understanding it would wait for the program to close. – Oorang Sep 04 '09 at 00:07
-1

Indeed the suggestion above

Sub ShellAndWait(pathFile As String) With CreateObject("WScript.Shell") .Run pathFile, 1, True End With End Sub

is simple and works!

The value 1 specifies to show the window, 0 is the default. The value True specifies to wait for completion; False returns immediately.

The pathFile follows the normal rules of construction you would use in a batch file - put the program path and name in quotes if necessary and can be followed by parameters.

LesD
  • 35
  • 6