Dll +C++ -> C#



  • Hallo,

    muss ich was besonderes beachten, wenn ich eine DLL in C++ baue, welche ich später in C# verwenden möchte ??

    GruzZz



  • Darauf, dass die Funktionen, die später von C# aus genutzt werden sollen, freie Funktionen sind, welche möglichst einfache Datentypen als Parameter und Rückgabewerte haben. Am Besten sind PODs und structs.



  • Und möglichst als reine C-Schnittstellenfunktionen (extern "C") erstellen, damit man keine kryptischen Funktionsbezeichner hat ("Name Mangling").



  • Eine andere Möglichkeit die sich anbietet wäre die C++ DLL als COM Komponente zu machen. Die kann dann in C# sehr einfach benutzt werden.



  • Kommt drauf an ob Du reines C++/CLI verwendest oder eine Mischung aus C++/CLI und nativem C++.

    Fall 1: Reines C++/CLI

    Bei reinem C++/CLI ist es genauso wie eine C# Library, nur in einer häßlicheren Syntax 😉

    Fall 2: natives C++ in einem C++/CLI Wrapper (IJW)

    Bei der Mischung von C++/CLI und nativem C++ in einer DLL solltest Du Dich mit dem IJW (It Just Works) von MS beschäftigen (und nein, ich habe das nicht erfunden, die nennen das wirklich IJW)

    Das gute an IJW ist, das es zu 99% nahtlos funktioniert und den Aufruf von natviven Methoden aus dem managed bereich heraus wunderbar schafft.

    Das schlimme and IJW wiederum ist, daß man als Entwickler schnell vergessen kann das es nut 99% sind die klappen und man sich um das eine % selber kümmern _MUSS_, Stichwort: pin_ptr. Vergisst man dieses "pinnen" von Objekten so hat man lustiges Debuggen vor sich.

    Hintergrund: Die GC vom Framework räumt nicht nur ungenutzte Objekte ab sondern komprimiert danach auch den Speicher. Für managed Objekte ist das kein Problem da diese referenziert werden. Beim Aufruf von nativen Funktionen aus der virtuellen Machine heraus verwendet IJW jedoch native Zeiger. Wenn diese nativen Zeiger zufällig auf eine Adresse in einem managed Objekt zeigen und dieses dann von der GC verschoben wird, hat man in Folge einen ungültigen Zeiger in der Hand...

    Folge: Unregelmässig auftretende Heap-Corruptions, immer kurz nach einem GC-Lauf.

    Fall 3: Reines C++ & PInvoke zum Aufruf

    Falls Du darüber nachdenkst eine rein native C++-Dll in einem C# Projekt einzubinden ist das natürlich wieder was anderes, weil dann kein IJW zum tragen kommt sondern PInvoke. ZU dem Thema PInvoke vs IJW findest Du in der MSDn einige Artikel. Hängt stark von Art und Umfang der C++-DLL ab was der bessere Weg ist.



  • Okay, also für den Fall 2 bedeutett das,
    ich sollte keine pointer von C# an native C/C++ übergeben, wenn ich den pointer nicht pinne.
    Ansonsten kann er komprimiert werde, und in Folge dessen stimmen die Adressberechnungen nicht mehr ???

    Kann man das so stehen lassen. ???
    Habs mir noch nicht genauer angesehen, komm leider erst jetzt wieder dazu.

    L.g.



  • Vereinfacht gesagt, ja. Allerdings braucht man interior_ptr und pin_ptr wirklich extrem selten, z.B. wenn du die Adresse einer Member-Variablen eines Objekts auf dem GC-Heap an eine native Funktion übergeben willst. Oder vom nativen Code auf die Elemente eines Arrays zugreifen willst.

    MfG



  • Jup, kann man so stehen lassen, bis auf ein Detail:

    C# ruft in dem Ansatz nur managed C++ auf (C++/CLI).
    Der Aufruf nativer Funktionen/nativem C++ passiert nur innerhalb der DLL zwischen C++/CLI und C++;

    Du hast also eine Dll die sich nach aussen wie eine normale managed Dll verhält und nur intern native Anteile hat.

    Vergisst man pin_ptr, so "funktioniert" auch erstmal alles auf den ersten Blick, halt bis die erste GC zum unpassenden Zeitpunkt läuft...


Anmelden zum Antworten