Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Textdatei zur Anzeige bringen (https://www.delphipraxis.net/21357-textdatei-zur-anzeige-bringen.html)

DanielBodensee 1. Mai 2004 15:32


Textdatei zur Anzeige bringen
 
Hallo,

ich muss von meinem Programm aus ein anderes Programm im Hintergrund starten, dass selber eine LOG-Datei schreibt.

Zum einen, wie kann ich mit Delphi3 ein Programm im Hintergrund starten (WinExec soll ja out sein) ohne das es sichtbar wird?

Wie kann ich die Logdatei ständig in einem TMemo anzeigen wenn die Datei schon mal 1,5MB groß werden kann? TScrollBox?

Unter Unix kann ich mir mit tail immer aktuell die neuen Zeilen welche in die LOG-Datei geschrieben werden anzeigen lassen. Kann ich unter Delphi3 gleiches machen bzw eben ein Memofeld mit Scroll-Leisten aktuell versorgen?

Wäre für Eure Tipps sehr dankbar, irgendwie finde ich nicht das richtige in der Hilfe...

Gruss,
Daniel

S2B 1. Mai 2004 15:38

Re: Textdatei zur Anzeige bringen
 
Mit Hier im Forum suchenShellExecute kannst du ein Programm starten. Soviel ich weiß, gibt es einen ShowWindow-Befehl (oder wie das heißt):
Code:
SW_HIDE
Damit müsstest du das Fenster im Hintergrund starten können!

alcaeus 1. Mai 2004 15:48

Re: Textdatei zur Anzeige bringen
 
Zitat:

Zitat von W32 SDK
ShellExecute(

HWND hwnd, // handle to parent window
LPCTSTR lpOperation, // pointer to string that specifies operation to perform
LPCTSTR lpFile, // pointer to filename or folder name string
LPCTSTR lpParameters, // pointer to string that specifies executable-file parameters
LPCTSTR lpDirectory, // pointer to string that specifies default directory
INT nShowCmd // whether file is shown when opened
);

Als ersten Parameter gibst du Application.Handle an
Als zweiten PChar("open")
Als dritten PChar(<Programmpfad)
Als vierten nil, außer wenn du Parameter brauchst
Als fünften PChar(ExtractFilePath(Application.ExeName))
Und als letzten SW_HIDE
Bedenke aber dass der Benutzer das zweite Programm nicht sieht, und folgedessen auch nicht so einfach beenden kannst, deshalb bist du für das Beenden des zweiten Programms zuständig.

DanielBodensee 1. Mai 2004 16:02

Re: Textdatei zur Anzeige bringen
 
Hi,

erst mal vielen Dank für Eure Tips.

Wie aber kann ich das Logfile in meinem Programm über z.Bsp. TMemo so anzeigen, dass auch die weiteren Zeilen die in das LOG-File geschrieben werden aktuell angezeigt werden?

Ich kann es nur so erklären was ich will:
Unter UNIX kann man mit Type wie unter DOS etc eine Textdatei anzeigen lassen. Mit dem Parameter -t oder -tail wird die Datei angezeigt und sobald ein neuer Eintrag hinzukommt, wird auch der gleich angezeigt.

Kann man das auch ohne ständig die Datei schliesen und wieder öffnen zu müßen anzeigen?

Gruss,
Daniel


PS: Beschreibe das evtl etwas umständlich, sind meine ersten Schritte in Delphi 3

S2B 1. Mai 2004 16:05

Re: Textdatei zur Anzeige bringen
 
Vielleicht mit Hier im Forum suchenAssignFile die Zeile in die Datei schreiben und die Zeile auch gleichzeitig ins Memo schreiben?

alcaeus 1. Mai 2004 16:07

Re: Textdatei zur Anzeige bringen
 
Wichtig ist, dass du andere Operationen auf die Datei zulässt. Dies geschieht nach AssignFile mit
Delphi-Quellcode:
FileMode := fmShareDenyNone;
Anschließend musst du die Dateigröße speichern, und in einem Timer überprüfen, ob sich diese geändert hat. Ist dies der Fall, musst du nur noch die letzten Zeilen ausgeben. Ob Seek auch bei Textdateien funktioniert weiß ich allerdings nicht.

Sharky 1. Mai 2004 16:08

Re: Textdatei zur Anzeige bringen
 
Die große Frage ist:
Ist das Programm das die LOG-Datei erzeugt von dir bzw. kanns Du an diesem etwas ändern?

DanielBodensee 1. Mai 2004 16:31

Re: Textdatei zur Anzeige bringen
 
Hallo,

leider wir die LOG-Datei von einem Programm geschrieben, auf das ich keinen Einfluß habe, kann daher leider nichts ändern.

Noch eine andere Frage:
Wenn ich das Programm im Hintergrund gestartet habe, muß ich dieses ja dann auch beenden wenn ich mein Programm schließe. Wie bekomme ich mit, dass das von mir gestartete Programm beendet ist?

Gruss,
Daniel

S2B 1. Mai 2004 16:34

Re: Textdatei zur Anzeige bringen
 
OnClose der Form, oder? :zwinker:

alcaeus 1. Mai 2004 16:36

Re: Textdatei zur Anzeige bringen
 
Zitat:

Zitat von S2B
OnClose der Form, oder? :zwinker:

Er hat gesagt, dass es sich um ein Fremdprogramm handelt, ich glaube nicht dass er da eine OnClose bekommt. Du kannst die eine Prozessliste holen und nachschauen, ob ein Prozess noch läuft. Schau mal in der Suche nach, vor kurzem war hier sowas..
Lies dir das hier durch, da könntest du was finden:
http://www.delphipraxis.net/internal...ct.php?t=24268

S2B 1. Mai 2004 16:38

Re: Textdatei zur Anzeige bringen
 
Oh, hab ich wohl falsch verstanden! :wall:

DanielBodensee 1. Mai 2004 21:40

Re: Textdatei zur Anzeige bringen
 
Hi,

mir ist gerade eingefallen, dass dieses zu startende Programm die Ausgabe ursprünglich auf dem Bildschirm ausgiebt, das LOG-File wird durch eine Umleitung (Pipe?) in die LOG-Datei geschrieben (also durch "programm.exe ergebnis.log")

Könnte man das Programm auch im Hintergrund starten und die Bildschirmausgabe in das Memo hineinschreiben? Das LOG-File kann man ja einfach mitschreiben, so als wenn es eben durch die Pipe erstellt würde.

Wäre das ein gangbarer Weg und hättet Ihr dazu eine Lösung?

Gruss,
Daniel

DanielBodensee 2. Mai 2004 08:43

Re: Textdatei zur Anzeige bringen
 
Guten Morgen,

nachdem ich gestern (oder eher heute so recht früh) noch nach weiteren Möglichkeiten zu meinem Problem gesucht habe, ist mir ein interessanter Artikel ins Auge gesprungen, der die Lösung sein könnte.

Hier wird quasi ein cmd-prozess gestartet (im Beispiel einfaches Dir) und dann über eine Stringlist in ein Memo-Feld übergeben.

Funktioniert erst mal gut bei kleiner Datenmenge, doch bei größerer Menge bleibt das Programm eben so lange stehen, bis die Ausgabe des CMD-Prozesses beendet ist.

Habe dann auf Grundlage dieses Codes versucht, das Memo-Feld direkt bzw sofort zu füllen, was mir aber nicht gelungen ist.

Da ich aber eben noch Anfänger bin, habe ich da auch nicht den driekten Durchblick und wollte Euch fragen, sich das mal anzusehen.

Der Link dazu (hoffe ist so erlaubt): Code

Gruss,
Daniel (der schlaflose :wink: )

alcaeus 2. Mai 2004 08:54

Re: Textdatei zur Anzeige bringen
 
Hier ist es für die Ausgabepipe, für die Fehlerpipe machst du das gleiche:
Delphi-Quellcode:
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;           //Diese Zeile
  Output.LoadFromStream(Stream);  //und diese Zeile
finally
  Stream.Free;
end;
CloseHandle(PipeOutputRead);
Der Code liest alle Daten heraus, und sobald die Eingabe abgebrochen wird, wir alles der Stringlist hinzugefügt. Wir ändern die Reihenfolge ein wenig: die beiden Zeilen, die mit einem Kommentar versehen sind, werden in die Schleife geschoben, das heißt der Code müsste so aussehen:
Delphi-Quellcode:
Stream := TMemoryStream.Create;
try
  while true do begin
    succeed := ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil);
    if not succeed then
      break;
    Stream.Write(Buffer, NumberOfBytesRead);
    Stream.Position := 0;           //Diese Zeile
    Output.LoadFromStream(Stream);  //und diese Zeile
  end;
