Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi CMD-Ausgabe von chkdsk, wget usw. ordentlich? (https://www.delphipraxis.net/134920-cmd-ausgabe-von-chkdsk-wget-usw-ordentlich.html)

Dalai 1. Jun 2009 17:00


CMD-Ausgabe von chkdsk, wget usw. ordentlich?
 
Hallo Forum,

bitte nicht hauen, wenn ich das falsche Unterforum erwischt haben sollte, denn wie ihr seht, schreibe ich zum ersten Mal hier in der DP :). Ich fand dies das passendste Unterforum.

Ich weiß, dass DOS-Ausgaben usw. schon mehrfach behandelt wurden, aber ich habe ein spezielleres Problem.

Ich habe eine Klasse TLaunch, die versch. Eigenschaften und VCL-Objekte (z.B. einen Button) beinhaltet. Beim Klick auf diesen Button wird der in den Eigenschaften des Objekts gespeicherte Befehl ausgeführt, und zwar unter Verwendung dieser Methode:
Delphi-Quellcode:
procedure TMainForm.LaunchClick(Sender: TObject);
const BufSize = 1024;
var
    // Ausführung mit Capture
    SA: TSecurityAttributes;
    SI: TStartupInfo;
    PI: TProcessInformation;
    StdOutPipeRead, StdOutPipeWrite: THandle;
    WasOK: Boolean;
    Buffer: array[0..BufSize] of Char;
    BytesRead: Cardinal;
begin
    obj:= (Sender as TLaunch);
    LogForm.LogMemo.Clear;
    LogForm.CloseBtn.Enabled:= False;
    LogForm.MyShowModal;
    with SA do
    begin
        nLength:= SizeOf(SA);
        bInheritHandle:= True;
        lpSecurityDescriptor:= nil;
    end;
    try
        CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
        Application.ProcessMessages;
        with SI do
        begin
            FillChar(SI, SizeOf(SI), 0);
            cb:= SizeOf(SI);
            dwFlags:= STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
            wShowWindow:= SW_HIDE;
            hStdInput:= GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
            hStdOutput:= StdOutPipeWrite;
            hStdError:= StdOutPipeWrite;
        end;
        WasOK:= CreateProcess(nil, PChar(obj.ExecFile + ' ' + obj.ExecParams),
                           nil, nil, True, 0, nil,
                           PChar(obj.ExecWorkDir),
                           SI, PI);
        CloseHandle(StdOutPipeWrite);
        if WasOK then
          try
            Application.ProcessMessages;
            repeat
                Application.ProcessMessages;
                WasOK:= ReadFile(StdOutPipeRead, Buffer, Pred(BufSize), BytesRead, nil);
                if BytesRead > 0 then
                begin
                    Buffer[BytesRead]:= #0;
                    OemToChar(Buffer, Buffer);
                    LogForm.LogMemo.Text:= LogForm.LogMemo.Text + String(Buffer);
                end;
                Sleep(50);
            until not WasOK or (BytesRead = 0);
            WaitForSingleObject(PI.hProcess, INFINITE);
          finally
            CloseHandle(PI.hThread);
            CloseHandle(PI.hProcess);
          end;
    finally
        CloseHandle(StdOutPipeRead);
        //CloseHandle(StdOutPipeWrite);
    end;
    LogForm.CloseBtn.Enabled:= True;
    LogForm.CloseBtn.SetFocus;
end;
Die Ausgabe wird auch wunderbar im Memo angezeigt, und das auch schön "in Echtzeit", also nicht erst nach Ende des Programms. Nun zum Problem: Programme, die Ausgaben in derselben Zeile erzeugen (chkdsk, wget, freshclam), generieren dann derartigen Output (gekürzt):
Code:
Der Typ des Dateisystems ist FAT32.
Datenträger SYSTEM erstellt 29.08.2006 00:34
Datenträgernummer: 44F3-8B85
Dateien und Ordner werden überprüft...
0 Prozent durchgeführt.
3 Prozent durchgeführt..
4 Prozent durchgeführt...
5 Prozent durchgeführt....
6 Prozent durchgeführt.....
7 Prozent durchgeführt......
8 Prozent durchgeführt.
9 Prozent durchgeführt..
10 Prozent durchgeführt...
11 Prozent durchgeführt....
12 Prozent durchgeführt.....
13 Prozent durchgeführt......
14 Prozent durchgeführt.
15 Prozent durchgeführt..
16 Prozent durchgeführt...
17 Prozent durchgeführt....
18 Prozent durchgeführt.....
19 Prozent durchgeführt......
Allerdings stehen die Prozentangaben alle in einer Zeile, die dann vom Memo irgendwann umgebrochen werden (bei maximaler Stringlänge oder so).

Hat jemand eine Idee, wie ich wirklich nur die Zeilen bekomme, die man auch sieht, wenn man die Befehle in der CMD ausführen würde?

Danke im Voraus für Hilfe :)

MfG Dalai

jaenicke 1. Jun 2009 17:07

Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
 
Du meinst, dass das in der selben Zeile aktualisiert wird?

Das wirst du manuell machen müssen, weil diese Positionierungsbefehle nicht mit angefangen werden. Ich weiß nicht, ob man das auch richtig hinbekommt. :nixweiss:

Dalai 1. Jun 2009 17:17

Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
 
Zitat:

Zitat von jaenicke
Du meinst, dass das in der selben Zeile aktualisiert wird?

So weit muss es nicht zwingend gehen. Es würde mir (vorerst) genügen, wenn die Ausgaben wie oben sind (alles untereinander) statt alles in derselben Zeile...

Zitat:

Zitat von jaenicke
Das wirst du manuell machen müssen, weil diese Positionierungsbefehle nicht mit angefangen werden.

Hast du eine Idee, wie ich das machen könnte? OK, eine Suche nach Chr(13) und/oder Chr(10) kann helfen, aber ob das genügt? Denn was ist, wenn die Zeichen mitten im String gefunden werden?

MfG Dalai

jaenicke 1. Jun 2009 17:21

Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
 
Ach jetzt verstehe ich. Ja, warum legst du es denn einfach hintereinander in das Memo, wenn du das gar nicht willst? Dann füge es doch in eine neue Zeile hinzu.
Delphi-Quellcode:
LogForm.LogMemo.Lines.Add(String(Buffer));
Besser wäre aber vermutlich einfach eine Komponente wie TDosCommand, dann musst du nicht die Ausgabe ins Memo in die Logik der Ausführung des Befehls bringen...

Dalai 1. Jun 2009 17:34

Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
 
Lines.Add() ist zwar schön, aber das erzeugt einen noch viel zerrupfteren Output. Wenn ich das Sleep(50) komplett rausnehme, werden auch einzelne Zeichen, die der Befehl ausgibt, auf eine neue Zeile geschrieben. Reduziere ich nur die Schlafzeit, landen trotzdem noch Zeilen hintereinander...

Zitat:

Zitat von jaenicke
Besser wäre aber vermutlich einfach eine Komponente wie TDosCommand

Darüber bin ich auch schon gestolpert. Ob das was für den Fall geeignet ist, weiß ich noch nicht, werde ich aber testen.

Zitat:

Zitat von jaenicke
dann musst du nicht die Ausgabe ins Memo in die Logik der Ausführung des Befehls bringen...

Das ist egal, weil das alles der Ereignisbehandlung des Klicks auf den Button dient.

MfG Dalai

jaenicke 1. Jun 2009 17:36

Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
 
Zitat:

Zitat von Dalai
Lines.Add() ist zwar schön, aber das erzeugt einen noch viel zerrupfteren Output.

Ja, stimmt, weil das eben nicht bis zum Zeilenende wartet. Was bei dem Quelltext auch egal ist, weil der für die Auswertung am Ende gedacht war.

