AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Interface aus DLL mit dynamischer Bindung - wann FreeLibrary aufrufen?

Interface aus DLL mit dynamischer Bindung - wann FreeLibrary aufrufen?

Ein Thema von DeddyH · begonnen am 24. Aug 2015 · letzter Beitrag vom 25. Aug 2015
Antwort Antwort
Seite 1 von 2  1 2   
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.459 Beiträge
 
Delphi 11 Alexandria
 
#1

Interface aus DLL mit dynamischer Bindung - wann FreeLibrary aufrufen?

  Alt 24. Aug 2015, 15:25
Ich versuche mich gerade an einer Art Plugin-System. Dabei soll eine DLL ein Interface zurückgeben. Das sieht im Moment so aus:
Delphi-Quellcode:
library Blabla;

uses MyIntf, MyClass; //Units, in denen das Interface und die implementierende Klasse stehen

{$R *.res}

procedure GetDings(out Dings: IDings); stdcall; export;
begin
  Dings := TDings.Create;
end;

exports
  GetDings;

begin
end;
Allerdings soll es mehrere DLLs geben, die verschiedene IDings-Klassen zurückliefern, daher binde ich diese dynamisch (LoadLibrary, GetProcAddress). Klappt soweit, aber der ordentliche Mensch denkt sich: wer LoadLibrary sagt, muss auch FreeLibrary sagen. Bei einem ersten Versuch hat es nur dann keine AV gegeben, wenn ich dies in einen Klassendestruktor verfrachtet habe. Es soll aber auch möglich sein, verschiedene DLLs nacheinander anzusprechen, da würde ich mir auf diese Weise ja jedesmal das Handle überschreiben und könnte somit nur das letzte wieder freigeben. Wo ist denn mein Denkfehler bzw. was könnte ich vergessen haben? Lasse ich FreeLibrary ganz weg, fluppt alles super, aber verschwende ich so keine Ressourcen?
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von baumina
baumina

Registriert seit: 5. Mai 2008
Ort: Oberschwaben
1.275 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Interface aus DLL mit dynamischer Bindung - wann FreeLibrary aufrufen?

  Alt 24. Aug 2015, 15:36
Ich merk mir die Handles in einer Liste, um sie dann mit FreeLibrary freigeben zu können.
Hinter dir gehts abwärts und vor dir steil bergauf ! (Wolfgang Ambros)
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.076 Beiträge
 
Delphi 10.3 Rio
 
#3

AW: Interface aus DLL mit dynamischer Bindung - wann FreeLibrary aufrufen?

  Alt 24. Aug 2015, 15:37
Übergibt Deiner Interface erzeuge Routine eine Backcall für den FreeLibary

Wenn das Interface Refcount 0 ist, wird der Destructor aufgerufen und der ruft - als letztes - den FreeLib auf.
(Asynchron wegen dem Return auf den Aufrufer)!
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#4

AW: Interface aus DLL mit dynamischer Bindung - wann FreeLibrary aufrufen?

  Alt 24. Aug 2015, 15:38
Resourcen verschwenden würdest du zwar keine, wenn das FreeLibrary sowieso erst bei Beendigung deines Programms aufgerufen würde, aber mit ist es natürlich schon sauberer.

Ohne mehr Code kann ich leider nicht viel sagen, aber ich vermute mal, dass das implizierte _Release von Delphi dir da einen Strich durch die Rechnung macht. Hast du sichergestellt, dass deine Interface-Instanzen vor dem FreeLibrary jeweils einmal manuell auf nil gesetzt wurden? Ansonsten könnte es passieren, dass die DLL entladen wird und danach impliziert _Release (und damit der Destructor) der aus dem Scope-laufenden Objekte gecallt wird. Da zu diesem Zeitpunkt die DLL dann schon entladen ist, gibt es an dieser Stelle die AV.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.459 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: Interface aus DLL mit dynamischer Bindung - wann FreeLibrary aufrufen?

  Alt 24. Aug 2015, 15:51
Ich bau mal ein Beispiel.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.459 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Interface aus DLL mit dynamischer Bindung - wann FreeLibrary aufrufen?

  Alt 24. Aug 2015, 16:15
War ja klar: im Beispiel funktioniert alles , der Fehler muss also an einer anderen Stelle liegen. Ich forsche mal weiter.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#7

AW: Interface aus DLL mit dynamischer Bindung - wann FreeLibrary aufrufen?

  Alt 24. Aug 2015, 16:38
Du könntest meine Theorie relativ einfach testen, indem du im Destructor deiner Objekte (die aus der DLL) mal eine MessageBox einbaust. Dann ersetzt du das FreeLibrary durch eine weitere MessageBox.

Erscheint jetzt die FreeLibrary Message vor der Message aus dem Destructor, weißt du, dass irgendwo noch Objektinstanzen existieren, die vor dem FreeLibrary nicht freigegeben werden.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.459 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Interface aus DLL mit dynamischer Bindung - wann FreeLibrary aufrufen?

  Alt 24. Aug 2015, 17:00
Hab ich gemacht, die Reihenfolge stimmt: zuerst werden die DLL-Objekte freigegeben, danach käme der FreeLibrary-Aufruf. Mittlerweile ist es genau andersherum als eingangs geschildert: wenn ein neuer DLL-Name zugewiesen wird, klappt ein Nullen des alten Objektes mit anschließendem FreeLibrary einwandfrei, nur im Destruktor nicht mehr. Das alles aber nur im echten Projekt, das Referenzbeispiel funktioniert ohne Murren.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.459 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Interface aus DLL mit dynamischer Bindung - wann FreeLibrary aufrufen?

  Alt 24. Aug 2015, 20:33
So, zu Hause nochmal unter XE7 nachgebaut und schon den ersten Fehler gefunden (Verwendung von string statt Widestring). Aber auch hier klappt es nur, wenn ich das FreeLibrary auskommentiere. Ich habe den Verdacht, dass ich eine ganz entscheidende Kleinigkeit vergessen habe (das ist zugegebenermaßen mein allererster Versuch in dieser Richtung). Ich hänge meine Demo mal an, jemand mit mehr Erfahrung auf dem Gebiet sieht das evtl. sofort.
Angehängte Dateien
Dateityp: zip Demo.zip (11,7 KB, 9x aufgerufen)
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
SMO

Registriert seit: 20. Jul 2005
178 Beiträge
 
Delphi XE6 Professional
 
#10

AW: Interface aus DLL mit dynamischer Bindung - wann FreeLibrary aufrufen?

  Alt 25. Aug 2015, 01:59
Delphi-Quellcode:
procedure TfrmMain.btnLoadClick(Sender: TObject);
type
  TLoadProc = procedure(out Person: IPerson); stdcall;
var
  DLLHandle: NativeUInt;
  PersonProc: TLoadProc;
  Person: IPerson;
  Item: TListItem;
begin
// ...
              while not Person.Eof do
                begin
                  Item := lvChildren.Items.Add;
                  Item.Caption := Person.Child.Name;
                  Item.SubItems.Add(DateToStr(Person.Child.Birthdate));
                  Person.Next;
// ...
    finally
      Person := nil;
      FreeLibrary(DLLHandle);
    end;
end;

Das Problem ist folgendes:
Person.Child liefert ein Interface (IChild). Das wird hier aber nicht in einer lokalen Variable gespeichert, sondern es wird gleich auf eine Eigenschaft zugegriffen (Name, Birthdate). Damit die automatische Referenzzählung funktioniert, muss Delphi aber trotzdem jede Interface-Instanz in einer unsichtbaren lokalen Variable speichern (hier also 2x IChild), die dann am Ende der Subroutine in einem impliziten "finally" Block freigegeben werden.
FreeLibrary wird aber vorher ausgeführt, d.h. es wird auf Ressourcen zugegriffen, die nicht mehr verfügbar sind. Daher die Zugriffsverletzung.

Lösung: Person.Child explizit in einer Variable speichern und die Referenz ebenfalls vor FreeLibrary freigeben.

Delphi-Quellcode:
procedure TfrmMain.btnLoadClick(Sender: TObject);
type
  TLoadProc = procedure(out Person: IPerson); stdcall;
var
  DLLHandle: NativeUInt;
  PersonProc: TLoadProc;
  Person: IPerson;
  Child: IChild;
  Item: TListItem;
begin
// ...
              while not Person.Eof do
                begin
                  Item := lvChildren.Items.Add;
                  Child := Person.Child;
                  Item.Caption := Child.Name;
                  Item.SubItems.Add(DateToStr(Child.Birthdate));
                  Person.Next;
// ...
    finally
      Person := nil;
      Child := nil;
      FreeLibrary(DLLHandle);
    end;
end;

Falls die DLL übrigens erkennen soll, wann sie geladen oder freigegeben wird, dann geht das ungefähr so.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 05:15 Uhr.
Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf