I need to launch two external programs in my program and connect the STDOUT of the first one to the STDIN of the second program. How can you achieve this in Delphi (RAD Studio 2
Here is the corrected code to work in Delphi XE. The CommandLine Strings must be variables and also defined above the ExecutePiped function.
program Parent;
{$APPTYPE CONSOLE}
uses
Windows, SysUtils, Classes;
var cmd1, cmd2 :string;
function ExecutePiped(CommandLine1: string; CommandLine2: string):string;
var
StartupInfo1, StartupInfo2 : TStartupInfo;
ProcessInfo1, ProcessInfo2 : TProcessInformation;
SecurityAttr : TSecurityAttributes;
PipeRead, PipeWrite : THandle;
Handle : Boolean;
WorkDir : String;
begin
PipeWrite := 0;
PipeRead := 0;
try
SecurityAttr.nLength := SizeOf(SecurityAttr);
SecurityAttr.bInheritHandle := True;
SecurityAttr.lpSecurityDescriptor := nil;
CreatePipe(PipeRead, PipeWrite, @SecurityAttr, 0);
FillChar(StartupInfo1, SizeOf(TStartupInfo), 0);
StartupInfo1.cb := SizeOf(TStartupInfo);
StartupInfo1.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
StartupInfo1.wShowWindow := SW_HIDE;
StartupInfo1.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
StartupInfo1.hStdOutput := PipeWrite;
StartupInfo1.hStdError := GetStdHandle(STD_ERROR_HANDLE);
FillChar(StartupInfo2, SizeOf(TStartupInfo), 0);
StartupInfo2.cb := SizeOf(TStartupInfo);
StartupInfo2.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
StartupInfo2.wShowWindow := SW_HIDE;
StartupInfo2.hStdInput := PipeRead;
StartupInfo2.hStdOutput := GetStdHandle(STD_OUTPUT_HANDLE);
StartupInfo2.hStdError := GetStdHandle(STD_ERROR_HANDLE);
FillChar(ProcessInfo1, SizeOf(TProcessInformation), 0);
FillChar(ProcessInfo2, SizeOf(TProcessInformation), 0);
WorkDir := '';
Handle := CreateProcess(nil, PChar(CommandLine2), nil, nil, True, 0, nil, PChar(WorkDir), StartupInfo2, ProcessInfo2);
Handle := CreateProcess(nil, PChar(CommandLine1), nil, nil, True, 0, nil, PChar(WorkDir), StartupInfo1, ProcessInfo1);
WaitForSingleObject(ProcessInfo2.hProcess, INFINITE);
finally
if PipeRead <> 0 then CloseHandle(PipeRead);
if PipeWrite <> 0 then CloseHandle(PipeWrite);
if ProcessInfo2.hThread <> 0 then CloseHandle(ProcessInfo2.hThread);
if ProcessInfo2.hProcess <> 0 then CloseHandle(ProcessInfo2.hProcess);
if ProcessInfo1.hThread <> 0 then CloseHandle(ProcessInfo1.hThread);
if ProcessInfo1.hProcess <> 0 then CloseHandle(ProcessInfo1.hProcess);
end;
end;
procedure Main;
begin
cmd1 := '"child1.exe"';
cmd2 := '"child2.exe"';
ExecutePiped(cmd1, cmd2);
end;
begin
try
Main;
except
on E: Exception do
begin
ExitCode := 1;
Writeln(Error, Format('[%s] %s', [E.ClassName, E.Message]));
end;
end;
end.
To test I have modified Child2.pas to write the received text into a file.
program Child2;
{$APPTYPE CONSOLE}
uses
Windows, SysUtils, Classes;
procedure Main;
var S: string;
OutFile : TextFile;
begin
AssignFile(OutFile, 'test.txt');
Rewrite(OutFile);
while not Eof(Input) do
begin
Readln(S);
Writeln(OutFile,S);
//if S <> '' then OutputDebugString(PChar(S));
end;
CloseFile(OutFile);
end;
begin
try
Main;
except
on E: Exception do
begin
ExitCode := 1;
Writeln(ErrOutput, Format('[%s] %s', [E.ClassName, E.Message]));
end;
end;
end.