![]() |
Zur Laufzeit, Zeilennummer feststellen
Hallo zusammen,
gibt es die Möglichkeit zur Laufzeit die Zeilennummer im Code auszugeben. Beispiel: 101 102 103 ShowMessage( {Zeilennummer} ); 104 Fenster: 103 Gruß Eppos |
AW: Zur Laufzeit, Zeilennummer feststellen
Ohne großen Aufwand kenne ich nichts außer
![]()
Delphi-Quellcode:
procedure p(const Message, Filename: string; LineNumber: Integer; ErrorAddr: Pointer);
begin ShowMessage( LineNumber.ToString() ); end; procedure TForm19.Button1Click(Sender: TObject); begin System.AssertErrorProc := p; assert(false, 'message'); end; Kannst du ein praktisches Beispiel geben wofür du das brauchst? Geht sicher besser. |
AW: Zur Laufzeit, Zeilennummer feststellen
Ich würde gerne ausgeben, an welcher Stelle ein Fehler auftritt.
|
AW: Zur Laufzeit, Zeilennummer feststellen
|
AW: Zur Laufzeit, Zeilennummer feststellen
Das deckt leider nicht mein internes Fehlerhandling ab. 8-)
|
AW: Zur Laufzeit, Zeilennummer feststellen
Fehler Behandlungs Beispiel:
Delphi-Quellcode:
var
number1, number0 : Integer; begin try number0 := 0; number1 := 1; number1 := number1 div number0; ShowMessage('1 / 0 = '+IntToStr(number1)); except on E : Exception do begin ShowMessage('Exception ClassName = '+E.ClassName); // hier gibt's den ClassName des Verursachers ShowMessage('Exception Nachricht = '+E.Message); // und seine Fehlermeldung end; end; end; Man kann auch auf verschieden Fehler in On Events reagieren, Beispiel:
Delphi-Quellcode:
Für Zeilennummern solltest Du Dich mit
except
On E : EInOutError do ShowMessage('IO Fehler : '+E.Message); On E : EDivByZero do ShowMessage('Division durch NULL : '+E.Message); else ShowMessage('andere Fehler'); end;
Delphi-Quellcode:
und
on e: exception do begin showmessage(e.StackTrace); end;
![]() edit ![]() ![]() |
AW: Zur Laufzeit, Zeilennummer feststellen
Könntest Du Dich etwas ausführlicher äußern?
Eine Exception zeigt im allg. auch die Position im Compilat an, an der es knallt. Mit Hilfe des Debuggers kommt man dann zu der fehlerhaften Sourcecodestelle. Gruß K-H |
AW: Zur Laufzeit, Zeilennummer feststellen
Zitat:
|
AW: Zur Laufzeit, Zeilennummer feststellen
Danke für die Vielzahl von Antworten.
Wir haben ein eigenes Fehlerhandling programmiert. Die Vorgabe war, keine externen Hilfsmittel zuzulassen (madExcept). Fehler zu melden, die nicht systemseitig erzeugt werden, sondern durch andere Fälle entstehen werden bei uns gesammelt und ausgewertet. |
AW: Zur Laufzeit, Zeilennummer feststellen
Im Compilat gibt es keine Zeilennummern mehr.
Bei Assert wird vom Compiler an der Stelle die Zeilennummer einkompilert, aber sowas wie _FILE_ und _LINE_ ala PHP oder anderer Scriptsprachen gibt es leider nicht. Alle anderen Varianten nehmen die Debuginfos, bzw. die MAP-Datei, welche der Compiler/Linker erstellen kann, und lesen/suchen daraus die naheliegenste Zeile zur entsprechenden Codeposition. Wenn keine Fremdkomponenten genommen werden sollen, damm müsst ihr eben das alles selber machen. Eurekalog und vermutlich auch madExcept nehmen die MAP-Datei, holen sich diese Infos da raus und hängen sie in einem eigenen Format als Ressource an das Compilat an. |
AW: Zur Laufzeit, Zeilennummer feststellen
Programm mit ausführlicher MAP-Datei kompilieren.
Fehleradresse in dieser suchen. Vor der Fehleradresse steht die Zeilennummer. Die erste Zeile mit einer Quelltextangabe (Line numbers for ...), vor der gefundenen Fehleradresse, gibt die Quelltextdatei an, in welcher der Fehler auftrat. Damit hat man dann die Quelltextdatei, Fehleradresse und die Zeilennummer des fehlerverursachenden Quelltextes. Die Fehlermeldung entnimmt man direkt der Exception. Das sollte mit wenig Aufwand in 'nem halben Arbeitstag umzusetzen sein. Und wenn man schon ein eigenes Fehlerhandling hat, kann man das entsprechend um eine Methode erweitern, die die Fehleradresse annimmt, die MAP-Datei entsprechend durchsucht und als Ergebnis den Namen der Quelltextdatei, zuzüglich der Zeilennummer, liefert. Es sind prinzipiell alle Informationen bereits vorhanden, man muss sie nur nutzen. |
AW: Zur Laufzeit, Zeilennummer feststellen
Wenn ihr JCL nutzt, kann das hier helfen.
Das Projekt wird im Debug-Modus etwa 100 KB größer. Im Release bei mir 140 KB. Also nicht die Welt. ![]() |
AW: Zur Laufzeit, Zeilennummer feststellen
Aber Zeilennummern aus einer Objekt orientierten Programmiersprache heraus zu holen ist doch eh ein falscher Ansatz.
Beispiel Procedure X ruft Function Y auf die wiederum einen externen Call Z macht, welche Zeilennummer soll angezeigt werden bei Fehler? Das was in X falsch war oder in Y oder gar Z ??? Ich hoffe das ich meine Sicht verständlich darlege. Besser bei Klassennamen und deren Message bleiben, da sollte dann sofort klar sein wo & warum Fehler YXZ entstand. Alternativ kannst Du Dir ja einen Globalen Counter reinbauen und dem bei jeder Neuen Code Zeile dessen Zeilennummer voranstellen, noch primitiver gehts kaum aber Du bist am Ziel. Beispiel
Delphi-Quellcode:
0 - var Zeile : Cardinal;
1 - procedure x; 2 - begin 3 - Zeile := 3; MachWas; 4 - Zeile := 4; MachMehr; 5 - end; |
AW: Zur Laufzeit, Zeilennummer feststellen
Wirklich aussagekräftig für den Entwickler ist eigentlich nur die Kombination aus Fehlerklasse, Fehlermeldung und Callstack. Das wäre schon mal eine gute Momentaufnahme der Situation, die man auch im Debugger sehen könnte, wenn der Fehler dort auftreten würde.
Das einzige was dann noch fehlt, wäre der Zustand des Programms zum Fehlerzeitpunkt (also die Variableninhalte), aber das würde wohl eindeutig den Rahmen jedweder Fehlermeldung oder Logdatei sprengen. |
AW: Zur Laufzeit, Zeilennummer feststellen
Hallo,
ich verwende zum Ermitteln der Zeilennummer die JCL, da ich in meinem Programmen häufig Fehler in eine Logdatei reinschreibe, der coole Tipp kam von diesem Forum ![]() Meine Logfunktion schaut in etwa so aus:
Delphi-Quellcode:
Meine Logdatei schaut dann so aus, wobei nach dem Unitnamen die Zeilennummer ist.
implementation
uses JCLDebug; procedure Log(S: String); var msg: String; Year, Month, Day, Hour, Min, Sec, MSec, H: Word; begin DecodeTime(now, Hour, Min, Sec, MSec); msg := Format('%.2d:%.2d:%.2d.%.3d %s:%u (%s) "%s"',[Hour,Min,Sec,MSec,FileByLevel(1), LineByLevel(1), ProcByLevel(1), S]); // hier schreibe ich die Fehlermeldung in eine Datei oder lasse es im Programm ausgeben //...... end;
Code:
Die JCL Debugfunktionenn können natürlich viel mehr wie z.B. Stacktrace ausgeben usw. siehe den alten Beitrag
23:03:53.262 Unit1.pas:2787 (TForm1.Update_CmB_Printer) "Fehler! Der Druckername "TM88IV" konnte nicht unter den installierten Druckern gefunden werden."
23:03:53.264 Unit1.pas:2794 (TForm1.Update_CmB_Printer) "Der aktive Druckername wird auf "TMU290" gesetzt." 23:03:53.266 Unit1.pas:536 (TForm1.FillPrinterDataToGui) "Current printer model "TM88IV" match with "C:\ProgramData\XXX\XXX\PrinterInfo.xml" 23:03:53.268 PrinterLib.pas:1104 (PrinterXmlGetStandardFeedsources) "In C:\ProgramData\XXX\XXX\PrinterInfo.xml <feedsource name="01"> node no <borderless> found." 23:03:53.270 Unit1.pas:550 (TForm1.FillPrinterDataToGui) "C:\Users\abc\AppData\Roaming\XXX\MediaNotVisible found" 23:03:53.272 Unit1.pas:1172 (TForm1.LoadPresets) "---TForm1.LoadPresets---" 23:03:53.273 Unit1.pas:1173 (TForm1.LoadPresets) "TForm1.LoadPresets: Suche alle Presets in C:\Users\abc\AppData\Roaming\XXX\PRESET\*.epl mit dem Druckermodel TM88IV" 23:03:53.282 Unit1.pas:1231 (TForm1.LoadPresets) "INVALID: C:\Users\abc\AppData\Roaming\XXX\PRESET\14_20150730_190038.epl" ![]() Lg, jus |
AW: Zur Laufzeit, Zeilennummer feststellen
Zitat:
Könntest du eventuell ProcByLevel erklären? Wenn Prozedur A einen Fehler hat und Prozedur B_Log aufruft und letztere wieder ProcByLevel(0), dann habe ich im Log den Namen B_log stehen. Heißt ProcByLevel(1) nur "gehe eine Prozedur weiter zurück? Wenn ja, was, wenn ich X Prozeduren habe die sich hintereinander aufrufen? |
AW: Zur Laufzeit, Zeilennummer feststellen
Zitat:
|
AW: Zur Laufzeit, Zeilennummer feststellen
Hat das irgendwelche Nachteile bezüglich der Sicherheit des fertigen Kompilats?
FileByLevel, LineByLevel, ProcByLevel. Was aber wenn ich nicht wie weit ich zurück muss? Ist mir mir gerade nicht so, aber für die Zukunft wäre das interessant. Hier nur ein Beispiel. In meiner Mainform ist eine Prozedur AppExceptionHandler. Die ruft eine Prozedur doLog in einer Log-Unit auf und doLog ruft letzten Endes die Prozedur auf, die das Log schreibt. Gehe ich 3x zurück, lande ich bei Vcl.Forms.pas. |
AW: Zur Laufzeit, Zeilennummer feststellen
Zitat:
Die Funktion wird auch von Anderen aufgerufen, wobei Einige dafür auch nur interne Loggingfunktionen sind. Ich gehe den Stacktrace nun einfach so lange rückwärts, bis ich einen "mir unbekannten" Funktionsnamen finde und dieser kommt ins Log. |
AW: Zur Laufzeit, Zeilennummer feststellen
Gerade mal mit einer Schleife und ProcByLevel nachgebaut.
Zitat:
Zitat:
|
AW: Zur Laufzeit, Zeilennummer feststellen
Application.HandleException ist da, wo es bei dir schon raus ist.
Delphi-Quellcode:
System.ExceptObject ... das entspricht dem on E: Exception im EXCEPT-Block
function HandleMessage;
try CallWindowsEvents; // hier hat es in einer unterfunktion geknallt except HandleException; // aber hier ist dein HandleException-Event drin, also ist ein Stacktrace von HIER aus sinnlos end System.ExceptAddr ... hier hatte es geknallt System.ReturnAddress ... mein Caller (bzw. der Befehl danach) Schau dir mal die Exception-Klasse genau an. Da kann man sich für die Stacktrace-Behandlung registrieren. Also während die Exception ausgelöst wird ... da kannst du den Stacktrace auslesen und innerhalb des aktuellen Exception-Objektes speichern. (Delphi bietet nur die Zugangspunkte, aber ohne eigene Funktion) Und in der anschließenden Exceptionbehandlung kannst du über das Exception-Objekt an dessen Stacktrace wieder rankommen. |
AW: Zur Laufzeit, Zeilennummer feststellen
Wie loggt ihr denn dann Fehler wenn nicht mit einer Exception-Prozedur? Ich kann schlecht überall try-except hinschreiben.
|
AW: Zur Laufzeit, Zeilennummer feststellen
Mit Try-Except und alles was wir vergessen haben über TApplicationEvents.OnException (nicht direkt an Application)
|
AW: Zur Laufzeit, Zeilennummer feststellen
Also doch try-except. Ich dachten immer man soll sauber funktionierenden Code schreiben und try-except sei nur eine Notlösung.
Zitat:
|
AW: Zur Laufzeit, Zeilennummer feststellen
Hier haben wir ein in Jahrzehnten gewachsenes Programm aus mehreren EXEn, vielen DLLs und massig BPLs.
Das wurde von Turbo Pascal (DOS) über Delphi 7 (Windows), aktuell Delphi XE und parallel neu für 10.x . 533 vorwiegend eigene Units, ~60 Projekte (EXE/DLL), ~30 Packages und vielen Fremdkomponenten. Wo mehrere Leute drin rumpfuschen .... mal ehrlich, erwartest du wirklich, dass es da alles reibungslos funktioniert? Neben Eurekalog sind da noch ein paar eigene Exceptionbehandlungen mit Erweitern der Exception-Message, da Eurekalog auch nicht immer den Stacktrace ausreichend aufbauen kann. |
AW: Zur Laufzeit, Zeilennummer feststellen
Hatten dies auch schon, das in unseren Exe beim Kunden AVs wie "Access violation at address 005CDF76 in module 'DummyProject. exe'. Read address 00000000." aufgetreten. Hat dann immer jeder gesagt, weis nicht wo der Fehler liegt. Bin dann hin gegangen und lies die Exe mit MAP Files kompilieren. Passend zur Exe Version wurde die entsprechende MAP Datei gesichert. Verteilt an den Kunden wurde nur die Exe.
Hat jetzt ein Kunde eine AV, kann ich mit einem selbst geschriebenen Programm, Zeilennummer der Exception filtern. Das Programm hab ich unter Github ![]() Ein Aufruf von "NathanMapFile.exe -MapFilename:.\DummyProject.map -CrashAddress:$005CDF76" ergibt dann: Offset: 6 Codeline: 34 Startaddress from Module: $001CCCA0 Name of procedure from address: Unit1.TForm1.Button1Click Sourcename from address: Unit1.pas Voraussetzung ist, zur Exe eine passende MAP Datei. Es ist dann auch keine IDE nötig. Vielleicht hilft dir das Programm was. |
AW: Zur Laufzeit, Zeilennummer feststellen
Hallo Nathan, verstehe ich das richtig, ich binde in meinem Projekt keinen Code von Dir ein sondern kompiliere es mit .MAP Datei Erzeugung, Kunde bekommt .exe, ich behalte .MAP.
Nun verwende ich Dein Tool wie Du es beschrieben hast und fertig? Falls das der Fall ist, könntest Du eventuell auch ein binary bereitstellen? JCL wollte ich nicht installieren um dein Tool kompilieren zu können um JCL danach gleich wieder los zu werden. |
AW: Zur Laufzeit, Zeilennummer feststellen
Funktioniert genau wie Du sagst. Musst kein Code von mir einbinden. Nur deine Anwendung mit MAP Files erzeugen. Die MAP Files liefere ich nicht aus, da sonst die Update zu groß werden. Halten aber für jeder Exe Version welche veröffentlicht wird, das entsprechende MAP File vor. Tritt dann beim Kunden eine unerwartete AV auf, kann ich meistens den Fehler genauer einschränken und muss nicht hoffen, das der Fehler reproduzierbar ist.
Ist halt leider nur eine Konsolenanwendung. Bindary für Win32 liegen auf GutHub unter ![]() |
AW: Zur Laufzeit, Zeilennummer feststellen
Vielen Dankeschön für prompte Antwort Nathan!
Ja da hätte ich auch darauf kommen können mal ins \bin\ zu gehen, tut mir leid dafür. Ich hab nur "clone or download" beim ersten mal geklickert. Ich habe es gerade mit einer TestApp die bewusst Fehler erzeugt ausprobiert. Resultat = It works! Ich bin begeistert und teste Garantiert noch diese oder jene Fehler aus um zu schauen was dein Tool darüber sagen kann. Das würde mich von MadExcept befreien, was ja auch ein ganz schöner Brocken ist. Mein Empfinden nach Ersten Test = Ich finde es Klasse! Console oder GUI ist mir in diesem Fall mehr als egal. |
AW: Zur Laufzeit, Zeilennummer feststellen
Nur die .map-Files zu verwenden kann manchmal helfen, aber was genau hilft es Dir, wenn Fehleradresse + .map-File Dir dann sagen, dass der Fehler in StrToInt etwa liegt? Doch nur, dass irgendwo im gesamten Programm ein String nicht ordentlich in eine Zahl umgewandelt werden kann.
Deshalb wurde weiter oben ja schon mehrfach erwähnt, dass erst Callstacks wirklich helfen - nur so kommst Du auch an den Kontext! Und den callstack ordentlich herauszufinden ist halt eine Herausforderung, weswegen madExcept, JclDebug, EurekaLog etc. erprobte Erleichterungen sind. |
AW: Zur Laufzeit, Zeilennummer feststellen
Zitat:
|
AW: Zur Laufzeit, Zeilennummer feststellen
Ich habe zugegeben wenig Erfahrungen mit JclDebug, warum sollt man JclCreateStackList nicht in eigenem Handler verwenden können?
Bin großer madExcept-Fan noch aus aktiven Delphi-Zeiten, unter Lazarus bin ich schon verwöhnt, weil GetStackTrace schon drin ist. |
AW: Zur Laufzeit, Zeilennummer feststellen
Ich schrieb ja auch nicht das es DIE Universal Lösung für jedermann ist, nach vorab Test = für meine Zwecke passt's.
|
AW: Zur Laufzeit, Zeilennummer feststellen
Ich kenne beide, finde aber madExcept deutlich besser.
|
AW: Zur Laufzeit, Zeilennummer feststellen
Kann man madExcept kostenlos verwenden, wenn man keinen Gewinn mit dem eigenen Programm erwirtschaftet?
Kenne madExcept jetzt nicht. Aber bei Google sehe ich viele Bilder mit so einem madExcept Fenster wo dutzende Informationen zum Fehler stehen. Kann man sich den Fehler nicht als String beschaffen und in ein eigenes Log schreiben? |
AW: Zur Laufzeit, Zeilennummer feststellen
kostenlos? Schon gegoogelt? ;-)
Statt einem Fenster kann man das sicher auch in ein Log schreiben. M.W. macht das EurekaLog auch so. |
AW: Zur Laufzeit, Zeilennummer feststellen
![]() Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:03 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 by Thomas Breitkreuz