我需要在程序中启动两个外部程序,并将第一个程序的STDOUT连接到第二个程序的STDIN.如何在Delphi中实现这一目标(RAD Studio 2009,如果重要的话)?我在
Windows环境中运行.
作为命令行命令,我的情况看起来像这样:
dumpdata.exe | encrypt.exe "mydata.dat"
解决方法
一个似乎有效的快速测试(受到
JCL的重大启发):
child1:说’你好,世界!’ 3倍至标准输出
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,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,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,0); Win32Check(CreateProcess(nil,PChar(CommandLine2),nil,True,NORMAL_PRIORITY_CLASS,StartupInfo2,ProcessInfo2)); Win32Check(CreateProcess(nil,PChar(CommandLine1),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,E.Message])); end; end; end.