I always used this code, which works fine. The only issue is if the other application is expecting an input (even a keypress to finish) because ReadFile will wait endlessly as far as I recall. It is easy to finetune it though.
function GetDosOutput(CommandLine: string; var ReturnString: String; var ReturnCode: Cardinal): Boolean;
const
LOGON_WITH_PROFILE = $00000001;
var
SA: TSecurityAttributes;
SI: TStartupInfo;
PI: TProcessInformation;
StdOutPipeRead, StdOutPipeWrite: THandle;
WasOK: Boolean;
Buffer: array[0..255] of AnsiChar;
BytesRead: Cardinal;
WorkDir: string;
Handle: Boolean;
begin
Handle := False;
ReturnCode := 255;
Result := False;
ReturnString := '';
SA.nLength := SizeOf(SA);
SA.bInheritHandle := True;
SA.lpSecurityDescriptor := nil;
CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
Try
With SI Do Begin
FillChar(SI, SizeOf(SI), 0);
cb := SizeOf(SI);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
wShowWindow := SW_HIDE;
//wShowWindow := SW_MINIMIZE;
hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
hStdOutput := StdOutPipeWrite;
hStdError := StdOutPipeWrite;
End;
WorkDir := '.';
Handle := CreateProcess(nil, PChar(CommandLine), nil, nil, True, CREATE_NEW_PROCESS_GROUP or CREATE_NEW_CONSOLE, nil, PChar(WorkDir), SI, PI);
CloseHandle(StdOutPipeWrite);
If Handle Then Try
Repeat
WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
If BytesRead > 0 Then Begin
Buffer[BytesRead] := #0;
ReturnString := ReturnString + Buffer;
End;
Until Not WasOK Or (BytesRead = 0);
WaitForSingleObject(PI.hProcess, INFINITE);
GetExitCodeProcess(PI.hProcess, ReturnCode);
While (Length(ReturnString)<>0) And ((ReturnString[Length(ReturnString)]=#10) Or (ReturnString[Length(ReturnString)]=#13)) Do
Delete(ReturnString,Length(ReturnString),1);
Result := True;
Finally
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
End;
Finally
CloseHandle(StdOutPipeRead);
End;
end;