title: Getting output from a command-line program in a Delphi application on Windows XP
body: <p>I have VCL application written in Delphi XE2 that needs to execute a command-line program (also written in Delphi XE2) and obtain the text output by it. I am currently using the following code, which is based on that found here: <a href="https://stackoverflow.com/questions/9119999/getting-output-from-a-shell-dos-app-into-a-delphi-app/9120103#9120103">Getting output from a shell/dos app into a Delphi app</a></p>
  
  <pre><code>function GetDosOutput(ACommandLine : string; AWorkingDirectory : string): string;
  var
    SecurityAttributes : TSecurityAttributes;
    StartupInfo : TStartupInfo;
    ProcessInformation: TProcessInformation;
    StdOutPipeRead, StdOutPipeWrite: THandle;
    WasOK: Boolean;
    Buffer: array[0..255] of AnsiChar;
    BytesRead: Cardinal;
    Handle: Boolean;
  begin
    Result := '';
    SecurityAttributes.nLength := SizeOf(TSecurityAttributes);
    SecurityAttributes.bInheritHandle := True;
    SecurityAttributes.lpSecurityDescriptor := nil;
    CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SecurityAttributes, 0);
    try
      FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
      StartupInfo.cb := SizeOf(TStartupInfo);
      StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
      StartupInfo.wShowWindow := SW_HIDE;
      StartupInfo.hStdInput := StdOutPipeRead;
      StartupInfo.hStdOutput := StdOutPipeWrite;
      StartupInfo.hStdError := StdOutPipeWrite;
      FillChar(ProcessInformation, SizeOf(ProcessInformation), 0);
      Handle := CreateProcess(
        nil,
        PChar(ACommandLine),
        nil,
        nil,
        True,
        0,
        nil,
        PChar(AWorkingDirectory),
        StartupInfo,
        ProcessInformation
      );
      CloseHandle(StdOutPipeWrite);
      if Handle then
        try
          repeat
            WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
            if BytesRead &gt; 0 then
            begin
              Buffer[BytesRead] := #0;
              Result := Result + Buffer;
            end;
          until not WasOK or (BytesRead = 0);
          WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
        finally
          CloseHandle(ProcessInformation.hThread);
          CloseHandle(ProcessInformation.hProcess);
        end;
    finally
      CloseHandle(StdOutPipeRead);
    end;
  end;
  </code></pre>
  
  <p>This works fine on most versions of Windows. Unfortunately it has recently come to our attention that it does not work on Windows XP. The call to WaitForSingleObject simply never returns. I tried replacing the second parameter INFINITE with a smaller value (e.g. 15000) but that doesnt't seem to make any difference. In Task Manager I can see that, after calling GetDosOutput, the command-line program is actually running. If I end the VCL application, the command-line program <em>then</em> seems to complete its work successfully (as evidenced by the fact that it outputs the files I was expecting it to). I've also noticed that if I remove STARTF_USESTDHANDLES from StartupInfo.dwFlags, the command-line program runs normally and WaitForSingleObject returns promptly; however I am then obviously unable to obtain the text returned by the program.</p>
  
  <p>Does anybody have a suggestion as to how I can get this working on Windows XP?</p>