AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Zugriffsverletzung beim Zerstören der TIniFile-Instanz
Thema durchsuchen
Ansicht
Themen-Optionen

Zugriffsverletzung beim Zerstören der TIniFile-Instanz

Ein Thema von TheSledgeHammer · begonnen am 26. Jan 2021 · letzter Beitrag vom 3. Feb 2021
Antwort Antwort
Seite 3 von 7     123 45     Letzte »    
TheSledgeHammer

Registriert seit: 22. Mai 2019
Ort: Mulfingen
43 Beiträge
 
Delphi 10.3 Rio
 
#21

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 27. Jan 2021, 13:58
2.
Wenn in der DLL TForm verwendet wird, enthält die DLL eine komplett eigenständige Kopie der VCL.
Die VCL verwendet ebenfalls globale Variablen, insbesondere "Application".
"Application.Handle" muss vor der Verwendung der VCL in der DLL einmalig gesetzt werden.
Delphi-Quellcode:
{in der DLL, Handle der Anwendung übernehmen}
procedure InitVCL(AHandle: THandle); stdcall;
begin
  Application.Handle := AHandle;
end;
{in der Anwendung, Handle der Anwendung übergeben}
...
InitVCL(Application.Handle);
Ich hab mir das mal zu Gemüte geführt. Hab das meiner Meinung nach auch korrekt umgesetzt, allerdings kommt jetzt irgendwann im Erstellungsprozess die Exception
Exception-Klasse EOSError mit Meldung
System Error. Code 1400. Ungültiges Fensterhandle.

Application war auch zu Beginn nicht verfügbar, da die Unit Vcl.Forms nicht eingebunden war. Ich möchte jetzt sicher gehen, dass ich das korrekt verstanden hab: das soll schon in der DLL gesetzt werden, richtig? Nicht erst "während" des Konstruktors des eigentlichen TForm-Objekts? Da wäre es meiner Meinung nach nämlich zu spät, aber ich will da lieber nochmal nachfragen. Das sieht jetzt ungefähr so aus:
Delphi-Quellcode:
// In der DLL
procedure CreateSearch({... ;} AHnd: THandle); cdecl;
begin
  Application.Handle := AHnd; // hier ist das ja korrekt oder?
  FDynamicSearchDlg := TFormDynamicSearchDialog.Create({...}); // hier als Parameter wäre zu spät, richtig?
  // usw.
end;

// Im DLL-Interface (-> außerhalb der DLL, in der EXE drinnen sozusagen)
CreateSearch({...;}, Application.Handle);
Tobias
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.580 Beiträge
 
Delphi 11 Alexandria
 
#22

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 27. Jan 2021, 14:08
Ihr glaubt gar nicht, wie häufig ich schon bei Konstruktor-Aufrufen Exceptions bekommen habe; daher stehen die immer innerhalb des Try-Blocks.
Dadurch zerschießt du dir den Speicher aber. Denn wenn dort eine Exception auftritt, ist die Variable gar nicht initialisiert. Es wird also ein Free auf einer pseudo-zufälligen Speicherstelle aufgerufen...

Du kannst ja außen herum noch einmal ein try..except setzen oder ähnliches, wenn du die Fehlerursache im Konstruktor nicht abstellen kannst, aber beim try..finally darf die Erstellung des Objekts aus dem genannten Grund nicht im try-Block stehen.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
TheSledgeHammer

Registriert seit: 22. Mai 2019
Ort: Mulfingen
43 Beiträge
 
Delphi 10.3 Rio
 
#23

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 27. Jan 2021, 14:51
Ihr glaubt gar nicht, wie häufig ich schon bei Konstruktor-Aufrufen Exceptions bekommen habe; daher stehen die immer innerhalb des Try-Blocks.
Dadurch zerschießt du dir den Speicher aber. Denn wenn dort eine Exception auftritt, ist die Variable gar nicht initialisiert. Es wird also ein Free auf einer pseudo-zufälligen Speicherstelle aufgerufen...

Du kannst ja außen herum noch einmal ein try..except setzen oder ähnliches, wenn du die Fehlerursache im Konstruktor nicht abstellen kannst, aber beim try..finally darf die Erstellung des Objekts aus dem genannten Grund nicht im try-Block stehen.
Aus diesem Grund setze ich die Variable zuvor auf NIL, in der Annahme, dass die Zuweisung der Variable ebenfalls unterbrochen wird, wenn eine Exception im Konstruktor-Prozess ausgelöst wird. In diesem Fall sollte aber sowieso der innere Check von "Free" einschreiten, das hatten wir ja zuvor schon Ist halt doppelt abgesichert

Das was du jetzt erwähnst, würde ja bedeuten, dass der "eigene" Konstruktor zwar abgebrochen würde, der vom TObject aber nicht. Wie himitsu in einem vorherigen Post erläutert hat, beginnt die Erzeugung des TObjects tatsächlich ja schon vor dem "begin". D.h. "eigene" Klassen machen nach dem inherited Create noch eigenes Zeug, was dann u.U. eine Exception auslöst. Wenn das passiert, wird doch dann ein Memory Leak existieren, oder? Ich muss also, um diesen Leak zu eliminieren, irgendwo ein Free aufrufen, damit zumindest das TObject (und je nach Vererbung auch alle höheren Instanzen) wieder sauber zerstört wird.
Tobias
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.464 Beiträge
 
Delphi 12 Athens
 
#24

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 27. Jan 2021, 16:03
Application war auch zu Beginn nicht verfügbar, da die Unit Vcl.Forms nicht eingebunden war. Ich möchte jetzt sicher gehen, dass ich das korrekt verstanden hab: das soll schon in der DLL gesetzt werden, richtig? Nicht erst "während" des Konstruktors des eigentlichen TForm-Objekts? Da wäre es meiner Meinung nach nämlich zu spät, aber ich will da lieber nochmal nachfragen. Das sieht jetzt ungefähr so aus:
Delphi-Quellcode:
// In der DLL
procedure CreateSearch({... ;} AHnd: THandle); cdecl;
begin
  Application.Handle := AHnd; // hier ist das ja korrekt oder?
  FDynamicSearchDlg := TFormDynamicSearchDialog.Create({...}); // hier als Parameter wäre zu spät, richtig?
  // usw.
end;

// Im DLL-Interface (-> außerhalb der DLL, in der EXE drinnen sozusagen)
CreateSearch({...;}, Application.Handle);
Ja im Prinzip hab ich das so gedacht. Die Initialisierung kann aber erst erfolgen, wenn die Applikarion schon läuft (Hauptfenster erzeugt ist).
Da dein Formular von TForm abgeleitet ist, muss die Unit Forms zumindest da schon eingebunden sein.
http://docwiki.embarcadero.com/Libra...ication.Handle

Modale Formulare vorher zu erzeugen und nur bei Bedarf anzuzeigen ist in der Regel nicht sinnvoll.
Diese werden häufig nach diesem Schema benutzt:
Delphi-Quellcode:
procedure ShowMyDialogForm(var AMyData: TMyData): Boolean;
var
  F: TMyDialogForm; // globale Variable ist für Dialoge nicht erforderlich
begin
  F := TMyDialogForm.Create(nil); // Owner = nil, wir übernehmen selbst die Freigabe des Dialogs
  try
    {Daten übergeben zur Anzeige/Bearbeitung z.B.}
    F.Data := Copy(AMyData);

    Result := (F.ShowModal = mrOk);

    {geänderte Daten übernehmen}
    if Result then
      AMyData := Copy(F.Data);
  finally
    F.Free;
  end;
end;
Wenn tatsächlich im Contructor ein Fehler auftreten kann, sollte man das zusätzllich mit try..except absichern.
F wird dann nicht zugewiesen und der Resourcenschutzblock try..finally komplett nicht durchlaufen.
Man solllte Objekte immer auf der Ebene freigeben, wo diese auch erzeigt wurden, insbesondere aber nur an einer Stelle.
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.464 Beiträge
 
Delphi 12 Athens
 
#25

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 27. Jan 2021, 16:32
Parameter als PChar sind problemlos verwendbar, solange die übergebenen Zeichenketten in der DLL nicht verändert werden.
Wieder auf String casten und dann verändern ist nicht zulässig.

