It is recommended to use the CreateProcess procedure instead WinExec. This is a very low-level procedure, it gives complete control over processes, threads and more.
CreateProcess takes 10 parameters, two of which are pointers to structures containing further parameters. Most parameters are not very interesting for our needs, so I have made a function CreateProcess that only takes the three most important params. The function is described in winfunc.p and can be called like in this example:
{windows.i} DEFINE VARIABLE hProcess AS INTEGER NO-UNDO. hProcess = CreateProcess("notepad.exe c:\config.sys", "", 1). IF hProcess=0 THEN ShowLastError(). RUN CloseHandle IN hpApi (hProcess, OUTPUT ReturnValue).
The first parameter is the command line with optional parameters. The second parameter is the working directory for the new process, where "" will result in the current working directory of the Progress application. The third parameter is cmdShow with the same meaning as in WinExec.
The return value is a handle to the new process or 0 if the call failed.
The GetLastError procedure did not work well in Progress 8, but it is fine now.
Do not forget to call CloseHandle. MS-Windows keeps a reference count to each kernel object, a process is a kernel object. A kernel object can not be destroyed when its reference count is larger than zero. Run CloseHandle decrements the reference count by one which only tells the kernel that you are not interested in keeping the new process alive. The process itself also has at least one reference to itself, so this CloseHandle call will not actually terminate the process. Forgetting to call CloseHandle will result in resource loss.
The following procedure also uses CreateProcess, but this time it returns a PID (process identifier) instead of a process handle.
This can be useful because procedure KillProcess expects a PID as input parameter, see terminate a process gently.
{windows.i} PROCEDURE MakeProcess : DEFINE INPUT PARAMETER CommandLine AS CHARACTER NO-UNDO. DEFINE INPUT PARAMETER WorkingDir AS CHARACTER NO-UNDO. DEFINE OUTPUT PARAMETER PID AS INTEGER NO-UNDO. DEFINE VARIABLE wShowWindow AS INTEGER NO-UNDO INITIAL 0. DEFINE VARIABLE bResult AS INTEGER NO-UNDO. DEFINE VARIABLE ReturnValue AS INTEGER NO-UNDO. DEFINE VARIABLE lpStartupInfo AS MEMPTR. SET-SIZE(lpStartupInfo) = 68. PUT-LONG(lpStartupInfo,1) = 68. PUT-LONG (lpStartupInfo,45) = 1. /* = STARTF_USESHOWWINDOW */ PUT-SHORT(lpStartupInfo,49) = wShowWindow. DEFINE VARIABLE lpProcessInformation AS MEMPTR. SET-SIZE(lpProcessInformation) = 16. DEFINE VARIABLE lpWorkingDirectory AS MEMPTR. IF WorkingDir NE "" THEN DO: SET-SIZE(lpWorkingDirectory) = 256. PUT-STRING(lpWorkingDirectory,1) = WorkingDir. END. RUN CreateProcessA IN hpApi ( 0, CommandLine, 0, 0, 0, 0, 0, IF WorkingDir="" THEN 0 ELSE GET-POINTER-VALUE(lpWorkingDirectory), GET-POINTER-VALUE(lpStartupInfo), GET-POINTER-VALUE(lpProcessInformation), OUTPUT bResult ). IF bResult=0 THEN PID = 0. ELSE DO: PID = GET-LONG(lpProcessInformation,9). /* release kernel-objects hProcess and hThread: */ RUN CloseHandle IN hpApi(GET-LONG(lpProcessInformation,1), OUTPUT ReturnValue). RUN CloseHandle IN hpApi(GET-LONG(lpProcessInformation,5), OUTPUT ReturnValue). END. SET-SIZE(lpStartupInfo) = 0. SET-SIZE(lpProcessInformation) = 0. SET-SIZE(lpWorkingDirectory) = 0. END PROCEDURE.