Entwickler-Ecke
Windows API - FreeLibrary - Programm hängt
Ratchet - Mo 28.09.09 10:26
Titel: FreeLibrary - Programm hängt
Ich habe ein Programm welches selbstgeschriebene DLLs dynamisch läd. Funktioniert auch alles prima, nur wenn ich das Programm ändere hängt es sich auf. Dort wo die DLLs wieder entladen werden sollen.
Ich habe eine Array (PluginList) in dem Objekte mit den Handles der DLLs gemerkt werden. Beim Beenden gehe ich nur dieses Array durch und möchte mit FreeLibrary alles schön sauber machen. Momentan habe ich zwei DLLs geladen. Die erste wird auch normal mit FreeLibrary abgearbeitet, aber bei der zweiten geht dann nichts mehr. Dachte erst irgendwann würde eine Überlauf passieren, habe das Programm also einfach mal laufen lassen, aber den ganzen Tag lang ist nichts passiert. Das Hostprogramm sowie die DLLs sind mit ShareMem und Laufzeitpackages übersetzt.
Jemand eine Idee was das sein könnte?
Pausiere ich das Programm erscheint das CPU Fenster beim Befehl
Quelltext
1: 2:
| ntdll.KiFastSystemCallRet: 77A95E74 C3 ret |
So entlade ich die DLLs
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure UnloadAllPlugins; var i: Integer; begin for i := Length(PluginList) - 1 downto 0 do begin FreeAndNil(PluginList[i].ccsPlugin); if PluginList[i].DllHandle <> 0 then begin FreeLibrary(PluginList[i].DllHandle); end; FreeAndNil(PluginList[i]); end; SetLength(PluginList, 0); end; |
Delete - Mo 28.09.09 12:38
hast du die Schleife schon mal debuggt und bist sie in Einzelschritten durchgegangen, um zu gucken, ob die Werte stimmen?
Ratchet - Mo 28.09.09 13:04
Ja, stimmt alles. Also alles was ich mir so ansehen kann sieht vernünftig aus. Die Objekte stimmen, Handle von den DLLs sind immer noch die gleichen wie nach dem Laden.
HelgeLange - Mo 28.09.09 16:44
Bist Dir sicher, dass in der DLL alles freigegeben wird ? ändere mal die reihenfolge, in welcher du die DLL lädst und entlädst und schau, ob es an einer bestimmten DLL hangt oder es immer die 2. ist
Tryer - Mo 28.09.09 20:10
Gibt es ein Handshake mit dem "cssPlugin" und wartet die dll noch auf irgendwas? Ggf. also die Free - Reihenfolge cssPlugin / dll anpassen.
Ratchet - Di 29.09.09 09:52
@HelgeLange: In den DLLs wird alles freigegeben, habe ich eben nochmal Schritt für Schritt geprüft. Die Reihenfolge des Ladens und Entladens habe ich auch mal geändert. Es ist immer ab der zweiten DLL, egal welche von beiden es ist. Irgendwas scheint da zu passieren.
@Tryer: Einen Handshake gibt es nicht. Das Free der DLLs und des csPlugins kann ich nicht ändern. Wenn ich das ccsPlugin nach der DLL lösche (FreeAndNil) dann bekomme ich eine Zugriffsverletzung. Ist auch logisch, denke ich, da ich ja keinen Zugriff mehr auf die DLL habe.
Flamefire - Di 29.09.09 11:18
wie ist denn die deklaration des arrays? hängt er wirklich beim freelibrary oder möglicherweise schon eher?
Ratchet - Di 29.09.09 11:51
Ja wirklich beim FreeLibrary. Das Array ist folgendermnaßen deklariert, das Laden der DLLs habe ich auch mal mit rangehängt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56:
| type TDllPlugin = class ccsPlugin: TccsPlugin; DllFile: string; DllHandle: THandle; end;
TPluginList = array of TDllPlugin;
TccsPluginInitProcedure = function(DBConnection: TADOConnection): TccsPlugin; stdcall;
var PluginList: TPluginList;
implementation
function LoadPlugins(Mask: string): Integer; var InitFunction: TccsPluginInitProcedure; i: Integer; sr: TSearchRec; begin Result := 0; if FindFirst(DllPath + Mask, faAnyFile, sr) = 0 then begin repeat SetLength(PluginList, Length(PluginList) + 1); PluginList[Length(PluginList) - 1] := TDllPlugin.Create; PluginList[Length(PluginList) - 1].DllFile := DllPath + sr.Name; PluginList[Length(PluginList) - 1].DllHandle := LoadLibrary(PAnsiChar(DllPath + sr.Name)); InitFunction := GetProcAddress(PluginList[Length(PluginList) - 1].Dllhandle, 'Init'); if Assigned(InitFunction) then begin PluginList[Length(PluginList) - 1].ccsPlugin := InitFunction(ccsGlobalDataConnection); Inc(Result); end; until FindNext(sr) <> 0; SysUtils.FindClose(sr); end; end;
procedure UnloadAllPlugins; var i: Integer; begin for i := Length(PluginList) - 1 downto 0 do begin FreeAndNil(PluginList[i].ccsPlugin); if PluginList[i].DllHandle <> 0 then begin FreeLibrary(PluginList[i].DllHandle); end; FreeAndNil(PluginList[i]); end; SetLength(PluginList, 0); end; |
Flamefire - Di 29.09.09 15:29
ok allgemein: solche sachen gehören in den constructor und destructor der klasse
wenn du schon ein objekt hast, warum benutzt du dann create/destroy nicht?
geht viel sauberer
2: statt findfirst benutze lieber fielexists
3: für dein problem: versuche es mal testweise so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure UnloadAllPlugins; var i: Integer; begin for i := Length(PluginList) - 1 downto 0 do begin if PluginList[i].DllHandle <> 0 then begin FreeLibrary(PluginList[i].DllHandle); end; end; SetLength(PluginList, 0); end; |
und danach so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure UnloadAllPlugins; var i: Integer; begin for i := Length(PluginList) - 1 downto 0 do begin if PluginList[i].DllHandle <> 0 then begin FreeLibrary(PluginList[i].DllHandle); end; FreeAndNil(PluginList[i]); end; SetLength(PluginList, 0); end; |
BTW: wenn du die initfunktion iwo benutzt: kommentier den teil mal aus, um zu prüfen, obs ohne die initfunktion korrekt funktioniert
Ratchet - Di 29.09.09 16:47
Flamefire hat folgendes geschrieben : |
ok allgemein: solche sachen gehören in den constructor und destructor der klasse
wenn du schon ein objekt hast, warum benutzt du dann create/destroy nicht?
geht viel sauberer |
Stimmt. Ist anscheint historisch so gekommen, habe es geändert.
Und egal ob mit oder ohne Init, und auch wenn ich die FreeAndNils weglasse, selbes Verhalten.
HelgeLange - Di 29.09.09 16:59
lädst Du Laufzeitpackages dynamisch ? also vcl.bpl, rtl, vcldb, rtldb und wie sie alle heissen ?
Du scheinst ein Object aus der DLL in deinem Unload freizugeben, wenn Du allerdings nichts mit Laufzeit-Packages arbeitest, haben Hauptprogramm und DLL alle eigene VCL variablen etc.
Tryer - Di 29.09.09 18:15
Hinweis aus dem MSDN bzgl. DllMain
| Zitat: |
Calling functions that require DLLs other than Kernel32.dll may result in problems that are difficult to diagnose. For example, calling User, Shell, and COM functions can cause access violation errors, because some functions load other system components. Conversely, calling functions such as these during termination can cause access violation errors because the corresponding component may already have been unloaded or uninitialized.
Because DLL notifications are serialized, entry-point functions should not attempt to communicate with other threads or processes. Deadlocks may occur as a result.
For information on best practices when writing a DLL, see http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx. |
HelgeLange - Di 29.09.09 18:31
Aber keine Sorge, das mit den DLLs funnktioniert und auch die DB-Verbindung, die du dahin übergeben willst.
Ich nutze ähnliches in meinem Komponenten-Package seit Jahren ohne Probleme.. naja, es gibt manchmal Zeiten wo es beim entyladen crasht, das liegt aber dadran, dass ich was essentielles ändern musste, was das Entladen beinflusste. Hatte erst gestern 2 Stunden einen solchen Fehler gesucht, der lag allerdings auch wirklich in meinen Komponenten...
Lass Dich also nicht entmutigen.
Zur Not poste doch mal ein komplettes lauffähiges Programm mit source, dann helf ich Dir debuggen
Ratchet - Do 01.10.09 08:02
HelgeLange hat folgendes geschrieben : |
lädst Du Laufzeitpackages dynamisch ? also vcl.bpl, rtl, vcldb, rtldb und wie sie alle heissen ?
Du scheinst ein Object aus der DLL in deinem Unload freizugeben, wenn Du allerdings nichts mit Laufzeit-Packages arbeitest, haben Hauptprogramm und DLL alle eigene VCL variablen etc. |
Ratchet hat folgendes geschrieben : |
| ...Das Hostprogramm sowie die DLLs sind mit ShareMem und Laufzeitpackages übersetzt... |
@Tryer: Werde ich mir gleich mal genauer anschauen, danke.
@HelgeLange: Das ganze Progamm werde ich hier nicht posten können. Zu umfangreich. Außerdem benutze ich noch eine von uns selbstgeschriebene Komponentensammlung. Das darf ich nicht mal eben so veröffentlichen.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!