TDosCommand hingegen bietet dir ein Event für eine neue Zeile an oder schreibt auf Wunsch das ganze gleich direkt in ein Memo.

Apollonius 1. Jun 2009 17:44

Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
 
Ich habe arge Zweifel, ob das mit dem aktuellen Ansatz überhaupt geht. Vermutlich verwenden die Programme die "low-level" Konsolenfunktionen, die ziemlich schwierig abzufangen sind. Da müsstest du dich mal einsehen, wie man MSDN-Library durchsuchenReadConsoleOutput verwendet.

Dalai 1. Jun 2009 18:44

Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
 
Zitat:

Zitat von Apollonius
Ich habe arge Zweifel, ob das mit dem aktuellen Ansatz überhaupt geht.

Das habe ich auch befürchtet.

TDosCommand habe ich mir angeschaut und für brauchbar befunden. Ich habe den Klassen TDosThread und TDosCommand noch 2 weitere Attribute hinzugefügt: FConvert für die Konvertierung nach ANSI und FWorkDir zum Setzen des Arbeitsverzeichnisses, denn manche Programme brauchen das.

Das Ergebnis ist ein schicker Output mit untereinanderliegenden Zeilen (so wie im ersten Post zu sehen) :). Lustiger Nebeneffekt: chkdsk funktioniert jetzt auch auf meinem Hostsystem, was bei meiner Variante nicht der Fall war :lol:. Keine Ahnung, wo das Problem war, auf anderen Rechnern wurde die Ausgabe problemlos abgefangen, nur auf dem einen nicht.

Das ReadConsoleOutput sieht mir zu kompliziert aus, und ich denke, mit dem jetzigen Stand kann ich ganz gut leben.

Danke für die schnelle Hilfe!

MfG Dalai

Dalai 2. Jun 2009 00:15

Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
 
Ich hoffe nochmals auf eure Hilfe :).

Meine Änderung bzgl. Konvertierung in ANSI tut nicht so, wie ich das hoffte :(. In der Methode TDosThread.FExecute habe ich folgende Änderung vorgenommen (durch Kommentar markiert):
Delphi-Quellcode:
if (bread <> 0) then begin
  if (iBufSize < avail) then begin // If BufferSize too small then rezize
    iBufSize := avail;
    ReallocMem(pBuf, iBufSize);
  end;
  FillChar(pBuf^, iBufSize, #0); //empty the buffer
  ReadFile(read_stdout, pBuf^, iBufSize, bread, nil); //read the stdout pipe

  // --- Änderung
  if FConvert AND (bread > 0) then
      OemToChar(pBuf^, pBuf^);
  // --- Änderung

  Str := Last; //take the begin of the line (if exists)
  i := 0;
  while ((i < bread) and not (Terminated)) do begin
    case pBuf^[i] of
[...]
FConvert ist ein boolsches Attribut, was ich hinzugefügt habe.
Ein Rechner hat damit allerdings ein Problem und er beendet nicht nur das ausgeführte Konsolenprogramm sondern auch das Delphi-Prog sang- und klanglos. Meine Vermutung ist, dass die Variable pBuf^ nicht mit #0 abgeschlossen ist (in bestimmten Situationen) und OemToChar() deswegen ins Schlingern kommt.

Wie löse ich das mit möglichst wenig (Konvertierungs-)Aufwand?

MfG Dalai

Fridolin Walther 2. Jun 2009 01:13

Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
 
Delphi-Quellcode:
  // --- Änderung
  if FConvert AND (bread > 0) then
      OemToChar(pBuf^, pBuf^);
  // --- Änderung
Wieso dereferenzierst Du pBuf? OemToChar mag doch nen Pointer haben laut MSDN. Oder ist die Delphi Definition der Funktion mit var erfolgt?


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:25 Uhr.
Seite 1 von 2  1 2      

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