Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Seltsames Verhalten der Destruktoren (https://www.delphipraxis.net/194604-seltsames-verhalten-der-destruktoren.html)

Delbor 12. Dez 2017 11:43

Delphi-Version: XE8

Seltsames Verhalten der Destruktoren
 
Hi zusammen

In meiner gegenwärtigen Testanwendung - SynpdfTestProject - tritt plötzlich ein seltsames verhalten der Destuktoren auf. Ich muss allerdings zugeben, ich hab das erst jetzt, bei Auftreten des Fehlers, gecheckt.
Wenn ich die Anwendung beende, geschieht folgendes in der gezeigten Reiheenfolge:
Delphi-Quellcode:
procedure TSynpdfMain.FormDestroy(Sender: TObject);
begin
  Self.WriteReportFile;
  FReportList.Free;
end;
WriteReportFile schreibt den Inhalt der Reportliste im eine Datei. Da diese das jeweilige Datum und die Zeit im Namen trägt, wird sie jedesmal neu angelegt, und es tritt eine Exception (im Debugmodus) auf.. Eine normale 'Fehlermeldung' die schell weggeklickt ist.

Seit neuestem (heute) erhalte ich aber eine neue AV, und zwar hier:
Delphi-Quellcode:
destructor TPDFiumFrame.Destroy;
begin
  _Document := 0;
  FPages.Free;
  PDFPageClass.Free;
  FReportList.Free;
  inherited;
end;
Die einzige Änderung ist die Zeile mit der Freigabe der PDFPageClass, die ich vor Tagen schon hinzugefügt habe und die nie zu Problemen geführt hat. Ausgelöst wird der Fehler schon in der ersten Zeile bei

Delphi-Quellcode:
_Document := 0;

Der Vollständigkeit halber hier auch noch die beiden Constructoren:

Delphi-Quellcode:
procedure TSynpdfMain.FormCreate(Sender: TObject);
begin
  FReportList := TStringlist.Create;
  FReportList.Sorted := False;
  FReportList.Add('________________________________________');
  FReportList.Add('procedure TSynpdfMain.FormCreate;');
  FReportList.Add('________________________________________');
end;
und
Delphi-Quellcode:
constructor TPDFiumFrame.Create(AOwner: TComponent);
begin
{$IFDEF TRACK_EVENTS}
  AllocConsole;
{$ENDIF}
  inherited;
  ControlStyle := ControlStyle + [csOpaque];
  FZoom := 100;
  FPageIndex := -1;
  PDFPageClass := TPDFPageClass.Create; //<== meine zweite Änderung
  FSelBmp := TBitmap.Create;
  FSelBmp.Canvas.Brush.Color := RGB(50, 142, 254);
  FSelBmp.SetSize(100, 50);
  FPages := TList.Create;
  FReportList := TStringlist.Create; //<== meine erste Änderung
  FReportList.Sorted := False;
  FGetPageAt := 0;
  try
    FPDF_InitLibrary;
  except
    FStatus := TLabel.Create(Self);
    FStatus.Align := alClient;
    FStatus.Parent := Self;
    FStatus.Alignment := taCenter;
    FStatus.Layout := tlCenter;
    FStatus.Caption := sUnableToLoadPDFium;
  end;
end;
Weshalb jetzt plötzlich dieses Verhalten? In meiner Anwendung gibt es scon seit Wochen zwei Frameinstanzen, die jede vom Basisframe erbt und die beide von der Mainform zerstört wurden. Und damit auch ihr _Ducument - Handle (Das Handle des PDF-Dokumentes).

Gerade getestet und ebenso falsch:

Delphi-Quellcode:
  if _Document > 0 then
    _Document := 0;
Gruss
Delbor

Delphi.Narium 12. Dez 2017 11:52

AW: Seltsames Verhalten der Destruktoren
 
Wenn im Programmablauf TPDFiumFrame.Destroy vor TSynpdfMain.FormDestroy aufgerufen wird, existiert FReportList im FormDestroy nicht mehr und damit kann Self.WriteReportFile auch nicht mehr auf FReportList zugreifen, da ja bereits im TPDFiumFrame.Destroy freigegeben.

Ausserdem wird FReportList in TPDFiumFrame.Destroy und TSynpdfMain.FormDestroy freigegeben. Warum?

himitsu 12. Dez 2017 12:02

AW: Seltsames Verhalten der Destruktoren
 
Form.OnDestroy wurde "früher" im Inherited des Destructor ausgeführt.
> Form.OldCreateOrder=True oder ganz alten Delphis

Form.OnDestroy wird "aktuell" im BeforeDestruction ausgeführt.
> Form.OldCreateOrder=False

Beim Upgrade alter Formulare in neues Delphi steht dieses Property auf True.
Bei neu erstellten Formularen im neuen Delphi steht dieses Property auf False.

PS: Das Selbe gilt auch für OnCreate der Forms, also früher im Constructor und nun im AfterConstruction.


Fazit: Stell OldCreateOrder auf False (sollte im XE8 schon lange drin sein) und pass auf die Aufrufreihenfolge der Events aus.
> neu/aktuell : Create > OnCreate > ... > OnDestroy > Destroy
> früher : Create > ... > Destroy - und da dann jeweils im Inherited das OnCreate und OnDestroy, also vor oder nach dem eigenem Code
>> bei mir also fast immer OnCreate > Create > ... > Destroy > OnDestroy - da ich normalter Weise beim Erstellen das Inherited am Anfang und beim Freigeben am Ende stehen hab



"Doppelt" freigeben ist kein Problem, wenn man es richtig macht.
> Delphi-Referenz durchsuchenFreeAndNil

Aber grundsätzlich sollte man etwas auch dort freigeben, wo es auch erstellt wurde.
OnCreate > OnDesoroy
Constructor > Destructor

DeddyH 12. Dez 2017 12:04

AW: Seltsames Verhalten der Destruktoren
 
Außerdem sind das (hoffentlich) 2 verschiedene Instanzen, einmal ein Feld des Frames und einmal des Formulars.

Delbor 12. Dez 2017 12:15

AW: Seltsames Verhalten der Destruktoren
 
Hi Delphi.Narium

Zitat:

Wenn im Programmablauf TPDFiumFrame.Destroy vor TSynpdfMain.FormDestroy...
Es ist ja eben gerade umgekehrt. Es ist auch nicht die Liste, die die AV auslöst.

TPDFiumFrame.Destroy will das Dokumentenhandle auf 0 setzen. Da dieses aber schon mit den Frameinstanzen der Mainform zerstört wurde, gibts das nicht mehr - und das gibteine AV.

Zitat:

Ausserdem wird FReportList in TPDFiumFrame.Destroy und TSynpdfMain.FormDestroy freigegeben. Warum?
Anfänglich hatte ich diese Liste im Frame deklariert - dieser ist Opensource und stammt nicht von mir, und so wollte ich mir über die Abläufe klar werden.
Schliesslich deklarierte ich die Liste auch in der Mainform, um die Zusammenhänge Mainform.Frameinstanzen und Basisframe zu dokumentieren. Die Einträge des Basisframes erfolgen nun immer in die Liste der Mainform. Das Entfernen der Deklaration etc. aus dem Frame ging dabei schlicht vergessen.

Gruss
Delbor

Delbor 12. Dez 2017 12:38

AW: Seltsames Verhalten der Destruktoren
 
Hi zusammen

@DeddyH:
Zitat:

Außerdem sind das (hoffentlich) 2 verschiedene Instanzen, einmal ein Feld des Frames und einmal des Formulars.
Falls du die Reportliste meinst: ja, sind sie.

@ himitsu
Der Frame verfügt zumindest im OI über kein Property 'OLdCreateOrder', und dasjenige der Form steht auf false.

Zitat:

Aber grundsätzlich sollte man etwas auch dort freigeben, wo es auch erstellt wurde.
OnCreate > OnDesoroy
Constructor > Destructor
Wenn vorhanden, bzw. wenn es Sinn macht, benutze ich immer das OnCreate-Event, um etwas zu initialisieren. Frames haben kein (Published)-Event OnCreate, wesshalb hier sowas immer im Costructor/Destructor geschieht.
Wie oben schon erwähnt, ist der PDFiumFrame Opensource, und ich bin nicht sein Autor. Bis auf die Erwähnten Änderungen ist der Code also Original.

Gruss
Delbor

Ghostwalker 12. Dez 2017 12:58

AW: Seltsames Verhalten der Destruktoren
 
Wenn ich das richtig Verstehe, hast du eine Form sowie zwei Frames. Desweiteren eine globale Instanz eines Dokumentes.

Wenn das so richtig ist, ists logisch das es kracht. Es wird versucht das Dokument freizugeben, obwohls schon im 1. Frame freigegeben wurde.

Das zweite das mich ein wenig irritiert ist

Delphi-Quellcode:
  _Document := 0;
Hier wird nichts freigeben, sondern lediglich ein Handle auf 0 gesetzt. Das ursprüngliche Handle existiert aber nach wie vor. Im besten fall ist sowas ein Memoryleak. :)

hoika 12. Dez 2017 13:06

AW: Seltsames Verhalten der Destruktoren
 
Hallo,
was ist denn _Document für ein Typ?

Setze einen Breakpoint und mache mal einen Watchpoint auf Self.
Es könnte sein, dass das Frame bereits freigegeben ist.
_Document := 0; ist ja zufällig die erste Codezeile.
Drehe mal die ersten beiden Zeilen um, wo knallt es dann?

Delbor 12. Dez 2017 13:35

AW: Seltsames Verhalten der Destruktoren
 
Hi Ghostwalker

Zitat:

Wenn ich das richtig Verstehe, hast du eine Form sowie zwei Frames. Desweiteren eine globale Instanz eines Dokumentes.
Jein - es gibt nur einen Basisframe, davon aber zwei Frameinstanzen. Das nur mal, um 'alle Klarheiten zu beseitigen'.
Grundsätzlich existiert von einem (Basis-)Frame, derFrameklasse mit zugehöriger Unit, ja immer mindestens eine Frameinstanz. Zumindest dann, wenn der Frame auch verwendet werden soll.
Der Basisframe ist im diesem Fall TPDFiumFrame. In die Mainform eingefügt sind PDFiumFrame1 und PDFiumFrame2 als 2 Instanzen des TPDFiumFrames. Und diese beiden Instanzen werden mit der Mainform bei Programmende zerstört - und damit auch das gerbte Handle (bzw. die Instanz (Kopie) davon.

Das sind die Fehlermeldungen,, die ich in der Reihenfolge erhalte:

Zitat:

Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt SynpdfTestProject.exe ist eine Exception der Klasse $C0000005 mit der Meldung 'access violation at 0x006476ae: read of address 0x000002c8' aufgetreten.
---------------------------
Zitat:

Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt SynpdfTestProject.exe ist eine Exception der Klasse $C0000005 mit der Meldung 'access violation at 0x005c7d73: read of address 0x00000010' aufgetreten.
---------------------------
Zitat:

Synpdftestproject
---------------------------
Zugriffsverletzung bei Adresse 005C7D73 in Modul 'SynpdfTestProject.exe'. Lesen von Adresse 00000010.
---------------------------

Zitat:

Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt SynpdfTestProject.exe ist eine Exception der Klasse $C0000005 mit der Meldung 'access violation at 0x005c7d73: read of address 0x00000010' aufgetreten.
---------------------------
Wichtig: Diesa habe ich erst seit heute, ohne auch nur die kleinste Änderung vorgenommen zu haben. Insbesondere sind im Framedestruktor ausser den dokumentierten Änderungen keine solchen vorgenommen worden.

Gruss
Delbor

Delbor 12. Dez 2017 13:49

AW: Seltsames Verhalten der Destruktoren
 
Hi Hoika
Document ist so deklariert:

Delphi-Quellcode:
FDocument : HPDFDocument;
...
 property _Document: HPDFDocument read FDocument write SetDocument;
Das Umdrehen der Codezeilen hat keine Änderung bewirkt.

Gruss
Delbor


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:06 Uhr.
Seite 1 von 2  1 2      

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