Entwickler-Ecke

Windows API - Aus Konsole lesen


gizmo - Mi 11.02.09 15:39
Titel: Aus Konsole lesen
Hallo,
Ich möchte unter WinXP den Inhalt der bereits geöffneten Konsole(cmd.exe) auslesen.
Ich habe mich eine Zeit lang damit beschäftigt:
http://www.delphi-forum.de/viewtopic.php?t=18095&highlight=konsole+lesen
aber das scheint nicht ganz das Richtige zu sein.

Hintergrund: Könnte man Werte, die in der Konsole angezeigt werden mit copy/paste entnehmen, wäre kein weiteres Programm notwendig.
Da das nicht geht muss ich vermeiden, dass Ich und Andere gezwungen sind diese Werte abzuschreiben, da die Fehleranfälligkeit dann zu groß ist.
Also brauche ich eine Anwendung, die den Konsole Inhalt in einem Memo anzeigt, aus welchem man kopieren kann.

Der Nachbau der Anwendung, die die Werte innerhalb der Konsole generiert liegt völlig außerhalb meiner Möglichkeiten (Kryptographie)

Grüße
Gizmo


JayEff - Mi 11.02.09 15:49
Titel: Re: Aus Konsole lesen
user profile icongizmo hat folgendes geschrieben Zum zitierten Posting springen:
Hintergrund: Könnte man Werte, die in der Konsole angezeigt werden mit copy/paste entnehmen, wäre kein weiteres Programm notwendig.
Rechtsklick auf die Konsole -> Markieren, nach der Markierung Enter drücken oder Rechtsklick->Kopieren :zustimm:


Nico72 - Mi 11.02.09 15:53

Hallo,

oder leite doch einfach die Ausgabe in eine Datei um. Also anstatt in der Konsole
"c:\MachEineAusgabe.exe" einzugeben nimm
"c:\MacheineAusgabe.exe >c:\Test.txt". Die Ausgabewerte findest du dann unter c:\Test.txt.


gizmo - Mi 11.02.09 16:20

Also das mit dem Umleiten in eine Textdatei sehe ich nicht.
Ich mache einen Rechtsklick auf einem 8GB Zip File und wähle Senden an MD5.BAT.
Darauf hin erscheint die Konsole mit dem Hash Wert, den ich benötige und den ich per E-Mail versenden muss.
Das sollen auch meine Kollegen ausführen können und denen kann ich nicht mit "Öffnen mit Parametern" und sowas kommen.

Was ich nicht wusste, und auch nie herausbekommen hätte, ist der Trick mit der ENTER Taste.
Rechtsklick und kopieren erzeugt leider keine Daten auf dem Clipboard. Das bleibt leer oder enthält einen alten Wert.
Mit der Entertaste geht es allerdings und das ist ausreichend unkompliziert.

Somit ist alles Gut. Danke euch!


Nico72 - Mi 11.02.09 16:27

Hast du denn mal geschaut, was in der Batch-Datei passiert? Vielleicht gibt es ja da einen noch einfacheren Weg...


JayEff - Mi 11.02.09 16:31

user profile iconNico72 hat folgendes geschrieben Zum zitierten Posting springen:
Hast du denn mal geschaut, was in der Batch-Datei passiert? Vielleicht gibt es ja da einen noch einfacheren Weg...

Richtig, ich wette, in der Batch-Datei kann man auch die Ausgabe auf eine Textdatei umleiten, die dann versendet werden kann, im Zweifelsfall die Datei in einer zweiten Batchdatei wrappen:

Quelltext
1:
2:
3:
4:
5:
@echo off
echo Erzeuge MD5-Prüfsumme in %appdata%\MD5.txt ...
MD5.bat %1 %2 %3 >%appdata%\MD5.txt
echo Erledigt! Bitte die Datei an die Email anhängen!
pause
:mrgreen:
(ungetestet. so oder so ähnlich.)


Narses - Mi 11.02.09 17:08

Moin!

Ähm, MD5-Hash von ´ner Datei ist doch nur ein Einzeiler, was soll denn das Gehampel mit dem Batch... :?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils, MD5;

begin
  if FileExists(ParamStr(1)) then
    WriteLn(MD5Print(MD5File(ParamStr(1))))
  else
    WriteLn('File not found!');
end.
cu
Narses


