Einzelnen Beitrag anzeigen

viakt133

Registriert seit: 16. Feb 2010
18 Beiträge
 
Lazarus
 
#9

Re: Name der Windoes Konsole zur KOmmunikation auf cmd.exe?

  Alt 19. Feb 2010, 12:49
Hallo,

Danke erst mal für Eure Antworten. Daraus habe ich mir jetzt die folgende Lösung gebaut:

Delphi-Quellcode:
unit IPCConsole;

interface

var
  StartupInfo: TStartupInfo;

  ProcessInfo: TProcessInformation;

  SecurityAttr: TSecurityAttributes;

  PipeOutputRead: THandle;

  PipeOutputWrite: THandle;

  PipeErrorsRead: THandle;

  PipeErrorsWrite: THandle;

  ConsoleOutput : TStringList;

  ConsoleErrors : TStringList;



function StartProcessDone(const AProcessStartCommand: String): Boolean;

function SendCommandDone(const Command: String; var Output, Errors: TStringList): Boolean;

implementation

function StartProcessDone(const AProcessStartCommand: String): Boolean;
var
  Succeed: Boolean;

  Buffer: array [0..255] of Char;

  NumberOfBytesRead: DWORD;

  Stream: TMemoryStream;
begin

  //Initialisierung ProcessInfo

  FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);


  //Initialisierung SecurityAttr

  FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0);

  SecurityAttr.nLength := SizeOf(SecurityAttr);

  SecurityAttr.bInheritHandle := true;

  SecurityAttr.lpSecurityDescriptor := nil;


  //Pipes erzeugen

  CreatePipe(PipeOutputRead, PipeOutputWrite, @SecurityAttr, 0);

  CreatePipe(PipeErrorsRead, PipeErrorsWrite, @SecurityAttr, 0);


  //Initialisierung StartupInfo

  FillChar(StartupInfo, SizeOf(TStartupInfo), 0);

  StartupInfo.cb:=SizeOf(StartupInfo);

  StartupInfo.hStdInput := 0;

  StartupInfo.hStdOutput := PipeOutputWrite;

  StartupInfo.hStdError := PipeErrorsWrite;

  StartupInfo.wShowWindow := sw_Hide;

  StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;


  if CreateProcess(nil, PChar(command), nil, nil, true,

  CREATE_DEFAULT_ERROR_MODE or CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil,

  StartupInfo, ProcessInfo) then begin

    result:=true;

    //Write-Pipes schließen

    //CloseHandle(PipeOutputWrite);

    //CloseHandle(PipeErrorsWrite);


    //Ausgabe Read-Pipe auslesen

    Stream := TMemoryStream.Create;

    try

      while true do begin

        succeed := ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil);

        if not succeed then break;

        Stream.Write(Buffer, NumberOfBytesRead);

      end;

      Stream.Position := 0;

      Output.LoadFromStream(Stream);

    finally

      Stream.Free;

    end;

    //CloseHandle(PipeOutputRead);


    //Fehler Read-Pipe auslesen

    Stream := TMemoryStream.Create;

    try

      while true do begin

        succeed := ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytesRead, nil);

        if not succeed then break;

        Stream.Write(Buffer, NumberOfBytesRead);

      end;

      Stream.Position := 0;

      Errors.LoadFromStream(Stream);

    finally

      Stream.Free;

    end;

    //CloseHandle(PipeErrorsRead);


    WaitForSingleObject(ProcessInfo.hProcess, INFINITE);

    //CloseHandle(ProcessInfo.hProcess);

  end

  else begin

    result:=false;

    CloseHandle(PipeOutputRead);

    CloseHandle(PipeOutputWrite);

    CloseHandle(PipeErrorsRead);

    CloseHandle(PipeErrorsWrite);

  end;

end;

function SendCommandDone(const Command: String; var Output, Errors: TStringList): Boolean;
var
  Succeed: Boolean;

  Buffer: array [0..255] of Char;

  NumberOfBytesRead: DWORD;

  Stream: TMemoryStream;

begin
    //Ausgabe Read-Pipe auslesen

    Stream := TMemoryStream.Create;

    try

      while true do begin

        succeed := ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil);

        if not succeed then break;

        Stream.Write(Buffer, NumberOfBytesRead);

      end;

      Stream.Position := 0;

      ConsoleOutput.LoadFromStream(Stream);

    finally

      Stream.Free;

    end;

    //CloseHandle(PipeOutputRead);


    //Fehler Read-Pipe auslesen

    Stream := TMemoryStream.Create;

    try

      while true do begin

        succeed := ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytesRead, nil);

        if not succeed then break;

        Stream.Write(Buffer, NumberOfBytesRead);

      end;

      Stream.Position := 0;

      ConsoleErrors.LoadFromStream(Stream);

    finally

      Stream.Free;

    end;

end;

initialization
  ConsoleOutput := TStringList.Create;
  ConsoleErrors := TStringList.Create;

finalization
  ConsoleErrors.Free;
  ConsoleOutput.Free;

end.

program p_console_read_write;

uses
  SysUtils,
  Classes,
  IPCConsole in 'IPCConsole.pas';

var
 Command: String;

procedure GetOutputFrom(var OutList: TStringList);
var cnt,i: Integer;
begin
  if Assigned(OutList) then
  begin
    i := 0;
    cnt := OutList.Count;
    while i<cnt do
    begin
      writeln('#### AUSGABE ####::: ',OutList[i]);
      inc(i);
    end;
    Writeln; Writeln;
  end;
end;

begin
  if StartProcessDone('MyProcess.exe') then
  repeat
    Write('Give a Command: '); Readln(Command);
    if SendCommandDone(Command, ConsoleOutput, ConsoleErrors) then GetOutputFrom(ConsoleOutput);
  until Command = 'q';
end.
Nun wird aber in meiner Funktion immer wieder CreateProcess aufgerufen. Wie erreiche ich nun, das beim 2. bis n-ten Durchlauf immer wieder derselbe Prozess benutzt wird und nicht etwa neue Instanzen gestartet werden.

Im MSDN habe ich nur Named Pipes gefunden. Sollte das denn aber nicht auch mit unnamed Pipes gehen.
Sviel ich bis jetzt davon verstanden habe, kann eine unnamed pipe nur in eriner Richtung (lesen oder schreiben) arbeiten. Hier im Quelltext werden aber schon zwei Pipes erzeugt, eine zum Lesen, eine zum Schreiben, wie ich es am Ende ja auch brauche. Aber wie greife ich nun auf diese Pipes zu?


Während ich die Frage formuliere kommen mir Ideen, wie ich mein Ziel erreichen könnte. Aber dennoch habe ich folgende Fragen:

Im obigen Quelltext werden zuerst, nach dem Füllen der StartupInfo die Pipes erzeugt. Dann wird in die Input-Pipe geschrieben, zB. mein Kommando. Das wird dann per MemoryStream in die Output Stringliste geschrieben.

Aber wenn ich das jetzt starte, bleibt der Konsolenbildschirm schwarz. Warum komme ich nicht in die Repeat until Schleife?

Wenn ich mir eine Routine schreibe, die per Pipe ein Kommando sendesn soll, hängt es am Screiben der Pipe. Werde wohl jetzt erst mal Interfaces weiter betrachten.

Delphi-Quellcode:
function SendCommand(const Command: String): Boolean;
var
  Buffer: array[0..255] of char;
  NumberOfBytesWritten: DWORD;
begin
  if PipesUsed then
  begin
    Writeln('Schreiben des Kommandos -> ',Command);
    move(Command[1], Buffer, Length(Command)); Buffer[Length(Command)]:=#0;
    PipesUsed := WriteFile(PipeOutputWrite, Buffer, 255, NumberOfBytesWritten, nil);
    Result := PipesUsed;
  end
  else Result := PipesUsed;
end;
  Mit Zitat antworten Zitat