Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Eine DLL freigeben. (CallBack) (https://www.delphipraxis.net/107548-eine-dll-freigeben-callback.html)

geskill 29. Jan 2008 16:59


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?

Muetze1 29. Jan 2008 17:02

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.

geskill 29. Jan 2008 17:08

Re: Eine DLL freigeben.
 
Zitat:

Das Laden sowie freigeben der DLL muss im Hauptprogramm geschehen.
Und WIE?
Die DLL sagt ja wann "Schluss" ist, nicht das Hauptprogramm,
wie kann das Hauptprogramm das mitbekommen,
bzw. wie "sage" ich das dem Hauptprogramm?

Muetze1 29. Jan 2008 17:23

Re: Eine DLL freigeben.
 
Da gibt es mehrere Möglichkeiten, z.B.:

- Windows Message an das Hauptprogramm
- Event triggern
- Callback aufrufen

DeddyH 29. Jan 2008 17:25

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.

geskill 29. Jan 2008 17:35

Re: Eine DLL freigeben.
 
Meinst du mit ShowModal TForm.ShowModal?

Zitat:

Zitat von DeddyH
Wenn die DLL ein Formular anzeigt, muss dies ja mit ShowModal innerhalb der Komponente geschehen.

Wieso müssen? Ich habe ein ganz normales Show.

Delphi-Quellcode:
Addons := TAddons.Create(NIL);
Addons.Show;
Oder sollte man das aus irgendeinem Grund nicht machen, bei mir klappt das wunderbar?

@Muetze1
Das sind doch mal Schlüsselwörter.
Ich werde mich mal durch die Suche wälzen :-)

geskill 29. Jan 2008 20:25

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:
library pDll_CallBack;

uses
  SysUtils,
  Classes,
  uDll_Form in 'uDll_Form.pas' {DllForm};

{$R *.res}

exports
  createdll;

begin
end.
Das DLL Formular
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.

Bernhard Geyer 29. Jan 2008 20:32

Re: Eine DLL freigeben. Mit CallBack
 
Zitat:

Zitat von geskill
Delphi-Quellcode:
procedure TDllForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  DllForm.Free;
  DllForm := NIL;

  // Hier muss das Callback starten
  closedll(AhLib);
end;

Autsch. Du gibts ein Objekt im eigene Close-Eventhandler frei. Das wird dir sowas um die Ohren fliegen da du damit Callstack-Technisch dir eine Nirvana baust. Du könntest maximal Action auf caFree setzen und im Destruktor/OnDestroy-Event diene globale Varfiable DLLForm auf nil setzen und anschließend deinem Hauptprogramm z.B. per Windows-Message einen notifier schicken.

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.

geskill 30. Jan 2008 10:08

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 :-(((

http://www.delphipraxis.net/internal...k+dll+formular

MainForm
Delphi-Quellcode:
  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.
Die DLL.dpr
Delphi-Quellcode:
library pDll;

uses
  SysUtils,
  Classes,
  uDllForm in 'uDllForm.pas' {DllForm};

{$R *.RES}

exports
  CreateDLL;

end.
Und das DLL-Formular
Delphi-Quellcode:
  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.
Muss ich das DLL Formular noch Releasen ? Alse TForm.Release; Oder was mache ich falsch ?

Bernhard Geyer 30. Jan 2008 10:15

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.

geskill 30. Jan 2008 10:21

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?

Bernhard Geyer 30. Jan 2008 10:25

Re: Eine DLL freigeben. (CallBack)
 
Zitat:

Zitat von geskill
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?

Der Teil mit der Freigabe Formular passt, aber du darfst die DLL nicht im Callback freigeben. Verwende wie schon angemerkt einen Event den du der Exe per PostMessage mitteilst.

geskill 30. Jan 2008 10:27

Re: Eine DLL freigeben. (CallBack)
 
argghhh...
dann hat Muetze1 mich auf den falschen Pfad gelockt... :-(((

Bernhard Geyer 30. Jan 2008 10:29

Re: Eine DLL freigeben. (CallBack)
 
Zitat:

Zitat von geskill
argghhh...
dann hat Muetze1 mich auf den falschen Pfad gelockt... :-(((

Häst doch nur seine Vorschläge von oben abarbeiten müssen :-)

Muetze1 30. Jan 2008 10:35

Re: Eine DLL freigeben. (CallBack)
 
Zitat:

Zitat von geskill
argghhh...
dann hat Muetze1 mich auf den falschen Pfad gelockt... :-(((

Wieso? Du kannst über den Callback sehr gut der Anwendung Bescheid geben, dass sie die DLL entladen kann. Ich habe nichts gesagt, dass die Hauptanwendung dies direkt im Callback machen soll. Sie kann sich aus dem Callback die DLL zum freigeben vermerken, etc. Die Hauptanwendung kann zum entkoppelt in dem DLL Callback sich selber per PostMessage entsprechend einen Auftrag senden, etc. Es gibt so viele Möglichkeiten und der Callback ist nun nicht eine ungehbare Version.

Und ich habe zuvor schon eine gewisse Sortierung in Richtung des Umfangs/Schwierigkeit gegeben, da hat Bernhard Geyer schon Recht.

geskill 30. Jan 2008 14:23

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:

Zitat von Muetze1
Und ich habe zuvor schon eine gewisse Sortierung in Richtung des Umfangs/Schwierigkeit gegeben, da hat Bernhard Geyer schon Recht.

Ich habe zum Thema CallBack am meisten gefunden, naja dann werde ich mir jetzt mit "Windows Message an das Hauptprogramm" senden beschäftigen... Hätte nichts gegen links wo dies erklärt wird, hier im Forum und Google spucken nicht so viel aus :(

oki 30. Jan 2008 14:43

Re: Eine DLL freigeben. (CallBack)
 
Hallo,

in der hilfe nach PostMessage suchen. Am besten du definierst dir einen eigene Nachricht
Delphi-Quellcode:
const
  wm_FreeMyLibrary = wm_User + 100;
Abschicken mit
Delphi-Quellcode:
  PostMassage(Mainform.Handle, wm_FreeMyLibrary, 0, 0);
Empfangen in der eigenen Procedure
Delphi-Quellcode:
  procedure WMFreeMyLibrary(var Message: TMsg); message WM_FreeMyLibrary;


procedure TMainForm.WMFreeMyLibrary(var Message: TMsg);
begin
  // DLL frei geben
end;
Gruß oki

geskill 30. Jan 2008 15:25

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:
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;
In der DLL.dpr habe ich nichts verändert nur die export Procedure...

DLL Formular
Delphi-Quellcode:
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;
Und nochmal als Download, damit es auch jeder ausprobieren kann; man bin ich glücklich :dancer: :-D :drunken: :firejump:

oki 30. Jan 2008 15:52

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

geskill 30. Jan 2008 15:57

Re: Eine DLL freigeben. (CallBack)
 
vielleicht noch ein wichtiger Hinweis, das mit dem PostMessage muss in der Hauptunit stehen, von welcher das Handle stammt....

oki 30. Jan 2008 16:02

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

Muetze1 30. Jan 2008 17:00

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.

geskill 30. Jan 2008 17:46

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"...

oki 30. Jan 2008 18:42

Re: Eine DLL freigeben. (CallBack)
 
Hi,

Muetze meint folgendes:
1.
Delphi-Quellcode:
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
so:
Delphi-Quellcode:
unit My_Types;

interface

const
  wm_FreeMyLibrary = wm_User + 100;
........


implementation
end;
So ist deine Konstante global definiert und gilt in allen Units deines Projektes in denen du unter uses My_Types angibst.

2.
Delphi-Quellcode:
   // nun wird zusätzlich das handle übergeben, was später benötigt wird
   THEN Mcreatedll(self.Handle);
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.
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

geskill 30. Jan 2008 18:48

Re: Eine DLL freigeben. (CallBack)
 
Ah... jetzt hab ich's gerafft... danke :thumb:

Muetze1 30. Jan 2008 20:27

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