JayEff - Mi 11.02.09 17:11

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
1:
{$APPTYPE CONSOLE}                    
user profile icongizmo hat folgendes geschrieben Zum zitierten Posting springen:
Hintergrund: Könnte man Werte, die in der Konsole angezeigt werden mit copy/paste entnehmen, wäre kein weiteres Programm notwendig.
:mrgreen: Schon klar, du meinst das nur als Beispiel (:


gizmo - Mi 11.02.09 19:06

Hmm..

{$APPTYPE CONSOLE} verstehe ich nicht.

if FileExists(ParamStr(1)) Was soll das für ein File sein?
Die MD5.exe, oder die Batch Datei?

WriteLn(MD5Print(MD5File(ParamStr(1))))
In welche Komponente wird hier geschrieben?

Es gibt eine MD5 Unit in Delphi?
Verdammt, ich weiß wirklich gar nix.


Narses - Mi 11.02.09 19:12

Moin!

user profile icongizmo hat folgendes geschrieben Zum zitierten Posting springen:
{$APPTYPE CONSOLE} verstehe ich nicht.
Ich habe einfach eine Konsolen-App angelegt. Datei->Neu->Konsolen-Anwendung. :idea:

user profile icongizmo hat folgendes geschrieben Zum zitierten Posting springen:
if FileExists(ParamStr(1)) Was soll das für ein File sein?
Das ist der erste Kommandozeilenparameter -> wenn du im Explorer eine Datei auf die EXE ziehst, wird dir hier der Dateiname übergeben.

user profile icongizmo hat folgendes geschrieben Zum zitierten Posting springen:
Die MD5.exe, oder die Batch Datei?
Das ist ja der Witz: brauchst du beides nicht (mehr). :)

user profile icongizmo hat folgendes geschrieben Zum zitierten Posting springen:
WriteLn(MD5Print(MD5File(ParamStr(1))))
In welche Komponente wird hier geschrieben?
In keine, es wird in den StandardOutput-Stream geschrieben -> in das Konsolenfenster, in dem die EXE läuft.

user profile icongizmo hat folgendes geschrieben Zum zitierten Posting springen:
Es gibt eine MD5 Unit in Delphi?
Yip, such mal Suche in: Delphi-Forum, Delphi-Library MD5 UNIT

cu
Narses

//EDIT: Seit irgend einer Windows-Version kann man das auch über die Crypto-API machen, dann braucht man gar keine extra Unit mehr. Mal im MSDN suchen gehen. :idea:


bummi - Mi 11.02.09 19:15

>> läuft bis incl. delphi 2007 (2009 habe ich noch ein Problem mit den Strings)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
Procedure TheCallBack(s:String);
var
  ansi:String;
begin
  Setlength(ansi,length(s));
  OemToAnsi(Pchar(s),Pchar(ansi));
  Form1.Memo1.Text:=Form1.Memo1.Text+ansi;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin

//   cs:=TConsoleThread.Create('Ping 192.168.1.1', '','',TheCallBack);
   cs:=TConsoleThread.Create('cmd /C CD \|dir'#13#10'','',TheCallBack);  // ACHTUNG CMD nur so


   cs.Resume;
end;

unit ConsoleThread;
//by Thomas Wassermann
interface

uses Windows,Classes,Forms,Dialogs;


  Type
  TCallBackProcedure = Procedure (Result:String);
  TConsoleThread = class(TThread)
  private
  FEnvironment,FOutPut,FErrors,FInput,FCommand:String;
  FCallBackProcedure:TCallBackProcedure;
  FCurrentOutPut:String;
  FOK:Boolean;
  protected
    procedure Execute; override;
    Procedure SendCallBack;
  public
    constructor Create(const Command,Input, Environment:String;CallBackProcedure:TCallBackProcedure);
  end;

implementation

Procedure TConsoleThread.SendCallBack;
begin
  FCallBackProcedure(FCurrentOutPut);
end;

constructor TConsoleThread.Create(const Command,Input, Environment:String;CallBackProcedure:TCallBackProcedure);
begin
  FCallBackProcedure:=CallBackProcedure;
  FreeOnTerminate:=true;
  FInput:=Input;
  FEnvironment:=Environment;
  FCommand:=Command;
  inherited Create(true);
end;

{-----------------------------------------------------------------------------
  Procedure: TConsoleThread.Execute
  Author:    Thomas Wassermann
  Date:      09-Nov-2004
  Arguments: None
  Result:    None
  Remarks:   None
-----------------------------------------------------------------------------}

Procedure TConsoleThread.Execute;
var
  StartupInfo: TStartupInfo;
  ProcessInfo: TProcessInformation;
  SecurityAttr: TSecurityAttributes;
  PipeOutputRead: THandle;
  PipeOutputWrite: THandle;
  PipeInputWrite: THandle;
  PipeInputRead: THandle;
  PipeErrorsRead: THandle;
  PipeErrorsWrite: THandle;
  Succeed: Boolean;
  Buffer: array [0..255of Char;
  NumberOfBytesRead: DWORD;
  Stream: TMemoryStream;
  p:PChar ;
begin

  FOutput := '';
  FErrors := '';
  //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);
  CreatePipe(PipeInputRead, PipeInputWrite, @SecurityAttr, 0);

  WriteFile(PipeInputWrite, FInput[1], Length(FInput), NumberOfBytesRead, nil);

  //Initialisierung StartupInfo
  FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
  StartupInfo.cb:=SizeOf(StartupInfo);
  StartupInfo.hStdInput := PipeInputRead;
  StartupInfo.hStdOutput := PipeOutputWrite;
  StartupInfo.hStdError := PipeErrorsWrite;
  StartupInfo.wShowWindow := sw_Hide;
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
  if Length(FEnvironment)=0 then p:=nil else p:=PChar(FEnvironment);


  if  CreateProcess(nil, PChar(Fcommand), nilnil, true,
  CREATE_DEFAULT_ERROR_MODE or CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, p, nil,
  StartupInfo, ProcessInfo) then begin
    FOK:=true;
    //Write-Pipes schließen
    CloseHandle(PipeOutputWrite);
    CloseHandle(PipeErrorsWrite);
    CloseHandle(PipeInputWrite);
    CloseHandle(PipeInputRead);

    //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);

        FCurrentOutPut:=Copy(buffer,1,NumberOfBytesRead);
        if Assigned(FCallBackProcedure) then Synchronize(SendCallBack);
        Application.ProcessMessages;
      end;
      Stream.Position := 0;
      SetLength(FOutput, Stream.Size);
      if Stream.Size > 0 then
        Stream.Read(FOutput[1], Stream.Size)
    finally
      Stream.Free;
    end;
    CloseHandle(PipeOutputRead);
    Stream := TMemoryStream.Create;
    try
      while true do begin
        succeed := ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytesRead, nil);
        if not succeed then break;
        Stream.Write(Buffer, NumberOfBytesRead);
        FCurrentOutPut:=Copy(buffer,1,NumberOfBytesRead);
        if Assigned(FCallBackProcedure) then Synchronize(SendCallBack);
        Application.ProcessMessages;        
      end;
      Stream.Position := 0;
      SetLength(FErrors, Stream.Size);
      if Stream.Size > 0 then
        Stream.Read(FErrors[1], Stream.Size)
    finally
      Stream.Free;
    end;
    CloseHandle(PipeErrorsRead);
    WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
    CloseHandle(ProcessInfo.hProcess);
  end
  else begin
    FOK:=false;
    CloseHandle(PipeOutputRead);
    CloseHandle(PipeOutputWrite);
    CloseHandle(PipeErrorsRead);
    CloseHandle(PipeErrorsWrite);
  end;
end;
end.


Moderiert von user profile iconNarses: Delphi-Tags hinzugefügt


Narses - Mi 11.02.09 19:22

Moin!

@bummi:
a) das haben wir auch hier in der Library [http://www.delphi-library.de/topic_KonsolenKommando+ausfuehren+und+Ergebnis+zurueckliefern_64132.html] ;)
b) warum sollte er mit externen Anwendungen hantieren, wenn man das auch viel einfacher direkt in Delphi machen kann... :nixweiss:

cu
Narses


gizmo - Mi 11.02.09 19:56

Dann kann ich die MD5.exe durch den Papierkorb jagen und mir selber was bauen.
Ich bin begeistert! Besten Dank für die Tipps.
Wenn ich damit auf dem Gesicht lande frage ich hier noch mal nach.
Alles Super! Danke!