2013-04-25 82 views
4

如何讓Delphi將一個字符串傳遞給CMD進程的輸入管道。我能夠得到一個錯誤管道和輸出管道功能正常,不幸的是不是輸入管道。我使用的代碼取自管道在線教程。原始代碼中有幾個錯誤導致編譯時出現問題。它們已被修復,但仍然在嘗試通過輸入時仍然存在問題。Delphi中的管道命令提示符

這是Form.Create事件中的代碼。我還包括了WritePipe和ReadPipe方法。 WritePipe不起作用,ReadPipe確實起作用。 Pipe方法中的WriteFile和ReadFile都會返回成功的消息,但只有ReadPipe實際上可以工作。

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; 

寫入管道:

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; 

讀取管道:

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; 

進一步注意;這是用於Java調試器,它需要分階段輸入,所以我不相信除了直接操縱輸入到JDB之外,還有其他方法。

任何幫助非常感謝!

+0

絕地武士代碼庫有一個組件,纏繞CreateProcess的API和轉換的輸入和輸出T流。 JCL安裝程序就是使用它的一個例子。 OTOH不要忘記在Windows圖形和文本(包括命令行)程序中使用不同的語言代碼頁。 – 2013-04-26 10:12:01

回答

5

1)你應該通過InputPipeRead作爲hStdInput到CreateProcess:取消你的行start.hStdInput := InputPipeRead;

2)WritePipeOut功能有兩個錯誤:它寫一個Unicode(UTF-16LE)字符串轉換成一個管道,它跳過第一個字符(因爲它寫入從InString [1]開始的內存區域)。取而代之的WriteFile(InputPipeWrite, InString[1], Length(InString),...,你應該寫這樣的:

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

謝謝分配!它的工作現在很棒!我一直無法找到許多關於Pipes的文檔,所以非常感謝您的幫助! – 2013-04-26 00:54:55