Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Name der Windoes Konsole zur KOmmunikation auf cmd.exe? (https://www.delphipraxis.net/147893-name-der-windoes-konsole-zur-kommunikation-auf-cmd-exe.html)

viakt133 18. Feb 2010 12:47


Name der Windoes Konsole zur KOmmunikation auf cmd.exe?
 
Hallo,

Ich habe in Dokus gelesen, das unter Linux eine Konsole unter /dev/ttyX ansprechbar ist. Gibt es da ein Äquivalent in Windows, falls ich auf der Kommandozeile die Konsole als Kommunikationsmedium ansprechen will/muss?

Ist das "con"? Wie beim Kommando "copy con <myfile.txt>"

Oder gibt es da für allgemeine Verwendung noch einen anderen Namen?

Dezipaitor 18. Feb 2010 12:53

Re: Name der Windoes Konsole zur KOmmunikation auf cmd.exe?
 
Linux besitzt Standardkonsolen auf die man im Betrieb umschalten kann. Das gibt es bei Windows nicht, daher kann man nicht so einfach mit Konsolen kommunizieren.

himitsu 18. Feb 2010 13:22

Re: Name der Windoes Konsole zur KOmmunikation auf cmd.exe?
 
Willst du die Konsole zu einem/deinem Prozess ansprechen oder Irgendeine eines anderen Programms?

Es gibt ja nicht nur die eine Konsole, also gibt es da auch keine Allgemeine Adresse, um diese anzusprechen.

Aber die Konsole, welche mit einem bestimmten Programm verbunden ist, läßt sich schon rausfinden und ansprechen (am Einfachsten natürlich die Konsole zum eigenem Programm)

viakt133 18. Feb 2010 18:50

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

Zitat von himitsu
Willst du die Konsole zu einem/deinem Prozess ansprechen oder Irgendeine eines anderen Programms?

Es gibt ja nicht nur die eine Konsole, also gibt es da auch keine Allgemeine Adresse, um diese anzusprechen.

Aber die Konsole, welche mit einem bestimmten Programm verbunden ist, läßt sich schon rausfinden und ansprechen (am Einfachsten natürlich die Konsole zum eigenem Programm)

Von meinem Prozess aus die eines anderen Prozesses.

Astat 18. Feb 2010 19:19

Re: Name der Windoes Konsole zur KOmmunikation auf cmd.exe?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo viakt133, du suchst dass!

lg. Astat

viakt133 19. Feb 2010 05:09

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

Zitat von Astat
Hallo viakt133, du suchst dass!

JEDI-VCL Demo -> TJvCreateProcess --> JvCreateProcess

lag. Astat

Danke! Von der Aufgabenstellung her, ja. Mein Freund wäre da das CreateProcessExample.dpr. Leider hab ich aber Probleme, die Jedis richtig zu installieren und wenn ich nur den Suchpfad angebe, findet der Compiler auch vieles nicht, was in der folgenden Compilermeldung endet:

[Fataler Fehler] Consts.pas(313): Ausgabedatei '..\..\dcu\Consts.dcu' kann nicht erstellt werden

Habe deshalb gegoogelt und dabei die Windows-API Funktion CreateProcess gefunden. Die gibt doch den Handle des laufenden Prozesses zurück. Könnte dieser Handle nicht auch eine Schnittstelle zu jenem Prozess bilden, den ich von meinem Prozess aus ansprechen will?

Werde mal sicherheitshalber auf diesen Thread hier verlinken. Dort habe ich die für das Problem interessante Funktion function GetProcessHandleFromID(ID: DWORD): THandle; gefunden.

Nun suche ich aber eine möglichst einfache Möglichkeit zur Prozesskommunikation ohne "Schnörkel". Nur zum Experimentieren.

mse1 19. Feb 2010 07:19

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

Zitat von viakt133
Könnte dieser Handle nicht auch eine Schnittstelle zu jenem Prozess bilden, den ich von meinem Prozess aus ansprechen will?

Verbinde vor dem CreateProcess()-Aufruf pipes mit STARTUPINFO hStdInput, hStdOutput und ev. hStdError und setze in dwFlags STARTF_USESTDHANDLES. Dies entspricht dann in etwa stdin, stdout und stderr unter Linux.
http://msdn.microsoft.com/en-us/libr...8VS.85%29.aspx
Beispielcode gibt es z.B. in Free Pascal und MSEgui.

Martin

Astat 19. Feb 2010 10:43

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

Zitat von viakt133
..Von der Aufgabenstellung her, ja. Mein Freund wäre da das CreateProcessExample.dpr.

Hallo viakt133, glaub mir, ist nicht Dein Freund, sieh dir mal die Unit uPipedProcess.pas an, und suche nach CreateProcess.

Habe bei meinem vorigen Thread die Attachment, durch nicht Componenten Version ersetzt.

Du kannst es jetzt ohne Komponenten compillieren.

lg. Astat

viakt133 19. Feb 2010 12:49

Re: Name der Windoes Konsole zur KOmmunikation auf cmd.exe?
 
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;


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:52 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz