When launching an .exe using .Run in VBA, a typical call may look like this:
x = wsh.Run(Command:="program.exe ""argument""", WindowStyle:=0, waitonreturn:=False)
Where windowStyle=0
should theoretically cause the program to run invisible to the user. But what if a pop-up window occurs within the .exe that you don't want to the user to see?
The windowStyle input will not suppress the appearance of warning messages or pop up windows declaring things like 'calculation complete' from appearing to the user, this often also pauses the code until the pop up is cleared. Clearing the window (i.e. clicking 'okay') in an automated manner is trivial (see this answer), but preventing it from appearing to the user to begin with is proving difficult to me as a relative beginner. (i.e. when the pop up is triggered by the .exe it is invisible to the user, and then closed automatically by the VBA code)
Currently I detect the existence of a new pop up window using this function (where sCaption is the name of the pop up window):
Private Function GetHandleFromPartialCaption(ByRef lWnd As Long, ByVal sCaption As String) As Boolean
Dim lhWndP As Long
Dim sStr As String
GetHandleFromPartialCaption = False
lhWndP = FindWindow(vbNullString, vbNullString) 'PARENT WINDOW
Do While lhWndP <> 0
sStr = String(GetWindowTextLength(lhWndP) + 1, Chr$(0))
GetWindowText lhWndP, sStr, Len(sStr)
sStr = Left$(sStr, Len(sStr) - 1)
If InStr(1, sStr, sCaption) > 0 Then
GetHandleFromPartialCaption = True
lWnd = lhWndP
Exit Do
End If
lhWndP = GetWindow(lhWndP, GW_HWNDNEXT)
Loop
End Function
Then close it automatically. But it still briefly flashes up on screen to the user. Ideally I'd like this VBA code to run in the background so the user can get on with other tasks whilst it runs, not being distracted by flashing boxes.
Is there a way to force all windows of program.exe, including pop ups, to be invisible whilst it is running?
For further information, see my previous question on how to close the pop up window, here. This thread concerns how to prevent its appearance to a user.
EDIT 1
SendKeys is temperamental, so I am using this looping code to kill the .exe when I detect the pop up window, therefore the .exe does not need to be in focus to close the pop up (closing the pop up kills the .exe in my case anyway):
....
Main Code Body
....
t = Now
waittime = Now + TimeValue("0:01:30") 'limit to run a single row of calculations
Do While t < waittime
If GetHandleFromPartialCaption(lhWndP, "Popup Window Text") = True Then
Set oServ = GetObject("winmgmts:")
Set cProc = oServ.ExecQuery("Select * from Win32_Process")
For Each oProc In cProc
If oProc.Name = "Program.exe" Then
errReturnCode = oProc.Terminate()
Marker2 = 1
Exit Do
End If
Next
Endif
Loop
....
Main Code Body Continues
....
where GetHandleFromPartialCaption()
is the function above, finding the pop up window based on the sCaption argument. My code loops and searches constantly for the pop up whilst the .exe is running the calculation, and kills the .exe as soon as it appears. But it still flashes up to the user.
To run an application completely hidden, launch it in a different desktop with
CreateProcess
.Here's an example executing a simple command line and waiting for the process to exit :
And if you need to find a window in the desktop, use
EnumDesktopWindows
instead ofEnumWindows
:If you need to close a window, simply send
WM_CLOSE
to the main window or to a popup: