[Ms VS 2005] C++ Dll in C# einbinden



  • Okay, seh ich ein 😉

    So, siehts jetzt aus:

    using System;
    using System.Runtime.InteropServices;
    using System.Collections.Generic;
    using System.Text;
    
    class dllimport
        {
            [DllImport ("c++_csharp.dll")]
            public static extern void call();
        }
    
    class program {
        static void Main(string[] args)
        { 
            dllimport.call();
        }
    }
    

    Beim Ausfuehren in der Konsole meckert er allerdings:

    Unable to find an entry point named 'call' in DLL 'c++_csharp.dll'.
    at dllimport.call()
    at program.Main(String[] args)

    //edit:
    Die DLL habe ich auch etwas vereinfacht:

    // c++_csharp.cpp : Defines the initialization routines for the DLL.
    
    #include "stdafx.h"
    #include "c++_csharp.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    BEGIN_MESSAGE_MAP(Cc_csharpApp, CWinApp)
    END_MESSAGE_MAP()
    
    // test method
    namespace test {
    	extern __declspec(dllexport) void call();
    }
    
    void call() {
    	printf("Hello world!");
    }
    


  • Vermutlich wird keine methode call exportiert.
    Überprüfe dies mit dem Dependecy Walker.

    Ein anderes Problem könnte das C++ Name Mangeling sein.

    -> ich würde call so schreiben:

    extern "C"
    {
       __declspec(dllexport) void call()
       {
           printf("Hello world!");
       }
    }
    

    Simon



  • Sicher, dass der Funktionsexport klappt? Üblicherweise brauchst Du dafür eine Exportdefinitionstabelle, die hast Du bisher nicht erwähnt. Dabei handelt es sich eine Datei mit der üblichen Endung „.def“, welche z.B. den folgenden Code enthält und die Du dem C++-Linker übergibst, wenn Du die DLL kompilierst (das kannst Du in den Projekteinstellungen einstellen):

    LIBRARY c++_csharp
    EXPORTS
        call
    


  • Leute... Tausend Dank bis hierhin!!
    Ich werde das spaeter oder morgen sofort ausprobieren... und mich dann sicher mit dem naechsten Problem wieder melden 😃
    Schoenen Abend noch!



  • Die Fehlermeldung ist klar.

    dllimport.call(); gibt es auch nicht.

    Siehe was Konrad Rudolph geschrieben hat.
    Solltest Du es nicht verstehen hast Du probleme mit Grundlagen.
    In C++ kann man auch keine Funktion verwenden ohne sie zu deklarieren.

    static void Main(string[] args)
        {
            call();
        }
    

    ohne jetzt zu wissen ob man damit eine printf aus der DLL machen kann.
    Normalerweise gibt man aus einer DLL einfach den String zurück und gibt in in NET aus.



  • Durch das

    __declspec(dllexport) void call();
    

    sollte die Methode schon exportiert werden. Vermutlich wird sie aber dekoriert (liegt, glaub ich, an der Aufrufkonvention).
    Versuch mal

    extern "C" __declspec(dllexport) void call();
    

    dann sollte es eigentlich klappen.
    Die "def" datei bruacht der Linker, isr klar. Mir DllImport wird aber dynamisch gelinkt, ähnlich wie in C/C++ mit LoadLibrary(...) und GetProcAddress(...), deshalb wird keine "def" Datei benötigt, sondern nur die Dll.



  • Durch das

    __declspec(dllexport) void call();
    

    sollte die Methode schon exportiert werden. Vermutlich wird sie aber dekoriert (liegt, glaub ich, an der Aufrufkonvention).
    Versuch mal

    extern "C" __declspec(dllexport) void call();
    

    dann sollte es eigentlich klappen.
    Die "def" datei bruacht der Linker, isr klar. Mir DllImport wird aber dynamisch gelinkt, ähnlich wie in C/C++ mit LoadLibrary(...) und GetProcAddress(...), deshalb wird keine "def" Datei benötigt, sondern nur die Dll.

    Unix-Tom schrieb:

    In C++ kann man auch keine Funktion verwenden ohne sie zu deklarieren.

    Natürlich kann man das, außerdem ist die Methode "call" deklariert...

    Oh, sorry für den doppelten Post, wollte eigentlich nur editieren... 🙄



  • Unix-Tom schrieb:

    Die Fehlermeldung ist klar.

    dllimport.call(); gibt es auch nicht.

    Dachte ich auch erst. 😉 Aber schau mal, wie die Klasse heißt, in der die Funktionsdeklaration liegt.

    Herb schrieb:

    Die "def" datei bruacht der Linker, isr klar. Mir DllImport wird aber dynamisch gelinkt, ähnlich wie in C/C++ mit LoadLibrary(...) und GetProcAddress(...), deshalb wird keine "def" Datei benötigt, sondern nur die Dll.

    Nein, da verwechselst Du etwas. Die 'DEF'-Datei wird vom Linker für das Erstellen der Exporttabelle benötigt. Wenn eine DLL keine Exporttabelle besitzt, dann kann sie auch nicht dynamisch verlinkt werden, es sei denn, man gibt den Einsprungpunkt direkt als Adresse an, was auch möglich wäre: Die Exportdefinitionstabelle wird von der Funktion 'GetProcAddress' benötigt.

    Aber generell gilt: Ohne 'DEF'-Datei keine Exporte. Theoretisch sollte es dem Compiler möglich sein, diese Datei on-the-fly aus den '__declspec(dllexport)'-Direktiven zu erstellen. Aber hier tritt dann genau das beschriebene Problem auf, dass der Compiler die Namen „mangled“. Um das zu umgehen führt, soweit ich weiß, kein Weg drumherum, die DEF-Datei selbstzuschreiben.



  • Herb schrieb:

    Unix-Tom schrieb:

    In C++ kann man auch keine Funktion verwenden ohne sie zu deklarieren.

    Natürlich kann man das

    Und wie?



  • Aber generell gilt: Ohne 'DEF'-Datei keine Exporte. Theoretisch sollte es dem Compiler möglich sein, diese Datei on-the-fly aus den '__declspec(dllexport)'-Direktiven zu erstellen. Aber hier tritt dann genau das beschriebene Problem auf, dass der Compiler die Namen „mangled“. Um das zu umgehen führt, soweit ich weiß, kein Weg drumherum, die DEF-Datei selbstzuschreiben.

    Genau dafür ist dann eben die

    extern "C"
    

    direktive - so wird beim __declspec(dllexport) das Name Mangeling ausgeschaltet.

    Zusammengefasst:

    Funktionen können auf folgende Arten exportiert werden:
    a.) mit *.def File (es findet KEIN name mangeling statt)
    b.) mit __declspec(dllexport) (es findet name mangeling statt, wenn dies nicht erwünscht ist die direktive extern "C" verwenden).

    -> Generell können aber auch funktionen mit name mangeling aufgerufen werden. Der funktions name ist jedoch nicht allzu leserlich. (Der name könnte mit dem DllImport Attribute gemappt werden.)

    Ich benütze für die Überprüfung, ob funktionen exportiert wurden und unter welchem namen immer den Dependency Walker: http://www.dependencywalker.com/

    Nur um Missverständnissen vorzu beueugen:
    Auf auf der managed Seite wird NUR die DLL mit den exportierten Funktionen benötigt (und natürlich die abhänigen DLLs). Kein *.lib, *.def oder *.h File.

    Noch ein Wort zum name mangeling:
    Das name mangeling wird vo C++ Compiler eingesetzt um z.B. Überladungen von Funktionen zuzulassen. So wird die Signatur (funktions name, typen und anzahl der parameter) ein den name hineincodiert.

    Grüsse
    Simon



  • Moin!
    Also es funktioniert mittlerweile.
    Das ganze sieht folgendermassen aus.

    DLL:

    namespace test {
    	extern "C" {
    		__declspec(dllexport) void call() {
    			printf("Hello World!");
    		}
    	}
    }
    

    C#:

    class dllimport
        {
            [DllImport ("c++_csharp.dll")]
            public static extern void call();
        }
    
    class program {
        static void Main(string[] args)
        { 
            dllimport.call();
        }
    }
    

    Ausgabe funktioniert 1a!



  • Hallo Simon,

    ich dachte bisher (hatte noch nie damit gearbeitet), dass das 'extern "C"' nur für den Import von Symbolen korrekt funktioniert, nicht für den Export. Dass es auch so funktioniert, ist natürlich schön, da man sich die DEF-Datei erspart.



  • Konrad Rudolph schrieb:

    Herb schrieb:

    Unix-Tom schrieb:

    In C++ kann man auch keine Funktion verwenden ohne sie zu deklarieren.

    Natürlich kann man das

    Und wie?

    int add(int a, int b)
    {
        return a + b;
    }
    
    int main()
    {
        return add(a,b);
    }
    

    Hab die funktion "add" nicht deklariert - die Definition reicht, sie muß nur vor dem Aufruf stehen.

    Mit der "def" Datei hast du natürlich recht.



  • Herb schrieb:

    Konrad Rudolph schrieb:

    Herb schrieb:

    Unix-Tom schrieb:

    In C++ kann man auch keine Funktion verwenden ohne sie zu deklarieren.

    Natürlich kann man das

    Und wie?

    int add(int a, int b)
    {
        return a + b;
    }
    
    int main()
    {
        return add(a,b);
    }
    

    Hab die funktion "add" nicht deklariert - die Definition reicht, sie muß nur vor dem Aufruf stehen.

    Das da oben ist (auch) eine Deklaration (*jede* Definition ist eine Deklaration). Siehe C++-Standard, Sektion 3 Abs. 5 und 3.1 Abs 2.


Anmelden zum Antworten