2010-06-02 16 views
6

Programımda iki harici program başlatmalı ve ilk programın STDOUT'unu ikinci programın STDIN'ine bağlamalıyım. Bunu Delphi'de nasıl başarabilirsiniz (eğer önemliyse RAD Studio 2009)? Windows ortamında çalışıyorum. Bir komut olarak İki işlemi başlatın ve Delphi ile bir boruyla bağlayın

benim durumum böyle bir şey olmazdı komuta:

dumpdata.exe | encrypt.exe "mydata.dat" 

cevap

9

iş gibi görünüyor hızlı bir testi (JCL tarafından ağır ilham):

child1: demek 'Merhaba dünya!' standart çıkışa 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. 

alt2: ne olursa olsun (DebugView tarafından görülebilir) OutputDebugString standart girdi yanar yankı

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. 

veli: fırlatma child1 İşte

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. 
+0

Tam olarak aradığım şey bu. Teşekkür ederim. Bazı nedenlerden dolayı, ana programın çalıştırılması bana ilk CreateProcess satırında "kernel32.dll modülünde erişim ihlali" verir. Tüm programları yaptım. Belki bir şey özlüyorum ... – Steve

+0

Kodda A/V'ye neden olabilecek hiçbir şey göremiyorum. D2007'yi kullandım ama D2009'da da çalışmalı. –

+3

CreateProcess'in (karakter olarak Delphi 2009'un deyimiyle) geniş karakterli sürümü, komut satırı dizesini değiştirebilir; bu nedenle, bir dizeyi değişmezden geçirmeniz gerekir. Bir dize değişkeninde saklayın ve PChar'a yazmadan önce UniqueString'i arayın. –

0

yaklaşım işe gerektiğini. Delphi'den arama konusunda endişelenmeden önce, bir komut istemi penceresinde (DOS penceresi) çalışarak komut satırının çalışmasını sağlayın.
Ardından bu komutu WinExec veya ShellExecute ile Delphi'den çağırın. Aramak ve beklemek ya da sadece "ateşle ve unut" seçenekleri vardır.

+0

Komut, komut satırında iyi çalışır. Süreçlerin bitmesini beklemek istiyorsam, bunu nasıl başarabilirim? Endişelenmem gereken, piped komutu ShellExecute (Ex) parametrelerine nasıl dahil edilmelidir? LpFile parametresinde tamamen mi yoksa kısmen de lpParameters mi? – Steve

+1

AFAIK, Windows API'sı değil, yönlendirme operatörlerini işlemek için komut kabuğu ("DOS" olmayan bir pencere, bir GUI olmayan win32/64 alt sistemi) 'dir. Öyleyse bu komut sadece cmd.exe dosyasını çağırmak ve bu komut satırını ona aktarmak için kullanılabilir. –

2

CreateProcess(), başlatılan uygulamaların hem stdin hem de stdout'unu yeniden yönlendirmenizi sağlar. Uygulamanız ilk uygulama stdout'undan okuyabilir ve ikinci uygulamaya stdin yazabilir.

+0

Ortadaki adamı dışarıda bırakmanın ve iki sürecin birbiriyle doğrudan iletişim kurmasına izin vermenin bir yolu var mı? – Steve

2

child2 yönlendirildi Delphi XE'de çalışmak için düzeltilmiş koddur. CommandLine Dizeleri, değişkenler olmalı ve ayrıca ExecutePiped işlevinin üstünde tanımlanmış olmalıdır.

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. 

Test etmek için Alınan metni bir dosyaya yazmak için Child2.pas'ı değiştirdim.

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.