[Verschieben!] LoadLibrary/FreeLibrary: Wann darf ich eine dll wieder "entladen" ?



  • Hallo,

    ich habe eine DLL die mir ein Objekt mit einer Factory baut, welches einem bestimmten pure virtual interface genügt.
    Etwa so:

    class Interface {
    public:
        virtual ~Interface() {}
        virtual bool foo(int bar) = 0;
    };
    
    // in einer DLL:
    class Implementation : public Interface {
    public:
         Implementation(int i):baz(i) {}
         bool foo(int bar) { return (bar == baz); }
    private:
         int baz;
    };
    
    DLL_EXPORT Interface* factory(int i) { return new Implementation(i); }
    
    // im Hauptprogramm
    // Fehlerbehandlung der Einfachheit halber weggelassen
    typedef Interface* (*function_type)(int i);
    HMODULE lib = LoadLibrary("Factory.dll");
    function_type factory = (function_type)(GetProcAddress(lib, "factory"));
    Interface* instance = (*factory)(42);
    

    Soweit, so gut. Jetzt meine Frage: Wenn ich jetzt

    FreeLibrary(lib);
    

    mache, gibts dann das Objekt, auf das Instance zeigt, noch?

    Philipp



  • Ups, falsche Kategorie. Kann das mal jemand nach WinAPI verschieben ??? Danke!



  • Hallo Philipp

    Soweit, so gut. Jetzt meine Frage: Wenn ich jetzt FreeLibrary(lib) mache,
    gibts dann das Objekt, auf das Instance zeigt, noch?

    Ja, in deinem Beispiel schon, hängt aber von der Implementierung der dll ab.

    Oft wird soetwas extra so implementiert daß die erzeugten Objekte
    in der DLL in statischen Listen gehalten werden und dann beim free library freigeben werden.

    Gruß Frank



  • Hallo Frank,

    da ich Hauptprogramm und lib ja selbst schreibe, hängt die Implementierung von mir ab 🙂
    Also wenn ich keine intelligenten Zeiger oder irgenwelche lokalen Speicherpools oder Tabellen verwende, sonder einfach nur stumpf mit new ein Objekt erzeuge und den Pointer rausgebe, lebt das auch nach dem FreeLibrary()-call noch?

    Philipp



  • einfach nur stumpf mit new ein Objekt erzeuge und den Pointer

    ne Dll ist eigentlich nur Code (CodeSegment) der in deinem Speicherbereich eingeblendet wird, das sollt keinen einfluss auf den HEAP oder stack haben. Erst recht wird nix automatisch freigegeben.

    bei deinem Object ergibt sich daher ne wesentliche frage:
    Wo liegen die definitionen der Methoden des Objects, bzw wo sind die gelinkt ...

    sinds in der exe, oder in ner anderen DLL gibts kein problem. Du hasst das new nur in die dll deligiert, der rest sollte in der Exe wieter funktionieren.

    sind die in der dll, und die dll entlaed es, bleibt dein speicher zwar unangetastet, aber jeder aufruf einer methode des Objects bzw. auch ein delete durch den destructor wird dir nen boesen crash bringen, da in deinem angesprungenen code mittlerweile sonstwas liegt ...

    Diese Antwort auf deine Frage kann aber eigentlich nur hypotetisch sein. Selbst wenn es technisch funktioniert, heisst es das man es auch machen sollt.

    C++ Coding style:
    rohes new und delete meiden !
    new und dazugehoeriges delete immer in Bloecken mit gleichen Context (selber Block, oder CTor / Dtor Paar).
    Smartpointer bevorzugen !

    Ciao ...



  • RHBaum schrieb:

    sind die in der dll, und die dll entlaed es, bleibt dein speicher zwar unangetastet, aber jeder aufruf einer methode des Objects bzw. auch ein delete durch den destructor wird dir nen boesen crash bringen, da in deinem angesprungenen code mittlerweile sonstwas liegt ...

    Danke, genau das wollte ich wissen. Ich darf die DLL also erst entladen, wenn ich das Objekt deleted habe und nicht mehr damit arbeite. Und ja, die konkrete Implementierung wird das wahrscheinlich über einen intelligenten Zeiger machen.

    Danke,
    Philipp

    PS: Gibt's hier keinen Moderator oder warum hat das niemand verschoben? Ist ja kein MFC.



  • Hallo Phillip,

    c++ ist keine gute Idee für ein dll Interface.

    neben dem Problem,
    das RHBaum angesprochen hat gibt es noch reichlich andere Probleme.
    Sehr guter Hinweis RHBaum 👍

    Selbst bei C sollten im Interface keine Strukturen stehen sonst
    kann auch wer weiß was passieren.

    Hintergrund für beides ist das man bei einer dll automatisch denkt
    man kann die dll updaten ohne das exe neu zu bauen.

    Wenn man das tut und Structs oder Class definitionen im Header hat,
    dann wird es früher oder später 'knallen' und man hat UB.
    Alternativ muss daß exe immer genau mit dem passenden Header kompiliert werden.
    Um das UB zu verhindern sollte im Header eine Versions Konstante stehen
    und die DLL einer Funktion anbieten um die 'gleiche' Konstante aus der DLL auslesen zu können. Man kann dann die kompile Konstante mit der DLL Konstante
    vergleichen und UB verhindern.

    Oder (besser): Im Header (Interface) nur primitives und pointer auf primitives
    und klassische C Funktionen. Oft werden noch nicht einmal Pointer genommen,
    sondern 'Handels', das halte ich bei interer Verwendung nicht unbedingt für erforderlich. Sollte aber jemand externes, andere Firma, ... auf die DLL zugreifen ist auch das ratsam.
    Bei Erweiterungen kommen nur neue Funktionen hinzu,
    das alte C Interface bleibt zu 100 % erhalten.
    In der dll selbst kann man dann wieder vollständig c++ Verwenden,
    auch der Anwender kann vollständiges c++ verwenden.

    Ich jedenfalls verwende kein C++ mehr im Interface und auch keine C Strukturen.

    Gruß Frank



  • Dieser Thread wurde von Moderator/in Unix-Tom aus dem Forum MFC (Visual C++) in das Forum WinAPI verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • c++ ist keine gute Idee für ein dll Interface.

    Wenn du wuesstest wie recht Du damit hasst 🙂
    Aber leider isses ne Philosphiefrage.
    Und C wird oft als veraltet angesehen (ich musst mir deswegen scho Dinge anhoeren .. )
    Aber die dlls, die immer laufen, die man nie updaten muss auch wenn man mal ein Framework updated ... das sind dlls mit C interfaces 🙂
    Problem iss halt oft auch, das zwar nen C-Interface haben kannst, wenn aber intern ne framework nutzt, und es nicht statisch zur dll kompilierst, bist auch wieder abhaengig vom framework.
    Wobei man das C++ Interface Problem meist nur bei windows hat. Unter *nixe gibts ja den systemcompiler ....

    Wenn man das tut und Structs oder Class definitionen im Header hat,
    dann wird es früher oder später 'knallen' und man hat UB.

    WO das her hasst weiss ich aber ned 🙂
    Class ist soweiso c++, das steht ausser disskussion.
    Aber structs sind unkritisch fuer schnittstellen !
    sie brauchen keinen code um zu leben, bzw der wird erstellt sobald man ihn braucht, in jeder uebersetzungseiheit.
    Speicher Ausrichtung sowie format sind fuer structs sehr wohl binaer definiert !
    Schau dir mal die winapi an, da wimmelts von structs. Und die winapi ist wirklich reines C und zu C binaerkompatibel.

    oder hab ich structs nur falsch verstanden ...

    Ciao ...



  • Hallo RHBaum,
    Hallo an alle dll entwickler.

    dlls sind u.a. dazu gedacht von mehreren Programmen verwendet zu werden.
    dlls sind auch dazu gedacht Erweiterungen der dll durchzuführen,
    ohne ALLE Programme neu bauen zu müssen.
    Will man beides (irgendwann) haben sind Structs und Klassen verboten,
    es geht schlichtweg nicht (ich kann nichts dafür 😞 ).
    Wer beides nicht braucht programmiert eine statische lib und
    kann dann structs und c++ verwenden.

    Warum ?

    Structs im Header sind dann extrem gefählich, wenn man die dll erweitern möchte,
    aber das ein oder andere exe z.B. nicht neu bauen will weil man z.B. diese spezielle Erweiterung nicht braucht.

    Wird das Struct nun z.B. um einen int erweitert,
    so ändert sich die Structsize um z.B. 4 Bytes.

    Das exe ist aber gegen das alte Struct kompiliert und hat die alte size reserviert (Heap, Stack, ..). Ruft man nun StructInit in der DLL auf hat man UB und es knallt.

    Deswegen Vorwärts deklarieren, die interna vom Struct verheimlichen und nur pointer, oder besser noch Handles im Header haben.
    Der Speicher wird in der DLL auf dem Heap angelegt und auch in der dll wieder freigeben, das exe reserviert nur 4 Bytes für den Pointer oder das Handle.
    Die Daten müssen alle mit gettern und setter abgefragt werden.
    Hier werden primitives zurückgegeben, bzw. Pointer/Handles womit dann wieder mit gettern und setter gearbeitet wird ...

    Anderes Beispiel:
    man ändert die Reihenfolge der Parameter im Struct,
    z.B. um eine kleinere Structsize zu erreichen.
    Wenn du das exe dann nicht neu baust, passiert auch alles, nur nicht das was gedacht war.

    Richtig lustig wird es erst mit Klassen im dll Header,
    am lustigsten mit einer abgeleiteten Klassenhierarchie.
    Wenn du dann eine neue Methode in einer Basisklasse einfügst und das exe nicht neu baust,
    Werden einfach die falschen Funktionen angesprungen, natürlich mit den komplett falschen Daten auf dem Stack.

    Gruß Frank


Anmelden zum Antworten