![]() |
Eine DLL freigeben. (CallBack)
Nabend,
Ich habe ein Programm was eine DLL aufruft, dynamisch. Wenn ich die DLL aufrufe, dann lade ich ein Formular. Wenn ich aber das Formular wieder schließe, würde ich die DLL gerne wieder entladen. Nur jetzt stellt sich die Frage WIE? Ich habe bereits versucht mit dem OnClose Ereignis die DLL freizugeben "FreeLibrary();". Den Parameter dazu sende ich beim laden der DLL. Jedoch wird durch diesen Aufruf das ganze Programm geschlossen. Deshalb vermute ich das der Aufruf von FreeLibrary vom Hauptprogramm stammen muss, oder? |
Re: Eine DLL freigeben.
Die DLL kann sich schlecht selbst freigeben, während sie noch Code in sich selber ausführt. Wie sollte denn die nächste Anweisung nach dem FreeLibary() ausgeführt werden, wenn die DLL freigegeben ist?
Das Laden sowie freigeben der DLL muss im Hauptprogramm geschehen. |
Re: Eine DLL freigeben.
Zitat:
Die DLL sagt ja wann "Schluss" ist, nicht das Hauptprogramm, wie kann das Hauptprogramm das mitbekommen, bzw. wie "sage" ich das dem Hauptprogramm? |
Re: Eine DLL freigeben.
Da gibt es mehrere Möglichkeiten, z.B.:
- Windows Message an das Hauptprogramm - Event triggern - Callback aufrufen |
Re: Eine DLL freigeben.
Wenn die DLL ein Formular anzeigt, muss dies ja mit ShowModal innerhalb der Komponente geschehen. Daher tippe ich, wenn Du aus der "Aufruffunktion" der Host-Anwendung herauskommst, sollte FreeLibrary eigentlich funktionieren. Falls ich hier falsch liege, möge man mich korrigieren.
|
Re: Eine DLL freigeben.
Meinst du mit ShowModal TForm.ShowModal?
Zitat:
Delphi-Quellcode:
Oder sollte man das aus irgendeinem Grund nicht machen, bei mir klappt das wunderbar?
Addons := TAddons.Create(NIL);
Addons.Show; @Muetze1 Das sind doch mal Schlüsselwörter. Ich werde mich mal durch die Suche wälzen :-) |
Re: Eine DLL freigeben. Mit CallBack
Irgendwie stehe ich komplett auf dem Schlauch :wall: ich komm einfach nicht mehr weiter ....
Wäre echt nett, wenn ihr mal drüberschaut. Ich habe mir ein Beispiel angeschaut (CallBack), dass konnte mir jedoch auch nicht weiterhelfen :-((( Hauptunit
Delphi-Quellcode:
TYPE TCallBackFunction = FUNCTION (hLib:Cardinal) : Cardinal;
PROCEDURE FreeDLL(hLib:Cardinal); TYPE Tcreatedll = PROCEDURE (hLib:Cardinal); var MainForm: TMainForm; implementation {$R *.dfm} procedure TMainForm.bLoadDllClick(Sender: TObject); VAR hLib:cardinal; Mcreatedll : Tcreatedll; BEGIN hLib := LoadLibrary(PChar('pDll_CallBack.dll')); IF hLib <> 0 THEN BEGIN @Mcreatedll := GetProcAddress(hLib, 'createdll'); IF @Mcreatedll <> NIL // Hier muss noch was passieren! THEN Mcreatedll(hLib); END; end; PROCEDURE FreeDLL(hLib:Cardinal); BEGIN FreeLibrary(hLib); END; Die DLL.dpr
Delphi-Quellcode:
Das DLL Formular
library pDll_CallBack;
uses SysUtils, Classes, uDll_Form in 'uDll_Form.pas' {DllForm}; {$R *.res} exports createdll; begin end.
Delphi-Quellcode:
// Die Prozedur für den Export PROCEDURE createdll(hLib:Cardinal); // in dieser Variable halte ich den Parameter der DLL VAR AhLib : Cardinal; TYPE TCallBackFunction = FUNCTION (hLib:Cardinal) : Cardinal; var DllForm: TDllForm; implementation {$R *.dfm} PROCEDURE closedll(hLib:Cardinal); BEGIN // ??? END; PROCEDURE createdll(hLib:Cardinal); BEGIN IF NOT (Assigned(DllForm)) THEN DllForm := TDllForm.Create(NIL); // Parameter zur speicherung übergeben AhLib := hLib; DllForm.Show; END; procedure TDllForm.bCloseClick(Sender: TObject); begin close; end; procedure TDllForm.FormClose(Sender: TObject; var Action: TCloseAction); begin DllForm.Free; DllForm := NIL; // Hier muss das Callback starten closedll(AhLib); end; end. |
Re: Eine DLL freigeben. Mit CallBack
Zitat:
Und bei nicht Modalen Formularen wird die Freigabe mit Release durchgeführt und nicht mit einem Free, da sonst einige Windows-Messages ebenfalls im Nirvana landen. |
Re: Eine DLL freigeben. (CallBack)
Liste der Anhänge anzeigen (Anzahl: 1)
Hi, ich habe im Forum was gefunden was ich auch einigermaßen verstanden habe, leider haut mir ein AV alles um die Ohren :-(((
![]() MainForm
Delphi-Quellcode:
Die DLL.dpr
TYPE Tcreatedll = PROCEDURE (ACallBack: Pointer);
PROCEDURE FreeDLL; var Form1: TForm1; hLib:cardinal; implementation {$R *.DFM} PROCEDURE FreeDLL; BEGIN // zum Test ob das CallBack klappt ShowMessage('Hallo'); // Un hier knallt es! Dabei wird auch das Hauptformular geschlossen, wenn der Debugger // deaktiviert ist. FreeLibrary(hLib); END; procedure TForm1.bLoadDllClick(Sender: TObject); VAR Mcreatedll : Tcreatedll; BEGIN hLib := LoadLibrary(PChar('pDll.dll')); IF hLib <> 0 THEN BEGIN @Mcreatedll := GetProcAddress(hLib, 'CreateDLL'); IF @Mcreatedll <> NIL // Hier wird die Prozedur übergeben die ausgeführt werden soll. THEN Mcreatedll(@FreeDLL); END; end; end.
Delphi-Quellcode:
Und das DLL-Formular
library pDll;
uses SysUtils, Classes, uDllForm in 'uDllForm.pas' {DllForm}; {$R *.RES} exports CreateDLL; end.
Delphi-Quellcode:
Muss ich das DLL Formular noch Releasen ? Alse TForm.Release; Oder was mache ich falsch ?
PROCEDURE CreateDLL(ACallBack: Pointer);
var DllForm: TDllForm; var gCallBack: procedure = nil; implementation {$R *.DFM} PROCEDURE CreateDLL(ACallBack: Pointer); BEGIN IF NOT Assigned(DllForm) THEN DllForm := TDllForm.Create(NIL); DllForm.Show; // Parameter übergeben... @gCallBack := ACallBack; END; procedure TDllForm.FormDestroy(Sender: TObject); begin DllForm := NIL; // CallBack starten if Assigned(gCallBack) then gCallBack; end; procedure TDllForm.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; procedure TDllForm.bCloseClick(Sender: TObject); begin close; end; end. |
Re: Eine DLL freigeben. (CallBack)
Du zerschießt dir schon wieder deinen Aufrufstack.
Du darfst keinen "Programmfaden" (Stack) mehr haben der sich auf Speicher in der DLL bezieht wenn du die DLL freigibst. |
Re: Eine DLL freigeben. (CallBack)
Ich habe das doch so gemacht wie du meinst.
Die Variable auf NIL im Destroy ist doch okay. Wenn ich dich richtig verstanden habe darf ich das nicht im Destroy freigeben oder? Ja wann dann? |
Re: Eine DLL freigeben. (CallBack)
Zitat:
|
Re: Eine DLL freigeben. (CallBack)
argghhh...
dann hat Muetze1 mich auf den falschen Pfad gelockt... :-((( |
Re: Eine DLL freigeben. (CallBack)
Zitat:
|
Re: Eine DLL freigeben. (CallBack)
Zitat:
Und ich habe zuvor schon eine gewisse Sortierung in Richtung des Umfangs/Schwierigkeit gegeben, da hat Bernhard Geyer schon Recht. |
Re: Eine DLL freigeben. (CallBack)
Ihr schreibt so als wäre ich jetzt richtig böse, mal lernt halt dazu, jetzt kann ich CallBack wieder hervorkrammen wenn ichs brauche...
Zitat:
|
Re: Eine DLL freigeben. (CallBack)
Hallo,
in der hilfe nach PostMessage suchen. Am besten du definierst dir einen eigene Nachricht
Delphi-Quellcode:
Abschicken mit
const
wm_FreeMyLibrary = wm_User + 100;
Delphi-Quellcode:
Empfangen in der eigenen Procedure
PostMassage(Mainform.Handle, wm_FreeMyLibrary, 0, 0);
Delphi-Quellcode:
Gruß oki
procedure WMFreeMyLibrary(var Message: TMsg); message WM_FreeMyLibrary;
procedure TMainForm.WMFreeMyLibrary(var Message: TMsg); begin // DLL frei geben end; |
Re: Eine DLL freigeben. (CallBack)
Liste der Anhänge anzeigen (Anzahl: 1)
Wie ich in den Debugger schaue und auf diesen Satz hoffe: "Modul entladen: ...". Und er kommt, erstmal danke an alle und besonders an oki aber, auch die anderen haben wieder super geholfen. So und an alle die gleiches Vorhaben werde ich hier mal meinen Code präsentieren:
MainForm
Delphi-Quellcode:
In der DLL.dpr habe ich nichts verändert nur die export Procedure...
type
TMainForm = class(TForm) bDllLaden: TButton; bClose: TButton; procedure bCloseClick(Sender: TObject); procedure bDllLadenClick(Sender: TObject); private // die Variable muss global gespeichert werden damit FreeLibrary ein Ziel hat class var hLib:cardinal; const wm_FreeMyLibrary = wm_User + 100; public procedure WMFreeMyLibrary(var Message: TMsg); message WM_FreeMyLibrary; end; // Die dynamische dekleration einer dll TYPE Tcreatedll = PROCEDURE (FormHandle:HWND); //[...] procedure TMainForm.bDllLadenClick(Sender: TObject); VAR Mcreatedll : Tcreatedll; BEGIN hLib := LoadLibrary(PChar('pDLL.dll')); IF hLib <> 0 THEN BEGIN @Mcreatedll := GetProcAddress(hLib, 'createDll'); IF @Mcreatedll <> NIL // nun wird zusätzlich das handle übergeben, was später benötigt wird THEN Mcreatedll(MainForm.Handle); END; end; procedure TMainForm.WMFreeMyLibrary(var Message: TMsg); begin // hier kann auch alles mögliche stehen, aber dass kann man dann auch in einem callback schreiben freelibrary(hLib); end; DLL Formular
Delphi-Quellcode:
Und nochmal als Download, damit es auch jeder ausprobieren kann; man bin ich glücklich :dancer: :-D :drunken: :firejump:
type
TDllAddons = class(TForm) bClose: TButton; procedure bCloseClick(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormDestroy(Sender: TObject); private const wm_FreeMyLibrary = wm_User + 100; public { Public-Deklarationen } end; //[...] AFormHandle:HWND; PROCEDURE createDll(FormHandle:HWND); //[...] PROCEDURE createDll(FormHandle:HWND); BEGIN IF NOT (Assigned(DllAddons)) THEN DllAddons := TDllAddons.Create(NIL); // parameterübergabe AFormHandle := FormHandle; DllAddons.Show; END; procedure TDllAddons.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; procedure TDllAddons.FormDestroy(Sender: TObject); begin // den parameter schön freigeben DllAddons := NIL; // die nachicht senden PostMessage(AFormHandle, wm_FreeMyLibrary, 0, 0); end; |
Re: Eine DLL freigeben. (CallBack)
hi,
schön, dass es klappt. Mein Codeschnipsel hat aber nur den Rest gebracht. Den Weg haben die anderen gewiesen. Gruß oki |
Re: Eine DLL freigeben. (CallBack)
vielleicht noch ein wichtiger Hinweis, das mit dem PostMessage muss in der Hauptunit stehen, von welcher das Handle stammt....
|
Re: Eine DLL freigeben. (CallBack)
Hi,
ich glaube, dass hat nichts mit der "Haupt-Unit" (was immer das ist) zu tun, sondern, dass du die Konstante als privaten Klassenmember deklariert hast. Somit ist sie nur innerhalb der Unit in der sie deklariert ist verfügbar. Ich deklariere diese Sachen immer global. Macht auch irgentwie mehr Sinn, denn ich sende solche Botschaften in der Regel von anderen Formularen. Gruß oki |
Re: Eine DLL freigeben. (CallBack)
Ein paar Anmerkungen:
- Diese Konstantendefinition für die Message kann sonstwo stehen, du kannst diese einmal in der Hauptunit deklarieren und dann nochmal in der DLL. Problem ist einfach nur, dass du bei einer Änderung der Message ID zwei Quellen aktualisieren musst und somit eine Fehlerquelle mehr vorhanden ist. Abhilfe schafft hier am besten wie von oki vorgeschlagen, eine Unit zu bauen, welche im Interface Abschnitt einfach nur diese Konstantendefinition enthält und dann vom Formular der App genauso angezogen werden kann wie von der DLL. - Du benutzt beim Aufruf der DLL die globale Variable der Mainform innerhalb ihrer eigenen Methode. Das ist böse, sehr böse. Übergebe das Handle direkt, schliesslich befindest du dich in der Methode des Form, somit einfach nur Handle beim Aufruf oder halt Self.Handle, aber nicht mainform.Handle. - Ich verstehe den Kommentar zu dem Library Handle Field in der Mainform Klasse nicht. Warum muss das eine static var sein? Hast du mehrere Mainforms? - Warum hast du das Mainform Handle als globale Variable innerhalb der DLL abgelegt und nicht als Member in dem Formular an sich? Schliesslich weist du den Member innerhalb der Methoden zu und benutzt ihn ausschliesslich innerhalb der Klasse. |
Re: Eine DLL freigeben. (CallBack)
1: das habe ich nur halb verstanden :-( also ich kann eine konstante in der laufzeit doch nicht verändern.
2: beim aufruf von Self.Handle oder Handle wird die DLL nicht freigegeben (Das habe ich jedenfalls im Debugger gesehen). Bessere Lösung die auch funktioniert ? 3: ne in diesem Beispiel nicht 4: klar hätte ich das auch in den public Teil packen können, private wäre problematisch da CreateDLL nicht in einer Klasse sein darf, jedenfalls habe ich das noch nicht geschaft, also damit das im Export teil klappt... EDIT: Bischen doof das man den Titel nach 24h nicht mehr ändern kann, weil CallBack passt zwar noch aber PostMessage oder Windows Message etc. wäre "richtiger"... |
Re: Eine DLL freigeben. (CallBack)
Hi,
Muetze meint folgendes: 1.
Delphi-Quellcode:
so:
type
TMainForm = class(TForm) bDllLaden: TButton; bClose: TButton; procedure bCloseClick(Sender: TObject); procedure bDllLadenClick(Sender: TObject); private // die Variable muss global gespeichert werden damit FreeLibrary ein Ziel hat class var hLib:cardinal; const wm_FreeMyLibrary = wm_User + 100; /// hier nicht public
Delphi-Quellcode:
So ist deine Konstante global definiert und gilt in allen Units deines Projektes in denen du unter uses My_Types angibst.
unit My_Types;
interface const wm_FreeMyLibrary = wm_User + 100; ........ implementation end; 2.
Delphi-Quellcode:
Wenn du hier die globale Variable benutzt (die delphi immer automatisch mit anlegt), dann kann es passieren, dass diese nicht definiert ist. Das ist vor allem dann der Fall, wenn du an anderer Stelle die Form kreierst und da eine andere Variable verwendet wird. Mache ich immer bei Formularen, die ich zur Laufzeit erstelle. Dann lösche ich im Projekt sogar die globale Variablendeklaration um sie nicht versehentlich zu verwenden.
// nun wird zusätzlich das handle übergeben, was später benötigt wird
THEN Mcreatedll(self.Handle); Man sollte es sich eh angewöhnen immer self und nicht eine Objektvariable in der Klasse für den Zugriff auf eigene Eigenschaften und Methoden zu verwenden. Jo, das war mein Teil dazu. Gruß oki |
Re: Eine DLL freigeben. (CallBack)
Ah... jetzt hab ich's gerafft... danke :thumb:
|
Re: Eine DLL freigeben. (CallBack)
Joa, ist ja nun schon alles geklärt. Zu dem 4. Punkt: ich habe mich geirrt und übersehen bzw. nicht dran gedacht, dass CreateDLL() natürlich klassenlos ist und somit hast du natürlich vollkommen Recht. Ich ziehe meinen 4. Punkt wegen Unsinn am Code zurück...
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:04 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz