Ich habe eine C lib und möchte die Funktion in dieser Bibliothek aus der C # -Anwendung aufrufen. Ich habe versucht, einen C ++ / CLI-Wrapper für die C lib zu erstellen, indem ich die C lib-Datei als Linker-Eingabe und die Quelldateien als zusätzliche Abhängigkeiten hinzugefügt habe.
Gibt es einen besseren Weg, um dies zu erreichen, da ich nicht sicher bin, wie ich der C # -Anwendung eine C-Ausgabe hinzufügen soll?
Mein C-Code -
__declspec(dllexport) unsigned long ConnectSession(unsigned long handle,
unsigned char * publicKey,
unsigned char publicKeyLen);
Mein CPP Wrapper -
long MyClass::ConnectSessionWrapper(unsigned long handle,
unsigned char * publicKey,
unsigned char publicKeyLen)
{
return ConnectSession(handle, publicKey, publicKeyLen);
}
Antworten:
Das Beispiel lautet für Linux :
1) Erstellen Sie eine
C
Dateilibtest.c
mit folgendem Inhalt:#include <stdio.h> void print(const char *message) { printf("%s\\n", message); }
Das ist ein einfacher Pseudo-Wrapper für printf. Stellt jedoch jede
C
Funktion in der Bibliothek dar, die Sie aufrufen möchten. Wenn Sie eineC++
Funktion haben, vergessen Sie nicht, extern zu setzenC
zu , um eine Verfälschung des Namens zu vermeiden.2) Erstellen Sie die
C#
Dateiusing System; using System.Runtime.InteropServices; public class Tester { [DllImport("libtest.so", EntryPoint="print")] static extern void print(string message); public static void Main(string[] args) { print("Hello World C# => C++"); } }
3) Wenn Sie die Bibliothek libtest.so nicht in einem Standardbibliothekspfad wie "/ usr / lib" haben, wird wahrscheinlich eine System.DllNotFoundException angezeigt. Um dies zu beheben, können Sie Ihre libtest.so nach / usr / lib oder verschieben Besser noch, fügen Sie einfach Ihr CWD zum Bibliothekspfad hinzu:
export LD_LIBRARY_PATH=pwd
Credits von hier
BEARBEITEN
Für Windows ist das nicht viel anders. Wenn Sie ein Beispiel von hier nehmen , haben Sie nur
*.cpp
Ihre Methode in Ihre Datei mitextern "C"
Etwas wie eingeschlossenextern "C" { //Note: must use __declspec(dllexport) to make (export) methods as 'public' __declspec(dllexport) void DoSomethingInC(unsigned short int ExampleParam, unsigned char AnotherExampleParam) { printf("You called method DoSomethingInC(), You passed in %d and %c\n\r", ExampleParam, AnotherExampleParam); } }//End 'extern "C"' to prevent name mangling
Dann kompilieren und in Ihrer C # -Datei tun
[DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")] public static extern void DoSomethingInC(ushort ExampleParam, char AnotherExampleParam);
und dann benutze es einfach:
using System; using System.Runtime.InteropServices; public class Tester { [DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")] public static extern void DoSomethingInC(ushort ExampleParam, char AnotherExampleParam); public static void Main(string[] args) { ushort var1 = 2; char var2 = ''; DoSomethingInC(var1, var2); } }
quelle
UPDATE - 22. Februar 2019: Da diese Antwort einige positive Stimmen erhalten hat, habe ich beschlossen, sie mit einer besseren Methode zum Aufrufen der C-Methode zu aktualisieren. Früher hatte ich vorgeschlagen,
unsafe
Code zu verwenden, aber der sichere und korrekte Weg besteht darin, einMarshalAs
Attribut zum Konvertieren eines .NETstring
in ein .NET zu verwendenchar*
. Außerdem gibt es in VS2017 kein Win32-Projekt mehr. Wahrscheinlich müssen Sie eine Visual C ++ - DLL oder ein leeres Projekt erstellen und diese ändern. Vielen Dank!Sie können C-Funktionen direkt von C # aus mit P / Invoke aufrufen.
Hier finden Sie eine kurze Anleitung zum Erstellen einer C # -Bibliothek, die eine C-DLL umschließt.
Fügen Sie der Lösung ein Win32-Projekt hinzu und setzen Sie den Anwendungstyp auf: DLL (ich nenne es "CLibrary")
Jetzt müssen wir das CLibrary-Projekt konfigurieren, mit der rechten Maustaste darauf klicken und zu den Eigenschaften gehen und Konfiguration auswählen: "Alle Konfigurationen".
CLibrary.h
__declspec(dllexport) unsigned long ConnectSession(unsigned long handle, unsigned char * publicKey, unsigned char publicKeyLen);
CLibrary.c
#include "CLibrary.h" unsigned long ConnectSession(unsigned long handle, unsigned char * publicKey, unsigned char publicKeyLen) { return 42; }
Es ist eine gute Idee, das Wrapper-Projekt von CLibrary abhängig zu machen, damit CLibrary zuerst erstellt wird. Klicken Sie dazu mit der rechten Maustaste auf das Wrapper-Projekt, gehen Sie zu "Projektabhängigkeiten" und aktivieren Sie "CLibrary". Nun zum eigentlichen Wrapper-Code:
ConnectSessionWrapper.cs
using System.Runtime.InteropServices; namespace Wrapper { public class ConnectSessionWrapper { [DllImport("CLibrary.dll", CallingConvention = CallingConvention.Cdecl)] static extern uint ConnectSession(uint handle, [MarshalAs(UnmanagedType.LPStr)] string publicKey, char publicKeyLen); public uint GetConnectSession(uint handle, string publicKey, char publicKeyLen) { return ConnectSession(handle, publicKey, publicKeyLen); } } }
Rufen
GetConnectSession
Sie jetzt einfach an und es sollte zurückkehren42
.Ergebnis:
quelle
Properties->Build->Platform Target
zux64
.Okay, öffnen Sie VS 2010, Springen Sie zu Datei -> Neu -> Projekt -> Visual C ++ -> Win32 -> Win32-Projekt und geben Sie ihm einen Namen (in meinem Fall HelloWorldDll). Wählen Sie dann im folgenden Fenster unter Anwendungstyp 'DLL' ' und unter Zusätzliche Optionen wählen Sie ' Projekt leeren ' .
Gehen Sie nun zu Ihrer Registerkarte " Projektmappen- Explorer", normalerweise rechts im VS-Fenster, klicken Sie mit der rechten Maustaste auf "Quelldateien" -> "Element hinzufügen" -> "C ++" -Datei (.cpp) und geben Sie ihr einen Namen (in meinem Fall HelloWorld ).
Fügen Sie dann in der neuen Klasse diesen Code ein:
#include <stdio.h> extern "C" { __declspec(dllexport) void DisplayHelloFromDLL() { printf ("Hello from DLL !\n"); } }
Jetzt bauen das Projekt, nach dem Navigieren Sie zu Ihren Projekten DEBUG Ordner und dort sollten Sie finden: HelloWorldDll.dll .
Jetzt erstellen wir unsere C # -App, die auf die DLL zugreift. Gehe zu Datei -> Neu -> Projekt -> Visual C # -> Konsolenanwendung und gib ihr einen Namen (CallDllCSharp). Kopiere diesen Code und füge ihn in dein Hauptmenü ein:
using System; using System.Runtime.InteropServices; ... static void Main(string[] args) { Console.WriteLine("This is C# program"); DisplayHelloFromDLL(); Console.ReadKey(); }
und erstellen Sie das Programm, jetzt, da wir beide Apps erstellt haben, können Sie sie verwenden, Ihre * .dll und Ihre .exe (bin / debug / .exe) im selben Verzeichnis abrufen und die Anwendungsausgabe ausführen
Ich hoffe, das klärt einige Ihrer Probleme.
Referenzen :
quelle
[DllImport("C:\\Users\\...full path...\\HelloWorldDll\\Debug\\HelloWorldDll.dll")]
HINWEIS: Der folgende Code gilt für mehrere Methoden aus der DLL.
[DllImport("MyLibc.so")] public static extern bool MyLib_GetName(); [DllImport("MyLibc.so")] public static extern bool MyLib_SetName(string name); [DllImport("MyLibc.so")] public static extern bool MyLib_DisplayName(string name); public static void Main(string[] args) { string name = MyLib_GetName(); MyLib_SetName(name); MyLib_DisplayName(name); }
quelle
Die P / Invoke-Methode wurde bisher ausführlich und wiederholt beschrieben. Was mir hier fehlt, ist, dass die C ++ / CLI-Methode einen großen Vorteil hat: Sicherheit aufrufen. Im Gegensatz zu P / Invoke, bei dem der Aufruf der C-Funktion dem blinden Schießen in den Himmel gleicht (wenn dieser Vergleich zulässig ist), überprüft niemand die Funktionsargumente beim Aufrufen der C-Funktion. Wenn Sie in diesem Fall C ++ / CLI verwenden, fügen Sie normalerweise eine Header-Datei mit den Funktionsprototypen hinzu, die Sie verwenden möchten. Wenn Sie die C-Funktion mit falschen / zu vielen / zu wenigen Argumenten aufrufen, werden Sie vom Compiler darüber informiert.
Ich glaube nicht, dass man allgemein sagen kann, welche Methode die bessere ist, ehrlich gesagt mag ich keine von beiden.
quelle