Autor Beitrag
SMO
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 120
Erhaltene Danke: 18


D2005 Personal
BeitragVerfasst: Do 28.05.15 15:18 
user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Der TResourceStream-Konstruktor verlangt als letzten Parameter bei Delphi 5
ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1447

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: Do 28.05.15 15:45 
Hallo SMO,
user profile iconSMO hat folgendes geschrieben Zum zitierten Posting springen:
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. :D

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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 28.05.15 17:45 
user profile iconSMO hat folgendes geschrieben Zum zitierten Posting springen:
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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 429
Erhaltene Danke: 107

Win 10
Delphi 6 Prof, Delphi 10.4 Prof
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 120
Erhaltene Danke: 18


D2005 Personal
BeitragVerfasst: Do 28.05.15 19:00 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
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...
ausblenden 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
        // mach was mit r1, r2, r3
      finally
        r3.Free;
      end;
    finally
      r2.Free;
    end;
  finally
    r1.Free;
  end;
end;


... ist gleichwertig mit dem hier ...

ausblenden 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);
    // mach was mit r1, r2, r3
  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