Dll Fragen



  • dllll schrieb:

    wenn du das objekt löschst kann es zu einem zugriffsfehler kommen, da
    das objekt im speicherraum der dll liegt.

    dann musst du nur eine löschfunktion exportieren

    void Destroy(test *t)
    {
        delete t;
    }
    

    Wenn das Objekt einen virtuellen Destruktor hat, ist das nicht nötig; siehe hier.

    YaDllNub schrieb:

    Wenn ich so eine quasi C-Schnittstelle (Create, Destroy) in der Dll habe, kann ich diese Dll dann mit jedem C++-Compiler nutzen (normal geht das ja nicht bei Klassen)?

    Nein, das ist nach wie vor compilerspezifisch, da vom C++-Standard kein ABI vorgeschrieben ist. Für so etwas muß entweder eine C-Schnittstelle oder COM verwendet werden.


  • Mod

    audacia schrieb:

    YaDllNub schrieb:

    Wenn ich so eine quasi C-Schnittstelle (Create, Destroy) in der Dll habe, kann ich diese Dll dann mit jedem C++-Compiler nutzen (normal geht das ja nicht bei Klassen)?

    Nein, das ist nach wie vor compilerspezifisch, da vom C++-Standard kein ABI vorgeschrieben ist. Für so etwas muß entweder eine C-Schnittstelle oder COM verwendet werden.

    Nein muss man nicht. Man kann auch dieses Interface Cmpiler neutral aufbauen. Macht COM ja auch!

    Ich wüsste aktuell keinen C++ Compiler, der keine COM Interfaces unterstützt, die nicht mit einer reinen virtuellen Interface Klasse identisch sind.
    Oder weißt Du da gegenteiliges?



  • Alternativ kann man in der Dll auch mit einem Objekt arbeiten und von außerhalb mit normalen API-Funktionen darauf zugreifen. Ein Beispiel ohne Fehlerbehandlung:

    HANDLE CreateObject()
    {
        CTest* pTest = new CTest;
        return reinterpret_cast<HANDLE>(pTest);
    }
    
    BOOL DoSomething(HANDLE hTest, int iParam1, int iParam2)
    {
        return reinterpret_cast<CTest*>(hTest)->DoSomething(iParam1, iParam2);
    }
    
    void DestroyObject(HANDLE hTest)
    {
        delete reinterpret_cast<CTest*>(hTest);
    }
    


  • Martin Richter schrieb:

    Nein muss man nicht. Man kann auch dieses Interface Cmpiler neutral aufbauen. Macht COM ja auch!

    Ich wüsste aktuell keinen C++ Compiler, der keine COM Interfaces unterstützt, die nicht mit einer reinen virtuellen Interface Klasse identisch sind.
    Oder weißt Du da gegenteiliges?

    Na, dann viel Vergnügen damit:

    • sind die Destruktor-Parameter standardisiert?
    • kann es sein, daß einige Compiler eine Klasse nur dann an die COM-Spezifikation anpassen, wenn sie dazu explizit aufgefordert werden (also wenn du explizit eine COM-Klasse erstellst)?
    • wie sehen VTable und RTTI-Descriptor aus, wo im Objektlayout wird auf sie verwiesen?
    • ist das Klassenlayout eindeutig? Im BCC gibt es beispielsweise zwecks Abwärtskompatibilität diverse Optionen, um das Objektlayout an frühere Versionen anzupassen.
    • wie setzt der Compiler Mehrfach- und virtuelle Vererbung um?
    • was passiert, wenn das Klasseninterface mit Iteratoren, Containern oder anderen Dingen der Standard-Library arbeitet?
    • etc. pp.

    Daß die gängigen Compiler COM unterstützen, heißt noch lange nicht, daß sie immer binärkompatible Klassenlayouts erzeugen.



  • sri schrieb:

    Alternativ kann man in der Dll auch mit einem Objekt arbeiten und von außerhalb mit normalen API-Funktionen darauf zugreifen. Ein Beispiel ohne Fehlerbehandlung:

    <snip>
    

    So ähnlich funktioniert das z.B. in COM+. Dort gibt es zusätzlich noch Klassen-Wrapper, die vollständig im Header implementiert sind - auch eine Möglichkeit, wenngleich sehr arbeitsintensiv.

    Ein Programm, das diesen Prozeß automatisiert und all diese Wrapperklassen und -funktionen zu generieren imstande ist, wäre reizvoll 🙂


  • Mod

    Mir ging es in keiner Weise um RTTI und virtuele Destruktoren! Geau das ist der Punkt.

    Wenn ich nur mit

    class IFoo
    {
    public:
     virtual void Foo1() = 0;
     virtual void Foo2(int i) = 0;
     virtual void Foo32(char *p) = 0;
    };
    

    eine Interface Klasse anlege und nur deren Zeiger austtausche, dürte es nicht schwierig sein mit allen Compilern eine entsprechende Funktionalität zu erzeugen.
    Jetzt brauche ich nurnoch ene Factory zum Erzeugen UND Zerstören, denn auf einen virtuelen Destruktor kann ich mich eben nicht verlassen... 😉

    Alle Deine Einwürfe (RTTI, virtueller Destruktor, Mehrfachvererbung) lass ich gelten, aber ich will Sie ja nicht nutzen. Genauso wenig wie sie COM nutzt!

    Meine Frage war:
    Welcher Compiler würde mit soetwas nicht zurande kommen, vorrausgesetzt man bekomt auch die Calling Konventions über entsprechende #defines übereinander.



  • Martin Richter schrieb:

    Wenn ich nur mit

    class IFoo
    {
    public:
     virtual void Foo1() = 0;
     virtual void Foo2(int i) = 0;
     virtual void Foo32(char *p) = 0;
    };
    

    eine Interface Klasse anlege und nur deren Zeiger austtausche, dürte es nicht schwierig sein mit allen Compilern eine entsprechende Funktionalität zu erzeugen.
    Jetzt brauche ich nurnoch ene Factory zum Erzeugen UND Zerstören, denn auf einen virtuelen Destruktor kann ich mich eben nicht verlassen... 😉

    Das mag soweit sogar funktionieren, aber IMHO ist gerade der Punkt mit dem Destruktor essentiell, weil er verhindert, daß der Zeiger in einem herkömmlichen Smart-Pointer untergebracht werden kann. Eine Wrapperklasse könnte hier Abhilfe schaffen (vielleicht ähnlich wie DelphiInterface<> in C++Builder?).

    Weiter wäre zu verifizieren, daß ein Klassenlayout in jedem Fall COM-kompatibel ist, auch wenn die Klasse nicht explizit als COM-Klasse deklariert wurde.

    Martin Richter schrieb:

    Meine Frage war:
    Welcher Compiler würde mit soetwas nicht zurande kommen, vorrausgesetzt man bekomt auch die Calling Konventions über entsprechende #defines übereinander.

    Wie gesagt: das bleibt zu überprüfen. Das werde ich bei Gelegenheit mal angehen, da die Frage mich auch interessiert. (Es ist btw sogar möglich, wenngleich nur mit C++Builder, auf ähnlichem Wege C++-Objekte in Delphi zu verwenden, insofern ist es ganz unwahrscheinlich nicht.)


  • Mod

    audacia schrieb:

    Das mag soweit sogar funktionieren, aber IMHO ist gerade der Punkt mit dem Destruktor essentiell, weil er verhindert, daß der Zeiger in einem herkömmlichen Smart-Pointer untergebracht werden kann. Eine Wrapperklasse könnte hier Abhilfe schaffen (vielleicht ähnlich wie DelphiInterface<> in C++Builder?).

    Selbst dies kann man mit einem eigenen Design sofort ösen, wenn z.B. in der Klasse selbst eine Methode Delete engebaut würde. Eine Smartpointer Klasse wäre hier in 2 Minuten geschrieben.

    Ich habe es sogar schon mal so weit gemacht, dass ich die COM Technologie in dem Sinne kopiert habe in dem ich selbst eine eigene Basis IUnknown-like Klasse genutzt habe inkl. Refrence Counting.
    Wen interessiert schon der ganze COM Overhead bzgl. Marshalling, Appartments und Klassenregistierung 🤡
    Man kann COM sofort clonen ohne selbst auch nur ein Stück COM nutzen zu müssen. Und schon kann man z.B. CComPtr verwenden 😉

    Für eine "Adapter-like" Techonolgie in meiner Software habe ich das sehr erfolgreich ausgenutzt. Allerdings hier alles komplett mit VS und unter Windows!



  • Man kann auch in wenigen Minuten Reference-Counting implementieren und dann einfach boost::intrusive_ptr verwenden 😉
    Das geht dann auch wenn die Funktionen nicht gerade AddRef und Release heissen.



  • Martin Richter schrieb:

    Selbst dies kann man mit einem eigenen Design sofort ösen, wenn z.B. in der Klasse selbst eine Methode Delete engebaut würde. Eine Smartpointer Klasse wäre hier in 2 Minuten geschrieben.

    Das ist mir schon klar. Aber die bestehenden lassen sich nicht nur nicht verwenden, sondern das muß gar unterbunden werden.

    Martin Richter schrieb:

    Ich habe es sogar schon mal so weit gemacht, dass ich die COM Technologie in dem Sinne kopiert habe in dem ich selbst eine eigene Basis IUnknown-like Klasse genutzt habe inkl. Refrence Counting.
    Wen interessiert schon der ganze COM Overhead bzgl. Marshalling, Appartments und Klassenregistierung 🤡
    Man kann COM sofort clonen ohne selbst auch nur ein Stück COM nutzen zu müssen. Und schon kann man z.B. CComPtr verwenden 😉

    So ein Ansatz hat zudem den Vorteil, daß er sich auch unter Nicht-Windows-Systemen implementieren ließe.

    Einen wichtigen Punkt habe ich übrigens noch vergessen: Exceptions. Wenn du verschiedene Compiler benutzt, mußt du zumindest ein rudimentäres Exception-Marshaling implementieren. Wenn eine Exception aus dem Code des einen Compilers in den des anderen gerät, dürften zwar, da vermutlich alle Windows-Compiler C++-Exceptions mittels SEH implementieren, die Destruktoren korrekt aufgerufen werden, aber die Exception wird nie gefangen werden können.


  • Mod

    audacia schrieb:

    Einen wichtigen Punkt habe ich übrigens noch vergessen: Exceptions. Wenn du verschiedene Compiler benutzt, mußt du zumindest ein rudimentäres Exception-Marshaling implementieren. Wenn eine Exception aus dem Code des einen Compilers in den des anderen gerät, dürften zwar, da vermutlich alle Windows-Compiler C++-Exceptions mittels SEH implementieren, die Destruktoren korrekt aufgerufen werden, aber die Exception wird nie gefangen werden können.

    Das ist absolut korrekt. Das ganze darf über diese Schnittstelle keine Exceptions werfen... Wie bei COM!



  • Zumindest diese Einschränkung ist mir hinreichend gravierend, so daß ich jetzt einen Workaround suchen gehe 😉


Anmelden zum Antworten