finally
  Stream.Free;
end;
CloseHandle(PipeOutputRead);
Dadurch werden die Daten vom Stream immer in die StringList geladen, und nicht erst sobald das cmd-Programm fertig ist. Der Algo ist sicher noch optimierungsfähig (nicht immer alles laden sondern nur zusätzliche Daten), aber es ist ein Ansatz.

DanielBodensee 2. Mai 2004 09:27

Re: Textdatei zur Anzeige bringen
 
Hi,

super, musste dann noch das einlesen in die Memobox mit aufnehmen und es hat tatsächlich funktioniert.

Mein Fehler zuvor war, dass ich das einfügen in die MemoBox nicht in der Schleife gemacht habe, Dank Dir sind meine Augen jetzt etwas offener :-D

Eine Frage stellt sich jetzt:
Die MemoBox wird jetzt gefüllt und ich kann über die Scrollbar den Inhalt ansehen. Wie könnte ich eine Art Autoscroll einstellen damit der Inhalt stets nach oben geschoben wird und die unterste Zeile die aktuelle ist?

Ausserdem, wo könnte ich zum optimieren ansetzen, denn bei größer werdender Datenmenge schläft das Programm natürlich jetzt ein, wird ja derzeit immer alles wieder und wieder in TMemo geschrieben.

