Autor |
Beitrag |
SMO
Beiträge: 120
Erhaltene Danke: 18
D2005 Personal
|
Verfasst: Do 28.05.15 15:18
Mathematiker hat folgendes geschrieben : | Der TResourceStream-Konstruktor verlangt als letzten Parameter bei Delphi 5
Delphi-Quelltext 1:
| constructor Create(Instance: THandle; const ResName: string; ResType: PChar); | einen String. |
Ein PChar ist nicht unbedingt ein String.
RT_RCDATA sollte in der Windows-Unit als "MakeIntResource(10)" definiert sein. Das ist nichts anderes als ein Typecast à la "Pointer(10)". Wie von Microsoft definiert.
Ich vermute, dass in deinem Resourcenskript die Font-Datei dann als "RT_RCDATA" deklariert ist, statt als "RCDATA". Letzteres ist der "normale" Typ, welcher der RT_RCDATA Konstante entspricht.
Für diesen Beitrag haben gedankt: Mathematiker
|
|
Mathematiker
Beiträge: 2622
Erhaltene Danke: 1447
Win 7, 8.1, 10
Delphi 5, 7, 10.1
|
Verfasst: Do 28.05.15 15:45
Hallo SMO,
SMO hat folgendes geschrieben : | Ich vermute, dass in deinem Resourcenskript die Font-Datei dann als "RT_RCDATA" deklariert ist, statt als "RCDATA". Letzteres ist der "normale" Typ, welcher der RT_RCDATA Konstante entspricht. |
Sehr schön. Ich habe wieder etwas gelernt.
Ändere ich in der Ressource auf "RCDATA", so funktioniert es mit der Konstanten.
Danke für die Erklärung
Mathematiker
_________________ Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
|
|
jaenicke
Beiträge: 19272
Erhaltene Danke: 1740
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Do 28.05.15 17:45
SMO hat folgendes geschrieben : | Wenn innerhalb des Konstruktors eines Delphi-Objekts eine Exception auftritt, wird automatisch der Destruktor aufgerufen und der Speicher wieder freigegeben. Soll heißen: ja, TResourceStream.Create kann eine Exception werfen, aber es ist unnötig diese abzufangen um ein rs.Free aufzurufen. |
Wenn aber in AddFontMemResourceEx eine Exception auftritt, wird bei deinem Quelltext rs nie freigegeben. Und deshalb waren die try..finally Blöcke sinnvoll...
|
|
mandras
Beiträge: 429
Erhaltene Danke: 107
Win 10
Delphi 6 Prof, Delphi 10.4 Prof
|
Verfasst: Do 28.05.15 17:53
Zum Beitrag von SMO:
das mit der Division durch Null hatte ich extra so gemacht um eine Exception zu erzeugen. Ein raise hätte es auch getan..
Wenn man Deine Erklärung ansetzt (Rückgabewert einer dank Exception abgebrochenen Funktion ist undefiniert) machen meine Beobachtungen alle Sinn. Inclusive der Tatsache, wann der Compiler Maschinencode erzeugt und wann er wegoptimiert (except ./. finally).
Betrachtet man eine Funktion nur für sich wäre der erzeugte Code eben nicht korrekt da bestimmte Zuweisungen wegoptimiert werden.
Berücksichtigt man den Aufrufkontext (wird die Funktion dank Exception abgebrochen, würde ihr Ergebnis auch dann nicht verwendet werden, wenn sie eines liefern würde) stimmt alles wieder.
Also keine Compilerbugs.
Wieder was gelernt.
|
|
SMO
Beiträge: 120
Erhaltene Danke: 18
D2005 Personal
|
Verfasst: Do 28.05.15 19:00
jaenicke hat folgendes geschrieben : | Wenn aber in AddFontMemResourceEx eine Exception auftritt, wird bei deinem Quelltext rs nie freigegeben. Und deshalb waren die try..finally Blöcke sinnvoll... |
Das passiert wie gesagt nicht. AddFontMemResourceEx wirft keine Exceptions zum Aufrufer, auch wenn man total falsche Parameter übergibt. Aber wenn man paranoid ist, kann man natürlich das "rs.Free" in einen eigenen finally-Block machen, oder in den vorhandenen zu FreeLibrary - dann muss man natürlich rs vor dem ersten try-Block mit nil initialisieren.
Das hier...
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| procedure LadeRes1; var r1, r2, r3: TResourceStream; begin r1 := TResourceStream.Create(HInstance, 'resource1', RT_RCDATA); try r2 := TResourceStream.Create(HInstance, 'resource2', RT_RCDATA); try r3 := TResourceStream.Create(HInstance, 'resource3', RT_RCDATA); try finally r3.Free; end; finally r2.Free; end; finally r1.Free; end; end; |
... ist gleichwertig mit dem hier ...
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| procedure LadeRes2; var r1, r2, r3: TResourceStream; begin r1 := nil; r2 := nil; r3 := nil; try r1 := TResourceStream.Create(HInstance, 'resource1', RT_RCDATA); r2 := TResourceStream.Create(HInstance, 'resource2', RT_RCDATA); r3 := TResourceStream.Create(HInstance, 'resource3', RT_RCDATA); finally r3.Free; r2.Free; r1.Free; end; end; |
... wobei ich die zweite Variante für besser lesbar halte.
Der erzeugte Code ist nicht identisch; jedes einzelne "try" produziert Code, der auf dem Stack einen neuen Structured Exception Handling (SEH) Frame erzeugt.
Aber der Endeffekt ist derselbe, die Objekte werden in jedem Fall freigegeben. Die Initialisierung mit nil ist wichtig, da lokale Variablen anfangs "zufällige" Werte enthalten. Nur die Typen mit Compiler Magic (Strings, dynamische Arrays, Interfaces) werden automatisch initialisiert.
Für diesen Beitrag haben gedankt: Martok, Mathematiker
|
|
|