Ist es möglich, eine C-Funktion von C#.Net aus aufzurufen
Lesezeit: 9 Minuten
Chinjoo
Ich habe eine C-Bibliothek und möchte die Funktion in dieser Bibliothek aus der C#-Anwendung aufrufen. Ich habe versucht, einen C++/CLI-Wrapper auf der C-Bibliothek zu erstellen, indem ich die C-Bibliothek als Linker-Eingabe und die Quelldateien als zusätzliche Abhängigkeiten hinzugefügt habe.
Gibt es einen besseren Weg, 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);
}
Ja, es ist möglich, und es gibt viele Beispiele, wenn Sie es googeln, aber keine Ahnung, was Ihr Problem aus den begrenzten Informationen ist
– Keith Nicholas
11. Juli 2012 um 3:44 Uhr
Wenn es weh tut, wenn Sie X ausführen, hören Sie auf, X auszuführen. Benennen Sie Ihre C++-Wrapper-Methode um, um dies als Ursache des Problems auszuschließen. Und poste deinen Code 🙂
– Eric J.
11. Juli 2012 um 3:48 Uhr
Ich habe eine AC-Bibliothek, die von einem Anbieter bereitgestellt wird, der über Funktionen wie ConnectToMachine (unsigned char * psig, char apt) verfügt. Ich möchte diese Funktion aus meiner C#-Klasse aufrufen.
F: Ist es möglich, eine C-Funktion von C#.Net aus aufzurufen? A: Ja, offensichtlich! F: Ist ein C++/CLI-Wrapper der richtige Weg? Ich persönlich halte C++/CLI für ein Greuel. Aber die Leute verwenden es in Szenarien wie diesem. Ich würde es vorziehen, Interop direkt zu verwenden (dh PInvoke) – alles C#, bis hinunter zum nativen, nicht verwalteten C/C++. Es gibt viele Tutorials, und es ist nicht schwierig. Sicherlich nicht schwieriger als C/C++ von VB6 aus aufzurufen;) IMHO..
– paulsm4
11. Juli 2012 um 3:55 Uhr
Gonzalo.-
Das Beispiel wird z Linux:
1) Erstellen Sie eine C Datei, libtest.c mit diesem Inhalt:
Das ist ein einfacher Pseudo-Wrapper für printf. Aber stellt keine dar C Funktion in der Bibliothek, die Sie aufrufen möchten. Wenn Sie eine haben C++ Funktion vergessen Sie nicht, extern zu setzen C um den Namen nicht zu verstümmeln.
2) Erstellen Sie die C# Datei
using 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, sehen Sie wahrscheinlich eine System.DllNotFoundException, um dies zu beheben, können Sie Ihre libtest.so nach /usr/lib verschieben, oder Besser noch, fügen Sie einfach Ihre CWD zum Bibliothekspfad hinzu: export LD_LIBRARY_PATH=pwd
Zum Windows, es ist nicht viel anders. Nehmen Sie ein Beispiel aus hierdu musst nur dich in deine einschließen *.cpp Datei Ihre Methode mit extern "C"
Etwas wie
extern "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 einfach verwenden:
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);
}
}
Gutes Beispiel! Dies ist ein sehr gutes Beispiel für die Verwendung von Interop. Es ist offensichtlich Linux (nicht Windows), aber das Prinzip ist dasselbe. Das ist EXAKT den Ansatz würde ich dem OP empfehlen.
– paulsm4
11. Juli 2012 um 3:59 Uhr
Könnte jemand die Antwort bearbeiten? Ich habe Probleme mit dem Include, zeigt stdio.h nicht an
– Gonzalo.-
11. Juli 2012 um 3:59 Uhr
schätze, das sollte funktionieren
– Chinjoo
11. Juli 2012 um 7:22 Uhr
wie Sie hier sehen können de.csharp-online.net/… Sie könnten dasselbe mit einer .dll tun
– Gonzalo.-
11. Juli 2012 um 12:26 Uhr
@Chinjoo bedenke das codeproject.com/Articles/6912/…. Haben Sie Ihren C-Code geändert und _declspec(dllexport) hinzugefügt? Wenn dieses Beispiel für Sie funktioniert, werde ich es der Antwort hinzufügen
– Gonzalo.-
16. Juli 2012 um 17:32 Uhr
Shahin Dohan
UPDATE – 22. Februar 2019: Da diese Antwort einige Upvotes erhalten hat, habe ich beschlossen, sie mit einer besseren Methode zum Aufrufen der C-Methode zu aktualisieren. Zuvor hatte ich vorgeschlagen, zu verwenden unsafe Code, aber der sichere und korrekte Weg ist die Verwendung MarshalAs -Attribut zum Konvertieren einer .NET string zu einem char*. Außerdem gibt es in VS2017 kein Win32-Projekt mehr, Sie müssen wahrscheinlich eine Visual C++-DLL oder ein leeres Projekt erstellen und dieses ändern. Vielen Dank!
Sie können C-Funktionen direkt aus C# aufrufen, indem Sie P/Invoke verwenden.
Hier ist eine kurze Anleitung zum Erstellen einer C#-Bibliothek, die eine C-DLL umschließt.
Erstellen Sie ein neues C#-Bibliotheksprojekt (ich nenne es „Wrapper“)
Fügen Sie der Projektmappe ein Win32-Projekt hinzu, setzen Sie den Anwendungstyp auf: DLL (ich nenne es “CLibrary”)
Sie können alle anderen cpp/h-Dateien entfernen, da wir sie nicht benötigen
Benennen Sie die CLibrary.cpp-Datei in CLibrary.c um
Fügen Sie eine CLibrary.h-Headerdatei hinzu
Jetzt müssen wir das CLibrary-Projekt konfigurieren, mit der rechten Maustaste darauf klicken und zu Eigenschaften gehen und Konfiguration auswählen: “Alle Konfigurationen”.
Legen Sie unter Konfigurationseigenschaften > C/C++ > Vorkompilierte Header für Vorkompilierte Header fest: „Vorkompilierte Header nicht verwenden“
Wechseln Sie im selben C/C++-Zweig zu Erweitert, ändern Sie Kompilieren als in: “Als C-Code kompilieren (/TC)”.
Wechseln Sie nun im Linker-Zweig zu Allgemein und ändern Sie die Ausgabedatei in: „$(SolutionDir)Wrapper\$(ProjectName).dll“. Dadurch wird die erstellte C-DLL in das Stammverzeichnis des C#-Projekts kopiert.
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;
}
Klicken Sie mit der rechten Maustaste auf das CLibrary-Projekt, erstellen Sie es, sodass wir die DLL im C#-Projektverzeichnis erhalten
Klicken Sie mit der rechten Maustaste auf das C# Wrapper-Projekt, fügen Sie ein vorhandenes Element hinzu, fügen Sie CLibrary.dll hinzu
Klicken Sie auf CLibrary.dll, gehen Sie zum Eigenschaftenbereich und stellen Sie “In Ausgabeverzeichnis kopieren” auf “Immer kopieren” ein.
Es ist eine gute Idee, das Wrapper-Projekt von CLibrary abhängig zu machen, damit CLibrary zuerst gebaut wird, Sie können das tun, indem Sie mit der rechten Maustaste auf das Wrapper-Projekt klicken, zu “Projektabhängigkeiten” gehen und “CLibrary” markieren. 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);
}
}
}
Jetzt einfach anrufen GetConnectSessionund es sollte zurückkehren 42.
Ergebnis:
Das hat bei mir funktioniert, aber ich musste auch meine .NET-Projekte ändern Properties->Build->Platform Target zu x64.
– Joseph
21. Februar 2018 um 21:47 Uhr
David Kroukamp
Okay, Open VS 2010, Gehe zu Datei -> Neu -> Projekt -> Visual C++ -> Win32 -> Win32-Projekt und gib ihr einen Namen (in meinem Fall HelloWorldDll), dann im folgenden Fenster unter Anwendungstyp wählen ‘DLL’ und unter Zusätzliche Optionen wählen ‘Leeres Projekt’.
Gehen Sie jetzt zu Ihrem Lösungsforscher Registerkarte normalerweise rechts vom VS-Fenster, Rechtsklick Quelldateien -> Element hinzufügen -> C++-Datei (.cpp) und gib ihm einen Namen (HelloWorld in meinem Fall)
Fügen Sie dann in der neuen Klasse diesen Code ein:
Jetzt Bauen das Projekt, nachdem Sie zu Ihren Projekten navigiert haben DEBUGGEN Ordner und dort sollten Sie Folgendes finden: HelloWorldDll.dll.
Lassen Sie uns nun unsere C#-App erstellen, die auf die DLL Goto zugreift Datei -> Neu -> Projekt -> Visual C# -> Konsolenanwendung und geben Sie ihm einen Namen (CallDllCSharp), kopieren Sie nun diesen Code und fügen Sie ihn in Ihren Hauptordner 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 unsere beiden Apps erstellt haben, können wir sie verwenden, holen Sie sich Ihre *.dll und Ihre .exe (bin/debug/.exe) im selben Verzeichnis, und führen Sie die Anwendungsausgabe aus
Ich konnte das C#-Programm nicht kompilieren, da mein Projekt die DLL-Datei nicht finden kann. Also habe ich den vollständigen Pfad in der DllImport-Anweisung verwendet: [DllImport("C:\\Users\\...full path...\\HelloWorldDll\\Debug\\HelloWorldDll.dll")]
– Quazi Irfan
23. April 2017 um 8:16 Uhr
Immer wieder „Es wurde versucht, ein Programm mit einem falschen Format zu laden. (Ausnahme von HRESULT: 0x8007000B)’. Hat noch jemand dieses Problem?
– max
19. August 2019 um 12:51 Uhr
HINWEIS: FOLGENDER CODE GILT FÜR MEHRERE METHODEN VON 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);
}
Das P/Invoke-Methode wurde ausführlich und mehrfach beschrieben, soweit ok. Was mir hier fehlt, ist, dass die C++/CLI-Methode einen großen Vorteil hat: Calling Safety. Im Gegensatz zu P/Invoke, wo der Aufruf der C-Funktion wie ein Blindflug in den Himmel ist (sofern dieser Vergleich erlaubt ist), wird beim Aufruf der C-Funktion niemand die Funktionsargumente prüfen. Die Verwendung von C++/CLI bedeutet in diesem Fall normalerweise, dass Sie eine Headerdatei mit den Funktionsprototypen einschließen, die Sie verwenden möchten. Wenn Sie die C-Funktion mit falschen/zu vielen/zu wenigen Argumenten aufrufen, teilt Ihnen der Compiler dies mit.
Ich glaube nicht, dass man pauschal sagen kann, welche die bessere Methode ist, ehrlich gesagt mag ich keine von beiden.
14185400cookie-checkIst es möglich, eine C-Funktion von C#.Net aus aufzurufenyes
Ja, es ist möglich, und es gibt viele Beispiele, wenn Sie es googeln, aber keine Ahnung, was Ihr Problem aus den begrenzten Informationen ist
– Keith Nicholas
11. Juli 2012 um 3:44 Uhr
Wenn es weh tut, wenn Sie X ausführen, hören Sie auf, X auszuführen. Benennen Sie Ihre C++-Wrapper-Methode um, um dies als Ursache des Problems auszuschließen. Und poste deinen Code 🙂
– Eric J.
11. Juli 2012 um 3:48 Uhr
Ich habe eine AC-Bibliothek, die von einem Anbieter bereitgestellt wird, der über Funktionen wie ConnectToMachine (unsigned char * psig, char apt) verfügt. Ich möchte diese Funktion aus meiner C#-Klasse aufrufen.
– Chinjoo
11. Juli 2012 um 3:48 Uhr
Einblick in PAufrufen
– Markus Halle
11. Juli 2012 um 3:53 Uhr
F: Ist es möglich, eine C-Funktion von C#.Net aus aufzurufen? A: Ja, offensichtlich! F: Ist ein C++/CLI-Wrapper der richtige Weg? Ich persönlich halte C++/CLI für ein Greuel. Aber die Leute verwenden es in Szenarien wie diesem. Ich würde es vorziehen, Interop direkt zu verwenden (dh PInvoke) – alles C#, bis hinunter zum nativen, nicht verwalteten C/C++. Es gibt viele Tutorials, und es ist nicht schwierig. Sicherlich nicht schwieriger als C/C++ von VB6 aus aufzurufen;) IMHO..
– paulsm4
11. Juli 2012 um 3:55 Uhr