Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Richtiges Beenden/Freigeben einer (Delphi) DLL (https://www.delphipraxis.net/210846-richtiges-beenden-freigeben-einer-delphi-dll.html)

OlliWW 21. Jun 2022 13:31

Richtiges Beenden/Freigeben einer (Delphi) DLL
 
Hallo Zusammen,

Ich habe eine kleine Anwendung (in Delphi) geschrieben, die eine DLL aufruft:

Delphi-Quellcode:
   Handle := LoadLibrary('MeineDLL.dll');
   if Handle <> 0 then
   begin
     try
        @dllinit := GetProcAddress(Handle, 'dllInit');
        if Assigned(dllinit) then
        begin
          dllinit;
        end;
     finally
     end
   end;
Wenn ich die Anwendung beende rufe ich im Destroy noch das FreeLibrary auf:
Delphi-Quellcode:
FreeLibrary(Handle);
Die DLL macht eigentlich nichts, außer in der Prozedur "dllInit" einen Logger zu initialisieren (ich habe es mit verschiedenen Loggern ausprobiert: Quicklogger, LoggerPro):
Delphi-Quellcode:
logger := TLoggerProFileAppender.Create(5, 10000, '.\log');
  Log := BuildLogWriter([logger]);
Logger und Log sind global deklariert:
Delphi-Quellcode:
    logger: TLoggerProFileAppender;
    Log: ILogWriter;
Wenn ich nun meine Anwendung starte, wird die DLL geladen, der Logger initialisiert und alles ist gut. Beende ich nun die Anwendung, bekomme ich eine Access Violation:
Code:
Erste Gelegenheit für Exception bei $78BE215B. Exception-Klasse $C0000005 mit Meldung 'access violation at 0x78be215b: access of address 0x78be215b'. Prozess Project2.exe
$C0000005 ist meines Erachtens ein Fehler bei dem von einer fremden Anwendung (Anwendung) auf fremden Speicher (DLL) zugegriffen werden soll.

Ich nehme an, dass das Freigeben der DLL das Finalization von verwendeten Units auslöst und dass das dafür sorgt, dass Windows denkt, hier greift jemand fremdes auf meinen DLL Speicher zu.

Ich habe das nun mit verschiedenen Units ausprobiert. Ich habe noch die Vermutung, dass es mit Units zusammenhängen KÖNNTE, die einen Thread besitzen (alle diese Logger probiere ich nämlich aus, um einen Threadsafen Logger zu haben).

Hat jemand eine Idee, wie ich das sauber lösen kann? Es geht mir hier nicht um das Logging Problem, das ist nur die Stelle, womit ich es am besten nachvollziehen kann.

Ich habe auch schon eine uses auf System.SimpleShareMem eingebaut, das hat aber auch nicht geholfen. Irgendwie müsste ich der DLL sagen können, dass sie sich selbst beenden soll und danach erst das FreeLibrary aufrufen.

Viele Grüße
Olli

Neutral General 21. Jun 2022 13:42

AW: Richtiges Beenden/Freigeben einer (Delphi) DLL
 
Hast du mal probiert dass FreeLibrary testweise in ein FormClose o.ä. zu packen um ein/auszuschließen dass es am finalization liegt?
Dann seh ich in deiner DLL ein Interface. Da gibt es auch einige Möglichkeiten ins Fettnäpfchen zu treten.
Wie gibst du denn deine Objekte in der DLL frei?

$C0000005 ist übrigens nur der interne Code für Zugriffsverletzungen.
Die meisten deiner Vermutungen sind denke ich falsch. DLL und Anwendung teilen sich einen Speicher.
Da sieht Windows selbst erst mal keinen Unterschied.

PS: Dein try-finally oben bewirkt rein gar nichts wenn das finally leer ist.

OlliWW 21. Jun 2022 13:48

AW: Richtiges Beenden/Freigeben einer (Delphi) DLL
 
Zitat:

Zitat von Neutral General (Beitrag 1507571)
Hast du mal probiert dass FreeLibrary testweise in ein FormClose o.ä. zu packen um ein/auszuschließen dass es am finalization liegt?

Ich hab das FreeLibrary mal zum testen in einen Button gelegt: Gleiches Phänomen.
Ich kann die DLL noch soweit debuggen, dass ich sehe dass der Finalization teil der DLL getriggert wird (wenn ich ihn implementiere). Das heisst, von meinem Verständnis läuft es wie folgt:

Anwendung: FreeLibrary
DLL: finalization der dll methoden
DLL: finalization der verwendeten units
DLL: <crash...in einer der verwendeten units>

Der Code funktioniert außerhalb einer DLL übrigens ohne Probleme, Memory Leaks etc. Alles was meine DLL ja macht, ist den Logger eine Drittkomponente zu initialisieren.

Zitat:

Zitat von Neutral General (Beitrag 1507571)
PS: Dein try-finally oben bewirkt rein gar nichts wenn das finally leer ist.

Ist nur "test code", kein sauber aufgeräumter Code. Ich habe mir nur schnell ein Testprogramm für den DLL Call geschriebnen um andere Seiteneffekte ausschließen zu können.

Sinspin 21. Jun 2022 13:56

AW: Richtiges Beenden/Freigeben einer (Delphi) DLL
 
Zitat:

Zitat von OlliWW (Beitrag 1507567)
$C0000005 ist meines Erachtens ein Fehler bei dem von einer fremden Anwendung (Anwendung) auf fremden Speicher (DLL) zugegriffen werden soll.

Ich nehme an, dass das Freigeben der DLL das Finalization von verwendeten Units auslöst und dass das dafür sorgt, dass Windows denkt, hier greift jemand fremdes auf meinen DLL Speicher zu.

Zuviele unbekannte. $C0000005 ist ein Nullpointer Fehler. Wie und warum hier in dem Fall kann nur ein detailierter Fehlerreport sagen.

Zitat:

Zitat von OlliWW (Beitrag 1507567)
Ich habe noch die Vermutung, dass es mit Units zusammenhängen KÖNNTE, die einen Thread besitzen

Es wird wärmer...

Zitat:

Zitat von OlliWW (Beitrag 1507567)
Irgendwie müsste ich der DLL sagen können, dass sie sich selbst beenden soll und danach erst das FreeLibrary aufrufen.

Gute Idee!
Zu DllInit kommt noch DllShutdown, was dafür sorgt dass alles was läuft auch beendet wird und ist(!) bevor die dll entladen wird.

DeddyH 21. Jun 2022 13:58

AW: Richtiges Beenden/Freigeben einer (Delphi) DLL
 
Könnte es etwas ähnliches sein? https://www.delphipraxis.net/189047-[erledigt]-interface-aus-dll-per-latebinding-freelibrary-toedlich.html

OlliWW 21. Jun 2022 14:10

AW: Richtiges Beenden/Freigeben einer (Delphi) DLL
 
Zitat:

Zitat von DeddyH (Beitrag 1507575)

Ja ich glaube das ist exakt mein Problem.

Ich habe nämlich auch vor ein PluginSystem zu bauen bzw. bin (bis auf dieses Problem) schon fertig. Auf das Problem bin ich auch nur gestoßen weil das ganze als Dienst läuft, der sich automatisch aktualisiert. Beim aktualisieren passiert folgendes:
Dienst beendet sich, Dienst startet sich neu, liefert die neuen DLLs aus (hängen als Resource dran) und läd die DLLs.

Mein Problem dabei ist nur, dass die DLLs beim beenden des Dienstes zu langsam freigegeben werden, wenn man FreeLibrary nicht nutzt, weswegen die DLLs beim Dienst-Neustart nicht überschrieben werden können.

Aber gut, dann denke ich nutze ich deine Lösung: Ich ignoriere FreeLibrary einfach und löse das andere Problem durch einen "Abwarten" Timer ;)

Vielen Dank!

Neutral General 21. Jun 2022 14:14

AW: Richtiges Beenden/Freigeben einer (Delphi) DLL
 
Zitat:

Zitat von DeddyH (Beitrag 1507575)

Aber was ist denn da (und hier) letztendlich rein technisch das Problem (gewesen)?

OlliWW 21. Jun 2022 14:16

AW: Richtiges Beenden/Freigeben einer (Delphi) DLL
 
Dass FreeLibrary dazu führt, dass ich mit Zugriffsverletzungen zugeworfen werde.

Da will man ordentlich sein dann ists auch nicht gut ;)

Sinspin 21. Jun 2022 14:35

AW: Richtiges Beenden/Freigeben einer (Delphi) DLL
 
Wo steht da dass FreeLibrary Fehler zuwirft?
Das ist Unsinn. Ich verwende FreeLibrary für meine Plugins und es knallt nie.
Jedes meiner Plugins hat Fenster und Threads. Alles wird ordentlich aufgeräumt und dann wird die Dll freigegeben. Das funzt.

Neutral General 21. Jun 2022 15:15

AW: Richtiges Beenden/Freigeben einer (Delphi) DLL
 
Zitat:

Zitat von OlliWW (Beitrag 1507578)
Dass FreeLibrary dazu führt, dass ich mit Zugriffsverletzungen zugeworfen werde.

Da will man ordentlich sein dann ists auch nicht gut ;)

Ja, aber warum? Das bedeutet immer noch, dass in deinem Code was verkehrt ist.
Du kannst grundsätzlich davon ausgehen, dass Windows API funktionen fehlerfrei* sind.

*) Was ist schon fehlerfrei. Aber in 99,99% aller Fälle liegt es nicht an der Windows API, sondern am Programmierer.


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:16 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