rafay092498
asked on
External Application: Return Codes and Execution
The question is similar to one already posted. I need to know how I can run an exe file "synchronously" from VB (not return to VB till the new application that I am launching terminates). In addition, I need to trap the code returned by the application I launched. I can use Shell to launch the application, but all that gives me is an AppId. I do not want to do a "busy wait" till the new application exits, and even if I do decide to wait in a loop till the application exits, how do I trap the return code?
Help!!!
Help!!!
The ideal way is to not use the Shell statement. Instead, use the CreateProcess() Windows API. This returns back a HANDLE. You can use this HANDLE for the WaitForSingleObject() API to know when the application has terminated.
ASKER
Agreed. But how does this get around the problem of trapping the exact code returned by the error (e.g. did the application exit with code 0, 1, 2, other???)? From what I know (and it is quite little!), the API only indicates what event caused the process to terminate (a timeout, normal termination etc) but the exact return code returned by the application cannot be captured by the calling function.
Dim ecode As Long, nret As Long, nret2 As Long
nret = WaitForSingleObject(hProce ss, CLng(TimeOut))
nret2 = GetExitCodeProcess(hProces s, ecode) ' ecode will contain exitcode
Call CloseHandle(hProcess)
nret = WaitForSingleObject(hProce
nret2 = GetExitCodeProcess(hProces
Call CloseHandle(hProcess)
Or, get exitcode only when 'Normal completion'
If nret = 0 Then
nret2 = GetExitCodeProcess(hProces s, ecode) ' ecode will contain exitcode
End If
If nret = 0 Then
nret2 = GetExitCodeProcess(hProces
End If
ASKER
For some reason, the CreateProcess is not returning a handle. Maybe I am making a basic mistake here, but when I execute the following code, lResult contains a zero after CreateProcess call. Somehow, it seems that there is something wrong here! Any suggestions?
--
Dim uSecurityAttrib As SECURITY_ATTRIBUTES 'passed by ref
Dim uSecurityAttrib2 As SECURITY_ATTRIBUTES
Dim uProcessInfo As PROCESS_INFORMATION
Dim uStartupInfo As STARTUPINFO
Dim lResult As Long, nRet As Long, nret2 As Long, ecode As Long, Timeout As Long
Timeout = 3000000 'set to see if this was causing problems
If Index = 0 Then 'OK
lResult = CreateProcess("c:\dummyapp .exe", "12", uSecurityAttrib, uSecurityAttrib2, False, 0, "", "", uStartupInfo, uProcessInfo)
nRet = WaitForSingleObject(lResul t, CLng(Timeout))
nret2 = GetExitCodeProcess(lResult , ecode)
Call CloseHandle(lResult)
Else 'Cancel
Unload Me
End If
--
Dim uSecurityAttrib As SECURITY_ATTRIBUTES 'passed by ref
Dim uSecurityAttrib2 As SECURITY_ATTRIBUTES
Dim uProcessInfo As PROCESS_INFORMATION
Dim uStartupInfo As STARTUPINFO
Dim lResult As Long, nRet As Long, nret2 As Long, ecode As Long, Timeout As Long
Timeout = 3000000 'set to see if this was causing problems
If Index = 0 Then 'OK
lResult = CreateProcess("c:\dummyapp
nRet = WaitForSingleObject(lResul
nret2 = GetExitCodeProcess(lResult
Call CloseHandle(lResult)
Else 'Cancel
Unload Me
End If
what are the DECLAREations of WaitForSingleObject and GetExitCodeProcess?
what are the DECLAREations of WaitForSingleObject and GetExitCodeProcess?
ASKER
Oops... error... The calls should have been (I think)...
---
lResult = CreateProcess("c:\dummyapp .exe", "12", uSecurityAttrib, uSecurityAttrib2, False, 0, "", "", uStartupInfo, uProcessInfo) 'retruns a BOOl and NOT a handle!
nRet = WaitForSingleObject(uProce ssInfo.hPr ocess, CLng(Timeout))
nret2 = GetExitCodeProcess(uProces sInfo.hPro cess, ecode)
Call CloseHandle(uProcessInfo.h Process)
---
and the declares are
---
Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As SECURITY_ATTRIBUTES, lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Any, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Declare Sub GetStartupInfo Lib "kernel32" Alias "GetStartupInfoA" (lpStartupInfo As STARTUPINFO)
Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
---
---
lResult = CreateProcess("c:\dummyapp
nRet = WaitForSingleObject(uProce
nret2 = GetExitCodeProcess(uProces
Call CloseHandle(uProcessInfo.h
---
and the declares are
---
Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As SECURITY_ATTRIBUTES, lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Any, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Declare Sub GetStartupInfo Lib "kernel32" Alias "GetStartupInfoA" (lpStartupInfo As STARTUPINFO)
Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
---
thui?
ASKER
so... can u see the problem??? Note that the CreateProcess API never creates the process... what do i do??
First, create EXE which uses ExitProcess API
and put this in Form_Click
ExitProcess 5
--
I don't have a problem using it. But, since you didn't reject thui's answer, it means you are expecting solution from him.
and put this in Form_Click
ExitProcess 5
--
I don't have a problem using it. But, since you didn't reject thui's answer, it means you are expecting solution from him.
ASKER
Well, actually the reason I didnt reject thui's answer was that I was expecting a response from him. I guess I have waited long enough. As for your latest suggestion, the problem is not that the new process is NOT returning an exit code. The problem is that it is never started with the CreateProcess API. Is there anything wrong with the code that I am using? Do I need to set anything else? I am a bit new to VB, but in C++, API calls as shown in code above work fine. Also, what else can I check to make sure that the CreateProcess does actually start the application. I know for sure that it does not start it because I dont see the new application ask for an input which it should do! Finally, the application that I am going to be calling is not written by me, but i know that it exits with some codes and those codes are what I am trying to capture. A quick reply (yet again :-)) would be GREATLY appreciated :-)
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Finally! Thanks :-)
P.S. Any idea why the API calls were not working?
Thanks again!
P.S. Any idea why the API calls were not working?
Thanks again!
I think your call to CreateProces might have incorrect arguments (lpCommandLine = "12"), but I didn't try.
CORRECTION:
In my answer, in function ShellAndWait, this line:
Call CloseHandle(hProcess)
should be moved, to be the last line in function, after the End Select statement.
----
This code was tested with a simple VB project, that uses:
ExitProcess 5
in Sub Form_Click()
It looks like this doesn't work for all the possible cases, but rafay found a fix.
In my answer, in function ShellAndWait, this line:
Call CloseHandle(hProcess)
should be moved, to be the last line in function, after the End Select statement.
----
This code was tested with a simple VB project, that uses:
ExitProcess 5
in Sub Form_Click()
It looks like this doesn't work for all the possible cases, but rafay found a fix.
ASKER
One last comment. In order for the GetExitCodeProcess API to be able to get the return code, the fdwAccess parameter in OpenProcess has to be set to PROCESS_ALL_ACCESS and not to SYNCHRONIZE, and this is equal to &H80000 + &HF0000 + &HFFF. With this the API correctly returns the return code of the process.