non-pods über DLL-Grenzen herumreichen



  • PI, was ist "world::chunk" denn für ein Typ? Wenn es eine Klasse ist, dann kann die natürlich von C aus nicht benutzt werden...



  • Ich rufe die Funktion über C++ auf... Daher dürfte es da kein Problem geben.





  • MSDN sagt: http://msdn.microsoft.com/en-us/library/1e02627y%28v=vs.71%29.aspx

    'identifier1' has C-linkage specified, but returns UDT 'identifier2' which is incompatible with C

    A function or pointer to function has a UDT (user-defined type, which is a class, structure, enum, union, or __value type) as return type and extern "C" linkage. This is legal if:

    All calls to this function occur from C++.
    The definition of the function is in C++.

    Damit kann ich das Problem lösen durch:

    #pragma warning(disable: 4190)
    

    🤡



  • 314159265358979 schrieb:

    Damit die Funktion gefunden wird, wenn ich sie laden möchte.

    Dafür hast du doch dllexport!?



  • Das macht sie nur "public", aber durch extern "C" wird der Funktinsname nicht gemangelt.



  • Aber die Funktion returned einen Typ der in einem Namespace liegt!? In dem Moment ist C doch schon gestorben!?



  • Der Rückgabetyp ist dann aber nicht im exportierten Funktionsnamen enthalten...



  • N3242 schrieb:

    Linkage from C++ to objects defined in other languages and to objects defined in C++ from other languages is implementation-defined and language-dependent.



  • Ich benutze die Lib aber nur in C++.



  • eben:

    theta schrieb:

    @pi: Warum schreibst Du überhaupt extern "C" hin?



  • Hab ich doch gesagt: Damit ich die Funktion beim Namen finde.



  • Und was genau bringt dir das, wenn doch sowieso schon alles implementation-defined ist?



  • Versteh ich nicht. Irgendwie muss ich die Funktion ja finden, um sie benutzen zu können?



  • dllimport?



  • Ich glaube du verstehst nicht... Die Funktionen liegen in einer DLL. Nicht alle Funktionen in der DLL müssen vorhanden sein, damit die DLL mit dem Programm zusammenarbeitet. Die Funktion destruct() ist z.B. optional und wird nur aufgerufen, wenn vorhanden.



  • @314159265358979
    D.h. du lädst die DLL dynamisch bzw. holst dir die Funktions-Adressen dynamisch (GetProcAddress)?
    Wenn ja, dann wäre das ne wichtige Info gewesen.

    extern "C" __declspec(dllexport) world::chunk generate(world::chunk::coords);
    

    ->

    extern "C" __declspec(dllexport) world::chunk* generate(world::chunk::coords);
    

    BTW: du solltest aus extern "C" Funktionen auch keine Exceptions werfen. Einige Compiler (wie MSVC mit Default-Einstellungen) gehen nämlich davon aus, dass extern "C" Funktionen keine Exceptions werfen, und erzeugen dann u.U. den für's Stack-Unwinding nötigen Code nicht.
    Und wenn die Funktion dann doch ne Exception wirft, dann kann alles mögliche schief gehen.

    All das kann man aber halbwegs gut umgehen, indem man sich aus der DLL nur ein Interface holt, und alles weitere dann über dieses Interface macht:

    class dll_interface
    {
    public:
        virtual world::chunk generate(world::chunk::coords) = 0;
        virtual bool is_destruct_required() const = 0;
        virtual void destruct(was_auch_immer) = 0; // NOP wenn is_destruct_required() == true
    };
    
    extern "C" __declspec(dllexport) dll_interface* get_dll_interface();
    


  • hustbaer schrieb:

    @314159265358979D.h. du lädst die DLL dynamisch bzw. holst dir die Funktions-Adressen dynamisch (GetProcAddress)?
    Wenn ja, dann wäre das ne wichtige Info gewesen.

    Ja, ich wusste bis vor deinem Post nicht mal, dass man Code aus DLLs auch anders laden kann... Daher bin ich davon ausgegangen, dass das selbstverständlich ist.

    hustbaer schrieb:

    extern "C" __declspec(dllexport) world::chunk generate(world::chunk::coords);
    

    ->

    extern "C" __declspec(dllexport) world::chunk* generate(world::chunk::coords);
    

    Der Chunk selbst ist bereits eine Art Smartpointer, ich will den einfach beim Aufruf der Funktion moven.

    Exceptions werfe ich keine.



  • All das kann man aber halbwegs gut umgehen, indem man sich aus der DLL nur ein Interface holt, und alles weitere dann über dieses Interface macht:

    Kann das nicht Probleme machen wenn die DLLs mit unterschiedlichen Compilern kompiliert wurden? Oder ist das VTable-Layout ähnlich genug um da von soetwas wie binärer Kompatibilität zwischen den Mainstream-Compilern wie MSVC und MinGW zu sprechen?

    Bei einem Plugin-System (Soll es das sein?) halte ich es für wichtig die Beiden zu unterstützen. MSVC nutzen viele, MinGW kann deutlich mehr C++11. Da ist es blöd LKeute auszusperren.



  • @314159265358979
    Das Zurückgeben eines Zeigers war als "Lösung" für die Warning von MSVC gedacht, nicht weil ich vorschlagen wollte dass du Zeiger verwendest.

    Du kannst es natürlich auch über Output-Parameter machen:

    extern "C" __declspec(dllexport) bool generate(world::chunk::coords, world::chunk* out_chunk);
    

    Das ist im Prinzip eh genau das was Compiler intern aus Funktionen mit Returntypen machen die keine eingebauten Typen sind (Zeiger, ints etc.).
    D.h. du kannst da auch "reinmoven" oder was auch immer du willst.

    @Ethon
    Das VTable-Layout ist auf Windows eher kein Problem, da jeder Compiler COM unterstützen möchte, und daher ein COM-kompatibles VTable Layout verwendet.
    Problematisch wird es bei anderen Dingen, z.B. Exceptions, RTTI oder gar der Standard-Library (std::string zwischen DLLs verwenden etc.).

    Ethon schrieb:

    Bei einem Plugin-System (Soll es das sein?) halte ich es für wichtig die Beiden zu unterstützen. MSVC nutzen viele, MinGW kann deutlich mehr C++11. Da ist es blöd LKeute auszusperren.

    Ich würde auf Windows einfach sagen MSVC Version so-und-so, und aus. Wer Plugins entwickeln will, muss sich halt das passende Studio installieren (Express Version ist eh gratis).
    Das machen viele Programme so, und es ist auch für viele Programme ausreichend.

    Wenn man wirklich mal was entwickeln sollte, wo es absolut wichtig ist dass jeder Plugins dafür entwickeln kann, dann sollte man auf C++ sowieso ganz verzichten. Dann kommen IMO nur klassische Win32/C DLLs in Frage, oder automation kompatible COM Interfaces.


Anmelden zum Antworten