![]() |
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:
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):
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;
Code:
Allerdings stehen die Prozentangaben alle in einer Zeile, die dann vom Memo irgendwann umgebrochen werden (bei maximaler Stringlänge oder so).
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...... 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 |
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: |
Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
Zitat:
Zitat:
MfG Dalai |
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:
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...
LogForm.LogMemo.Lines.Add(String(Buffer));
|
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:
MfG Dalai |
Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
Zitat:
TDosCommand hingegen bietet dir ein Event für eine neue Zeile an oder schreibt auf Wunsch das ganze gleich direkt in ein Memo. |
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
![]() |
Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
Zitat:
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 |
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:
FConvert ist ein boolsches Attribut, was ich hinzugefügt habe.
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 [...] 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 |
Re: CMD-Ausgabe von chkdsk, wget usw. ordentlich?
Delphi-Quellcode:
Wieso dereferenzierst Du pBuf? OemToChar mag doch nen Pointer haben laut MSDN. Oder ist die Delphi Definition der Funktion mit var erfolgt?
// --- Änderung
if FConvert AND (bread > 0) then OemToChar(pBuf^, pBuf^); // --- Änderung |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:21 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz