Pipes in Delphi for the command line

How can I get Delphi to pass a string into the input channel to the CMD process. I can work normally with the error tube and output labor, unfortunately, not the input channel. The code I use is taken from an online tutorial for piping. There were several errors in the source code that caused compilation problems. They were fixed, but I still have problems trying to transfer the input yet.

Here is the code in the Form.Create event. I also included the WritePipe and ReadPipe methods. WritePipe does not work, ReadPipe works. Both the WriteFile and ReadFile methods in the Pipe methods return a successful message, however, only ReadPipe actually works.

var DosApp: String; DosSize: Integer; Security : TSecurityAttributes; start : TStartUpInfo; byteswritten: DWord; WriteString : ansistring; begin CommandText.Clear; // get COMSPEC variable, this is the path of the command-interpreter SetLength(Dosapp, 255); DosSize := GetEnvironmentVariable('COMSPEC', @DosApp[1], 255); SetLength(Dosapp, DosSize); // create pipes With Security do begin nlength := SizeOf(TSecurityAttributes) ; binherithandle := true; lpsecuritydescriptor := nil; end; CreatePipe(InputPipeRead, InputPipeWrite, @Security, 0); CreatePipe(OutputPipeRead, OutputPipeWrite, @Security, 0); CreatePipe(ErrorPipeRead, ErrorPipeWrite, @Security, 0); // start command-interpreter FillChar(Start,Sizeof(Start),#0) ; //start.hStdInput := InputPipeRead; start.hStdOutput := OutputPipeWrite; start.hStdError := ErrorPipeWrite; start.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW; start.wShowWindow := SW_Show;//SW_HIDE; start.cb := SizeOf(start) ; if CreateProcess('', PChar(DosApp), @Security, @Security, true, CREATE_NEW_CONSOLE or SYNCHRONIZE, // CREATE_NO_WINDOW, nil, nil, start, ProcessInfo) then begin MyThread := MainUnit.monitor.Create; // start monitor thread MyThread.Priority := tpHigher; end; Button1.Enabled := true; cmdcount := 1; end; 

Write Pipe:

 procedure WritePipeOut(OutputPipe: THandle; InString: PWideChar); // writes Instring to the pipe handle described by OutputPipe var count : integer; byteswritten: DWord; outputstring : PAnsiChar; TextBuffer: array[1..32767] of AnsiChar;// char; TextString: String; begin // most console programs require CR/LF after their input. InString := PWideChar(InString + #13#10); WriteFile(InputPipeWrite, InString[1], Length(InString), byteswritten, nil); end; 

Read the handset:

 function ReadPipeInput(InputPipe: THandle; var BytesRem: Integer): String; { reads console output from InputPipe. Returns the input in function result. Returns bytes of remaining information to BytesRem } var TextBuffer: array[1..32767] of AnsiChar;// char; TextString: String; BytesRead: Cardinal; PipeSize: Integer; begin Result := ''; PipeSize := length(TextBuffer); // check if there is something to read in pipe PeekNamedPipe(InputPipe, nil, PipeSize, @BytesRead, @PipeSize, @BytesRem); if bytesread > 0 then begin ReadFile(InputPipe, TextBuffer, pipesize, bytesread, nil); // a requirement for Windows OS system components OemToChar(@TextBuffer, @TextBuffer); TextString := String(TextBuffer); SetLength(TextString, BytesRead); Result := TextString; end; end; 

Next, note; this is for use with Java Debugger, which requires input in stages, and therefore I do not believe that there is any alternative method other than controlling input directly in JDB.

Any help is much appreciated!

+4
source share
1 answer

1) You must pass InputPipeRead as hStdInput to CreateProcess : uncomment your line start.hStdInput := InputPipeRead;

2) The WritePipeOut function has two errors: it writes a Unicode string (UTF-16LE) to the channel and skips the first character (since it writes the memory area starting with InString [1]). Instead of WriteFile(InputPipeWrite, InString[1], Length(InString),... you should write something like:

 var AnsiBuf: AnsiString; ... AnsiBuf := String(InString) + #13#10; Write(InputPipeWrite, AnsiBuf[1], Length(AnsiBuf), byteswritten, nil); 
+5
source

All Articles