Start two processes and connect them with a pipe in Delphi

前端 未结 4 2152
一整个雨季
一整个雨季 2021-02-09 16:09

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

4条回答
  •  余生分开走
    2021-02-09 16:47

    A quick test which seems to work (inspired heavily by JCL):

    child1: say 'Hello, world!' 3x to standard output

    program child1;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils;
    
    procedure Main;
    var
      I: Integer;
    begin
      for I := 0 to 2 do
        Writeln('Hello, world!');
      Write(^Z);
    end;
    
    begin
      try
        Main;
      except
        on E: Exception do
        begin
          ExitCode := 1;
          Writeln(ErrOutput, Format('[%s] %s', [E.ClassName, E.Message]));
        end;
      end;
    end.
    

    child2: echo whatever comes on standard input to OutputDebugString (can be viewed by DebugView)

    program child2;
    
    {$APPTYPE CONSOLE}
    
    uses
      Windows, SysUtils, Classes;
    
    procedure Main;
    var
      S: string;
    begin
      while not Eof(Input) do
      begin
        Readln(S);
        if S <> '' then
          OutputDebugString(PChar(S));
      end;
    end;
    
    begin
      try
        Main;
      except
        on E: Exception do
        begin
          ExitCode := 1;
          Writeln(ErrOutput, Format('[%s] %s', [E.ClassName, E.Message]));
        end;
      end;
    end.
    

    parent: launch child1 redirected to child2

    program parent;
    
    {$APPTYPE CONSOLE}
    
    uses
      Windows, Classes, SysUtils;
    
    procedure ExecutePiped(const CommandLine1, CommandLine2: string);
    var
      StartupInfo1, StartupInfo2: TStartupInfo;
      ProcessInfo1, ProcessInfo2: TProcessInformation;
      SecurityAttr: TSecurityAttributes;
      PipeRead, PipeWrite: THandle;
    begin
      PipeWrite := 0;
      PipeRead := 0;
      try
        SecurityAttr.nLength := SizeOf(SecurityAttr);
        SecurityAttr.lpSecurityDescriptor := nil;
        SecurityAttr.bInheritHandle := True;
        Win32Check(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);
    
        Win32Check(CreateProcess(nil, PChar(CommandLine2), nil, nil, True, NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo2,
          ProcessInfo2));
    
        Win32Check(CreateProcess(nil, PChar(CommandLine1), nil, nil, True, NORMAL_PRIORITY_CLASS, nil, nil, 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
      ExecutePiped('child1.exe', 'child2.exe');
    end;
    
    begin
      try
        Main;
      except
        on E: Exception do
        begin
          ExitCode := 1;
          Writeln(Error, Format('[%s] %s', [E.ClassName, E.Message]));
        end;
      end;
    end.
    

提交回复
热议问题