CreateProcess

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.

notes

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.

returning a PID

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.