Gruss,
Daniel

alcaeus 2. Mai 2004 09:31

Re: Textdatei zur Anzeige bringen
 
Bei allen von TCustomEdit abgeleiteten Klassen gibts die Eigenschaften SelStart und SelLength. SelStart gibt den Start des markierten Textes an, und wenn kein Text markiert ist, ist SelStart die Cursorposition, wobei 0 das erste Zeichen darstellt. Also z.B.:
Delphi-Quellcode:
Memo1.SelStart := Length(Memo1.Text)-1;
Memo1.SelLength := 0;

DanielBodensee 2. Mai 2004 12:03

Re: Textdatei zur Anzeige bringen
 
Hallo,

habe mir mal TMemoryStream angeschaut und gesehen, dass es dort ein Size und ein Position gibt. Nun habe ich mir ein label auf mein Form gelegt und gebe beim abarbeiten die Größe des Streams aus.

Da die Größe ja mit den Daten anwächst, dachte ich mir, man könnte ja die Position nach jedem Leseschritt merken und beim nächsten Durchgang wieder setzen, damit nicht der ganze Stream gelesen wird.

Dadurch wird die Anwendung erwartungsgemäß sehr viel schneller (da ja schon gelesene Daten quasi übersprungen werden), doch das ist nicht ganz das erwartete.

Ich vermute mal, dass wenn der Steam bis zum Ende des jeweiligen Schleifendurchgang gelesen wird und dies aber noch nicht das Zeilenende war, schreibe ich mit intems.addstrings den bis dahin gelesenen String in die Liste, die dann beim nächsten einfügen eben eine neue Zeile beginnt.

Dies ist aber so nicht gewollt, denn das Ergebnis sieht eben nicht so gut aus weil die Zeile unterbrochen ist.

Habt Ihr dazu evtl eine Idee? Leider geht ja Readln nicht, denn der würde ja dann lesen bis #10#13 oder so.

Gruss,
Daniel

alcaeus 2. Mai 2004 13:46

Re: Textdatei zur Anzeige bringen
 
probier mal anstatt dem hier:
Delphi-Quellcode:
Stream := TMemoryStream.Create;
try
  while true do begin
    succeed := ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil);
    if not succeed then
      break;
    Stream.Write(Buffer, NumberOfBytesRead);
    Stream.Position := 0;          
    Output.LoadFromStream(Stream);  
  end;
finally
  Stream.Free;
end;
CloseHandle(PipeOutputRead);
das hier zu verwenden:
Delphi-Quellcode:
Output.Clear;
Output.Strings.Add('');
try
  while true do begin
    succeed := ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil);
    if not succeed then
      break;
    Output[0] := Output[0]+Buffer;
  end;
finally
  Stream.Free;
end;
CloseHandle(PipeOutputRead);
So fügst du immer den gerade herausgelesenen Text der Stringlist hinzu...

DanielBodensee 2. Mai 2004 20:47

Re: Textdatei zur Anzeige bringen
 
Hi,

habe jetzt alles so gemacht, nur leider bekomme ich jetzte eine Exception der Klasse EAccessViolation, ausserdem ist die Ausgabe scheinbar nicht mehr Zeilenweise sondern die Angaben erscheinen hintereinander.

Ich habe mal den Code eingefügt, MmAusgabe ist ein TMemo, die Variable Abbruch wird durch ein Button gesetzt. Sobald ich den Ablauf abbreche und die Variable Abbruch auf true setze und darauf dann die Procedure mit exit verlassen will, erscheint die obige Exception.

Scheinbar ist das schon der richtige Weg, es klappt nur nicht mit der Ausgabe (also dem TMemo), welche ja von der Console kommt.

Der Einfachheitshalber (auch wegen der Datenmenge) habe ich ein das Dir mit /s versehen.

Könntet Ihr das mal versuchen und mir helfen?

Gruss,
Daniel


Delphi-Quellcode:
procedure THauptForm.GetConsoleOutput(const Command: String);
var
  StartupInfo: TStartupInfo;
  ProcessInfo: TProcessInformation;
  SecurityAttr: TSecurityAttributes;
  PipeOutputRead: THandle;
  PipeOutputWrite: THandle;
  PipeErrorsRead: THandle;
  PipeErrorsWrite: THandle;
  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
    //Write-Pipes schließen
    CloseHandle(PipeOutputWrite);
    CloseHandle(PipeErrorsWrite);

    //Ausgabe Read-Pipe auslesen
    Abbruch:=false;
    MmAusgabe.Clear;
    MmAusgabe.Lines.Add('');
    try
      while true do begin
        succeed := ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil);
        if not succeed then break;
        MmAusgabe.Lines[0]:=MmAusgabe.Lines[0] + Buffer;
        Application.ProcessMessages;
        if Abbruch then exit;
      end;
    finally
      Stream.Free;
    end;
    CloseHandle(PipeOutputRead);

    //Fehler Read-Pipe auslesen
    try
      while true do begin
        succeed := ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytesRead, nil);
        if not succeed then break;
        MmAusgabe.Lines[0]:=MmAusgabe.Lines[0] + Buffer;
        Application.ProcessMessages;
        if Abbruch then exit;
      end;
    finally
      Stream.Free;
    end;
    CloseHandle(PipeErrorsRead);

    WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
    CloseHandle(ProcessInfo.hProcess);
  end
  else begin
    CloseHandle(PipeOutputRead);
    CloseHandle(PipeOutputWrite);
    CloseHandle(PipeErrorsRead);
    CloseHandle(PipeErrorsWrite);
  end;
end;


procedure THauptForm.BtTestClick(Sender: TObject);
begin
    GetConsoleOutput('cmd /c dir c:\winnt /s');
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:28 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