Rückgabewerte aus der DLL als PChar sind problematisch. Solange der Rückgabewert auf eine Constante oder einen Resourcestring verweist, ist das ok.
Delphi-Quellcode:
function MyDLLFunction(): PChar;
const
  sc = 'ConstText';
var
  s: string;
begin
  s := MyInternFunction;
  Result := PChar(s); // unzulässig da "s" nach verlassen der Funktion eventuell nicht mehr existiert
  // <- wenn Referenzzähler von s auf 0 fällt, wird der String freigegeben, Result enthält einen ungültiger Zeiger

  s := sc;
  Result := PChar(s); // zulässig da "s" auf eine Konstante verweist
  // Referenzzähler von String-Konstanten ist immer -1
end;
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.596 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#26

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 27. Jan 2021, 18:36
Parameter als PChar sind problemlos verwendbar, solange die übergebenen Zeichenketten in der DLL nicht verändert werden.
Wieder auf String casten und dann verändern ist nicht zulässig.
Doch. Ein "auf String casten" erzeugt eine Kopie des Inhalts.

Man muss nur darauf achten, dass auf beiden Seiten das gleiche PChar verwendet wird, oder besser gleich auf beiden Seiten PAnsiChar oder PWideChar, dann ist es eindeutig.
Thomas Mueller
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.580 Beiträge
 
Delphi 11 Alexandria
 
#27

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 27. Jan 2021, 19:05
Kannst du vielleicht ein Beispielprojekt erstellen, das nur die DLL-Funktion aufruft? Wenn dann der Fehler noch passiert, kannst du ja vielleicht alles aus der DLL herauswerfen, das du nicht posten möchtest, solange der Fehler noch auftritt.
Denn mit einem funktionierenden Beispiel ließe sich das Problem hier sicher ganz schnell lösen.

Wenn das passiert, wird doch dann ein Memory Leak existieren, oder? Ich muss also, um diesen Leak zu eliminieren, irgendwo ein Free aufrufen, damit zumindest das TObject (und je nach Vererbung auch alle höheren Instanzen) wieder sauber zerstört wird.
Ja, das ist ein Memory Leak, aber dagegen kannst du nichts tun. Wie gesagt: Wenn eine Exception im Konstruktor auftritt, wird der Variable nichts zugewiesen und sie ist dann, wenn sie vorher wie du geschrieben hast initialisiert wurde, schlicht nil. Wenn du es aber vergisst, gibt es Probleme.

Der Vorteil, den du in diesem Konstrukt siehst, ist zwar nachvollziehbar, kann aber in der Realität nie (!) eintreten.

Deshalb sollte man sich besser an den Standard halten. Der hat schon seinen Sinn.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
TheSledgeHammer

Registriert seit: 22. Mai 2019
Ort: Mulfingen
43 Beiträge
 
Delphi 10.3 Rio
 
#28

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 28. Jan 2021, 08:00
Ja im Prinzip hab ich das so gedacht. Die Initialisierung kann aber erst erfolgen, wenn die Applikarion schon läuft (Hauptfenster erzeugt ist).
Da dein Formular von TForm abgeleitet ist, muss die Unit Forms zumindest da schon eingebunden sein.
http://docwiki.embarcadero.com/Libra...ication.Handle
Also nur, damit ich das klarstelle: wenn ich den Erben einer TForm-Klasse (hier das Objekt TFormDynamicSearchDialog) erzeuge, brauche ich keine Unit Vcl.Forms einbinden; das geht auch ohne. In derjenigen Unit, wo ich die Klasse TFormDynamicSearchDialog allerdings implementiere, da brauche ich das natürlich, sonst kennt Delphi ja den Typ TForm nicht.

Ich hab jetzt aber dort, wo ich den Erben von TForm instanziiere, das Obkekt Application verwenden sollen und da brauchte ich bisher die Unit Vcl.Forms noch nicht. Daher hab ich sie jetzt erst eingebunden. Aber wie ich ja sagte: ich erhalte eine invalid handle value Exception. Und das während der Konstruktion des Objekts TFormDynamicSearchDialog. Ich glaub es war bei der Erzeugung des PageControl-Components, bin mir aber nicht mehr sicher. Was mache ich denn jetzt damit? Die Hauptapplikation ist ja die EXE-Anwendung und die läuft natürlich schon. Oder hast du damit gemeint, dass ich das Handle-Value nach der Erzeugung des Objekts TFormDynamicSearchDialog erst setzen soll?

Modale Formulare vorher zu erzeugen und nur bei Bedarf anzuzeigen ist in der Regel nicht sinnvoll.
Diese werden häufig nach diesem Schema benutzt:
Delphi-Quellcode:
procedure ShowMyDialogForm(var AMyData: TMyData): Boolean;
var
  F: TMyDialogForm; // globale Variable ist für Dialoge nicht erforderlich
begin
  F := TMyDialogForm.Create(nil); // Owner = nil, wir übernehmen selbst die Freigabe des Dialogs
  try
    {Daten übergeben zur Anzeige/Bearbeitung z.B.}
    F.Data := Copy(AMyData);

    Result := (F.ShowModal = mrOk);

    {geänderte Daten übernehmen}
    if Result then
      AMyData := Copy(F.Data);
  finally
    F.Free;
  end;
end;
Exakt! Und dieses Schema bilde ich heute schon in der EXE-Anwendung nach. Dort steht es exakt so, wie du es im Beispiel gezeigt hast. Jetzt wurde aber das Objekt in eine DLL verlagert und da ich ja nicht wollte, dass meine Kollegen zu viel Code anpassen müssen, hab ich die einzelnen Methoden in der DLL abgebildet. D.h. um in deinem Beispiel zu bleiben gibt es einen Konstruktor, einen Destruktor, ein ShowModal und eine Property; letztere gibt es natürlich nur im Interface zur DLL, die DLL selbst exportiert dann natürlich eine Setter- und Getter-Methode. Daher steht das "Create" getrennt von dem "ShowModal", was die DLL angeht. Aber das ist ja nichts, was man jetzt nicht machen darf. Eine neue Komponente würde ich so natürlich nicht programmieren, da gäbe es dann eine Art "CreateAndShow"-Methode oder so.
Tobias
  Mit Zitat antworten Zitat
TheSledgeHammer

Registriert seit: 22. Mai 2019
Ort: Mulfingen
43 Beiträge
 
Delphi 10.3 Rio
 
#29

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 28. Jan 2021, 08:03
Parameter als PChar sind problemlos verwendbar, solange die übergebenen Zeichenketten in der DLL nicht verändert werden.
Wieder auf String casten und dann verändern ist nicht zulässig.

Rückgabewerte aus der DLL als PChar sind problematisch. Solange der Rückgabewert auf eine Constante oder einen Resourcestring verweist, ist das ok.
Delphi-Quellcode:
function MyDLLFunction(): PChar;
const
  sc = 'ConstText';
var
  s: string;
begin
  s := MyInternFunction;
  Result := PChar(s); // unzulässig da "s" nach verlassen der Funktion eventuell nicht mehr existiert
  // <- wenn Referenzzähler von s auf 0 fällt, wird der String freigegeben, Result enthält einen ungültiger Zeiger

  s := sc;
  Result := PChar(s); // zulässig da "s" auf eine Konstante verweist
  // Referenzzähler von String-Konstanten ist immer -1
end;
Also hier gibt es keine Probleme. Ich caste alles entsprechend, so wie dummzeuch es ja beschrieben hat. I.d.R. werden aber die PChar-Variablen unverändert einfach durch gereicht, von daher gibt es hier auch keine Veränderungen. Aber sollte es in einem anderen Fall dazu kommen, wird natürlich eine lokale Kopie erzeugt und mit der weiter gearbeitet.
Tobias
  Mit Zitat antworten Zitat
DasWolf

Registriert seit: 7. Jun 2016
76 Beiträge
 
Delphi 10.1 Berlin Professional
 
#30

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 28. Jan 2021, 10:59
Free prüft selbst ob die Variable bereits nil ist, dann passiert nichts.
TObject(nil).Free; // läuft problemlos
Das ist falsch. Korrigiert mich bitte, wenn es nach Version Delphi 10.1 anders sein sollte.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 3 von 7     123 45     Letzte »    


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:54 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