title: Acceptable replacement for WinExec()?
body: <p>I want to run a command that the user defined in an INI file.</p>
  
  <p>The commands can be EXE files, or other files (e.g. DOC files) and parameters should be allowed.</p>
  
  <p>Since WinExec() can handle arguments (e.g. "cmd /?"), but ShellExec() can handle Non-EXE files (e.g. "Letter.doc"), I am using a combination of these both.</p>
  
  <p>I am concerned about future Windows versions, because WinExec() is deprecated, and even from the 16 bit era.</p>
  
  <p>Here is my current function:</p>
  
  <pre><code>procedure RunCMD(cmdLine: string; WindowMode: integer);
  
    procedure ShowWindowsErrorMessage(r: integer);
    begin
      MessageDlg(SysErrorMessage(r), mtError, [mbOK], 0);
    end;
  
  var
    r, g: Cardinal;
  begin
    // We need a function which does following:
    // 1. Replace the Environment strings, e.g. %SystemRoot%  --&gt; ExpandEnvStr
    // 2. Runs EXE files with parameters (e.g. "cmd.exe /?")  --&gt; WinExec
    // 3. Runs EXE files without path (e.g. "calc.exe")       --&gt; WinExec
    // 4. Runs EXE files without extension (e.g. "calc")      --&gt; WinExec
    // 5. Runs non-EXE files (e.g. "Letter.doc")              --&gt; ShellExecute
    // 6. Commands with white spaces (e.g. "C:\Program Files\xyz.exe") must be enclosed in quotes. 
  
    cmdLine := ExpandEnvStr(cmdLine);
  
    // TODO: Attention: WinExec() is deprecated, but there is no acceptable replacement
    g := WinExec(PChar(cmdLine), WindowMode);
    r := GetLastError;
    if g = ERROR_BAD_FORMAT then
    begin
      // e.g. if the user tries to open a non-EXE file
      ShellExecute(0, nil, PChar(cmdLine), '', '', WindowMode);
      r := GetLastError;
    end;
    if r &lt;&gt; 0 then ShowWindowsErrorMessage(r);
  end;
  
  function ExpandEnvStr(const szInput: string): string;
  // http://stackoverflow.com/a/2833147/3544341
  const
    MAXSIZE = 32768;
  begin
    SetLength(Result, MAXSIZE);
    SetLength(Result, ExpandEnvironmentStrings(pchar(szInput),
      @Result[1],length(Result)));
  end;
  </code></pre>
  
  <p>Microsoft recommends using CreateProcess(), but I do not accept it as a real replacement for WinExec().</p>
  
  <p>For example, given following command line:</p>
  
  <pre><code>"C:\Program Files\xyz.exe" /a /b /c
  </code></pre>
  
  <p>Since ShellExecute() and CreateProcess() require a strict separation of command and arguments, I would have to parse this string myself. Is that really the only way I can go? Has someone written a public available code featuring this functionality?</p>
  
  <p>Additional note: The process should not be attached to the caller. My program will close, right after the command has started.</p>