Hi Gary --
(Crossed to the API group, to solicit feedback on VB's internal operation --
see bottom of post for the question this raises in my mind.)
i've already got the shell&wait functionality. but in this case i don't want
to wait until the app closes. i want to wait until it fully opens so that i
can send keystrokes to it. maybe the answer is to use a win32 api like
sendmessage instead of vba's sendkeys.
Usually, VB will actually be blocked until the application is responding. You can
test this with any moderately slow-to-start app:
Private Const ExeFile As String = "C:\Program
Files\Corel\Graphics10\Programs\coreldrw.exe"
Private Sub Command2_Click()
Shell ExeFile, vbNormalFocus
AppActivate Me.Caption
MsgBox "Are we there yet?"
End Sub
I would suppose there may be times when that doesn't happen quite as planned. To be
sure, you can use WaitForInputIdle, which is just a bit more complicated but not too
bad. Here's a simple case, using a hard-coded executable path (indented to highlight
wordwrap!):
Option Explicit
Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA"
(ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal
lpProcessAttributes As Any, ByVal lpThreadAttributes As Any, ByVal bInheritHandles As
Long, ByVal dwCreationFlags As Long, ByVal lpEnvironment As Any, ByVal
lpCurrentDriectory As Any, lpStartupInfo As STARTUPINFO, lpProcessInformation As
PROCESS_INFORMATION) As Long
Private Declare Function WaitForInputIdle Lib "user32" (ByVal hProcess As Long,
ByVal dwMilliseconds As Long) As Long
' Constants used with CreateProcess
Private Const STARTF_USESHOWWINDOW As Long = &H1
Private Const STARTF_FORCEONFEEDBACK As Long = &H40
' Structures used with CreateProcess
Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long 'LPBYTE
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type
Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessID As Long
dwThreadID As Long
End Type
Private Const ExeFile As String = "C:\Program
Files\Corel\Graphics10\Programs\coreldrw.exe"
Private Sub Command1_Click()
Dim hProcess As Long
Dim nRet As Long
Const Timeout As Long = 10000 'Ten seconds
Const SYNCHRONIZE As Long = &H100000
Const WAIT_FAILED = -1& 'Error on call
Const WAIT_TIMEOUT = &H102& 'Timeout period elapsed
hProcess = hProcShell(ExeFile, vbNormalFocus).hProcess
If hProcess Then
nRet = WaitForInputIdle(hProcess, Timeout)
Select Case nRet
Case 0
MsgBox "Application is now waiting for input!"
Case WAIT_FAILED
Debug.Print nRet, Err.LastDllError, Hex$(hProcess)
MsgBox "Wait failed."
Case WAIT_TIMEOUT
MsgBox "Wait timed out."
End Select
End If
End Sub
Private Function hProcShell(ByVal JobToDo As String, Optional ExecMode As
VbAppWinStyle = vbNormalFocus) As PROCESS_INFORMATION
' Shells a new process and returns
' the main process handle.
Dim StartUp As STARTUPINFO
Dim ProcInfo As PROCESS_INFORMATION
' Set length of StartUp structure.
StartUp.cb = Len(StartUp)
' Set appropriate StartUp flags.
StartUp.dwFlags = STARTF_USESHOWWINDOW Or STARTF_FORCEONFEEDBACK
' Set StartUp ShowWindow flag.
StartUp.wShowWindow = ExecMode
' Call CreateProcess to start requested job.
If CreateProcess(JobToDo, vbNullString, 0&, 0&, False, 0&, 0&, vbNullString,
StartUp, ProcInfo) Then
hProcShell = ProcInfo
Else
Debug.Print "Can't CreateProcess: "; Err.LastDllError
End If
End Function
I can't be sure, but this little test leads me to think that perhaps VB is actually
inserting the call to WaitForInputIdle itself, following its own call to
CreateProcess. Anyone else have a conjecture on that?
Thanks... Karl