Запустите два процесса и соедините их с каналом в Delphi

Я должен запустить две внешних программы в своей программе и соединить STDOUT первого к STDIN второй программы. Как можно достигнуть этого в Delphi (Studio RAD 2009, если он имеет значение)? Я действую в среде Windows.

Как команда командной строки выглядела бы примерно так моя ситуация:

dumpdata.exe | encrypt.exe "mydata.dat"
6
задан Steve 2 June 2010 в 12:09
поделиться

3 ответа

Быстрый тест, который, кажется, работает (вдохновленный JCL):

child1: say 'Hello, world!' 3x на стандартный вывод

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: эхо, что приходит на стандартный ввод в OutputDebugString (может быть просмотрено 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: запуск child1 перенаправляется на 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.
9
ответ дан 8 December 2019 в 18:32
поделиться

Такой подход должен работать. Прежде чем беспокоиться о вызове его из Delphi, разработайте командную строку, запустив ее в окне командной строки (окно DOS).
Затем просто вызовите эту команду из Delphi с помощью WinExec или ShellExecute. Есть варианты звонить и ждать или просто «выстрелил и забыл».

0
ответ дан 8 December 2019 в 18:32
поделиться

CreateProcess() позволяет перенаправлять как stdin, так и stdout запущенного приложения. Ваше приложение может считывать данные из первого stdout приложения и записывать во второе приложение stdin.

2
ответ дан 8 December 2019 в 18:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: