Ist es möglich, eine C-Funktion von C#.Net aus aufzurufen

Lesezeit: 9 Minuten

Benutzeravatar von Chinjoo
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.

    – 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


Benutzeravatar von Gonzalo.-
Gonzalo.-

Das Beispiel wird z Linux:

1) Erstellen Sie eine C Datei, libtest.c mit diesem Inhalt:

#include <stdio.h>

void print(const char *message)
{
  printf("%s\\n", message);
}

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

Kredite ab hier

BEARBEITEN

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


Benutzeravatar von Shahin Dohan
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.

  1. Erstellen Sie ein neues C#-Bibliotheksprojekt (ich nenne es „Wrapper“)
  2. 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
  3. 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:
Testen der Wrapper-Bibliothek in einer Konsolenanwendung

  • 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

Benutzeravatar von David Kroukamp
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:

#include <stdio.h>

extern "C"
{
  __declspec(dllexport) void DisplayHelloFromDLL()
  {
    printf ("Hello from DLL !\n");
  }
}

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

Dies ist ein C#-Programm

Hallo von DLL!

Hoffe, das klärt einige Ihrer Probleme.

Verweise:

  • 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.

1418540cookie-checkIst es möglich, eine C-Funktion von C#.Net aus aufzurufen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy