Mit Shared Libs auf Funktionen im Hauptprogramm zugreifen?



  • mit vmt meinst du die virtual method table? nur um sicherzugehen.

    ja, stimmt. die könnte sich verändern. wahrscheinlich auch dann, wenn man ableitet.
    aber eigentlich sollte die sich nicht mit jeder neuen methode vergrößern, die reservieren meist mehr platz als nötig. aber das ist dann natürlich compilerabhängig. also eher unsicher und damit unbrauchbar.

    wie wäre es, wenn du für neue funktionalitäten neue klassen einführst und dazu auch passende myfuncs, dann kannst du daran entscheiden, welche klasse die dll haben will und übergibst eben die entsprechende.
    dann ändert sich die gemeinsame header datei nicht mehr..

    warum hast du eigentlich zwei client.h dateien gepostet?

    ciao,
    jenz



  • Gibt da zwei Möglichkeiten die mir einfallen:
    a) Du fügst neue Funktionalität hinzu indem du ein neues Interface erstellst, dass das alte erbt, dann können neue Plug-Ins das neue nehmen und alte Plug-Ins laufen weiterhin, ungefähr so:

    class SocketInterfaceVersion1
    {
      public:
      //Methoden
    };
    
    class SocketInterfaceVersion2 : public SocketInterfaceVersion1
    {
      public:
      //Neue Methoden
    };
    

    b) Du benutzt die Interfaces nicht mehr direkt sondern über Proxies welche automatisch für jedes Plug-In die passende Version raussuchen.
    Einen Artikel dazu gibts hier



  • Ja, die Virtual Method Table meinte ich. Die wird ja inkonsistent, wenn ich im Hauptprogramm eine neue virtuelle Methode hinzufüge, in der DLL aber nicht.

    Ich hab zwei client.h gepostet, weil die eine die ist, die in der DLL verwendet wird und die andere die, die im Hauptprogramm verwendet wird.

    Mit den Proxys, das schau ich mir mal an, das könnte eventuel was sein.



  • @FloFri

    Du exportierst Klassen (auch wenns nur C++ Schnittstellen, also abstrakte klassen sind). d.h. dein Programm und dein Plugin sollten mit dem selben compiler uebersetzt sein, und paar compilerflags muessen auch uebereinstimmen.

    Prinzipiell sollten dann auch nur rein abstrakte klassen und Zeiger auf diese klassen sowie POD's teil deiner schnittstelle sein. Insbesondere halb auskompilierte klassen und per tamplate generierte klassen sollten nie teil deiner schnittstelle sein. Wenn da bestimmte compilerflags ned 100% identisch sind kanns schon schiefgehen. Zum beispiel sollten std::string und std:: - container kein Bestandteil deiner schnittstelle sein, das macht die compilereinstellungen gefaehrlich ....

    Die Interfaces sollten auch nur in einer ! Headerdatei defininiert werden, welche dann von App und plugin gemeinsam genutzt werden. Sobald dann irgendwie nen unresolved symbol kommt, weil irgendwo ne definition fehlt, dann weisst das an deinen Schnittstellen noch was faul ist ....

    willst du wirkliche unabhaengigkeit bei solchen schnittstellen, wirst um plain c nicht drumherumkommen ... da iss dann alles compilerunabhaengig ...

    Die Reihenfolge in der VMT ist eigentlich definiert ! Und zwar sobald du immer nur funktionen "hintenanhaengst" wird eine aelter version der klassendefinition mit der neuen vmt noch funktionieren. Nur solltest das mit allen mitteln vermeiden. Ableiten dder schnittstellen um zu erweitern ist besser und sicherer.

    Ciao ...



  • #ifndef CLIENT_H
    #define CLIENT_H
    
    #include <string> 
    #include <iostream> // stl header kopf einer schnittstelle sind immer nen ganz schlechtes zeichen ! STL dinger sind meist templates -> compilierung bei bedarf 
    
    using namespace std; // das im header iss ne mittlere katastrophe, in nem Interface header potentiert sich das nochmals. Benutzer deiner klassenschnittstelle bekommen hier definitiv namespace konflikte
    
    class Client
    {
        public:
            Client(string initStr);  // std::string - auskompiliertes Template als unbergabeparameter ... wenn hier die compilerflags ned stimmen ... 
            virtual ~Client();
            virtual void ShowString();
    };
    
    #endif // CLIENT_H
    

    Besser:

    Client_if.h

    class IClient
    {
    protected:   // annahme, nur deine Anwendung soll IClients erstellen koennen 
        // leerer CTor und DTor 
        IClient(){}
        virtual ~IClient(){}
    public:
        virtual void ShowString() = 0;
    };
    

    Das waer deine schnittstelle, ... nun brauchst noch ne Impl dazu
    ClientImpl.h

    class ClientImpl : public IClient
    {
    public:
        ClientImpl(std::string strinit);
        virtual ClientImpl();
    
        // und wir muessen die abstrakte funktion auch definieren .... 
        virtual void ShowString(); // diesmal definiert ! 
    };
    

    die CLientImpl.cpp solltest nu selber hinbekommen

    deine main funktion !

    int main()
    {
        // Client* myCli = new Client("ichbins"); // warum dynamisch ? 
        ClientImpl cli("ich bins!");
        cout << "Loading DLL" << endl;
    
        HINSTANCE dllInstance = LoadLibrary("testdll/testdll.dll");
    
        if (dllInstance == NULL)
        {
            cout << "Can not load!" << endl;
            return 1;
        }
    
        p_myFunc myFunc = (p_myFunc)GetProcAddress((HMODULE)dllInstance, "myFunc");
    
        if (myFunc == NULL)
        {
            cout << "Error" << endl;
            return 1;
        }
    
        cout << "Calling DLL-Function" << endl;
        myFunc(&cli); // hier nu einfach zeiger auf das statiosche objet uebergeben ...
        // wo war in der alten version  das delete ? 
        return 0;
    }
    

    Und in der Dll arbeitest nur noch mit dem Interface !

    auszug aaus deiner dll impl

    / a sample exported function
    void myFunc(IClient *myclitest)
    {
        cout << "Calling Client-Function" << endl;
        myclitest->ShowString();
    }
    

    Prinzip verstanden ?

    Ciao ...


Anmelden zum Antworten