wake-up-neo.com

Wie rufe ich C ++ / CLI von C # aus auf?

Ich habe eine Klasse in C++ implementiert, die für die arithmetische Berechnung des Programms verantwortlich ist, und eine Schnittstelle mit WPF. Ich verarbeite die Eingabe mit C #, aber wie kann ich dann meine C++ - Klasse verwenden?

Ich habe einige Kommentare zum Erstellen einer verwalteten C++ - Wrapper-Klasse für die Interaktion mit ihr gesehen, weiß aber nicht, wo ich anfangen soll. Ich weiß auch nicht, wie ich es zusammen mit all dem anderen Code kompilieren soll. Ich kann kein Tutorial dazu finden, und das, was Google auf Managed C++ zeigt, scheint nicht wirklich hilfreich zu sein.

Gibt es irgendetwas, das mir helfen könnte? Das erscheint mir nicht unangemessen.

EDIT Versuchte m3rLinEz-Lösung, aber es gibt mir eine BadImageFormatException. Ich denke, das liegt daran, dass die DLL nicht generiert wurde. Das habe ich getan Alles wie gesagt, keine Ahnung, was passiert ist.

64
master chief

Haben Sie sich C++/CLI angesehen?

Lassen Sie mich ein sehr kurzes Beispiel geben. Hier ist die Quelldatei aus einem Visual C++ -> CLR -> Class Library-Projekt. Grundsätzlich wird der Windows-Benutzername abgerufen und zurückgegeben.

Bitte beachten Sie, dass Sie, um dies zu kompilieren, in die Projekteinstellungen gehen und "Additional Dependencies" als "Inherit from parent" markieren müssen, da wir diese Windows-Bibliotheken verwenden (kernel32.lib, user32.lib, ..).

// CSCPP.h

#pragma once

#include "windows.h"

using namespace System;

namespace CSCPP {

    public ref class Class1
    {
        // TODO: Add your methods for this class here.
    public:
        String^ GetText(){
            WCHAR acUserName[100];
            DWORD nUserName = sizeof(acUserName);
            if (GetUserName(acUserName, &nUserName)) {
                String^ name = gcnew String(acUserName);
                return String::Format("Hello {0} !", name);
            }else{
                return gcnew String("Error!");
            }
        }
    };
}

Erstellen Sie jetzt ein neues C # -Projekt und fügen Sie einen Verweis auf unser erstes C++/CLI-Klassenbibliotheksprojekt hinzu. Rufen Sie dann die Instanzmethode auf.

namespace CSTester
{
    class Program
    {
        static void Main(string[] args)
        {
            CSCPP.Class1 instance = new CSCPP.Class1();
            Console.WriteLine(instance.GetText());
        }
    }
}

Dies ergab auf meinem Rechner folgendes Ergebnis:

Hallo m3rlinez!

C++/CLI ist im Grunde eine verwaltete Erweiterung des C++ - Standards. Sie können damit CLR-Klassen und -Datentypen in Ihrem C++/CLI-Projekt verwenden und diese auch für verwaltete Sprachen verfügbar machen. Hiermit können Sie einen verwalteten Wrapper für Ihre alte C++ - Bibliothek erstellen. Es gibt einige seltsame Syntaxen wie String^, um den Referenztyp für die CLR-Zeichenfolge zu definieren. Ich finde "Schnelles C++/CLI - Lernen von C++/CLI in weniger als 10 Minuten" hier nützlich.

56
Gant

Es gibt mindestens drei Möglichkeiten, um nicht verwalteten Code von einem verwalteten in demselben Prozess aufzurufen:

  1. C++/CLI
  2. Plattform aufrufen
  3. Binden Sie Ihr C++ in ein COM-Objekt ein

Bei der Arbeit verwenden wir dafür C++/CLI, es scheint zu funktionieren.

9
Arve

Ich würde eine standardmäßige (nicht COM/Managed) Dynamic Link Library als hier beschrieben erstellen und dann das DllImport-Attribut (Plattformaufruf) im c # -Code verwenden, um auf die exportierten Funktionen zuzugreifen .

Der entscheidende Punkt aus diesem Artikel:

Beachten Sie den Modifizierer __declspec (dllexport) in den Methodendeklarationen in diesem Code. Mit diesen Modifizierern kann die Methode von der DLL exportiert werden, damit sie von anderen Anwendungen verwendet werden kann. Weitere Informationen finden Sie unter dllexport, dllimport.

Dies ist eine leichtere Alternative zu einem tatsächlichen COM-Interop-Wrapper und vermeidet Probleme wie die Registrierung usw. (die DLL kann einfach in das Anwendungsverzeichnis gestellt werden).

Eine andere Alternative ist Es funktioniert einfach (IJW). Dies ist wahrscheinlich die bessere Wahl, wenn Sie C++ - Code verwaltet haben und von anderen .NET-Sprachen aus darauf zugreifen müssen. Dies ist jedoch nur dann eine Option, wenn Sie nicht verwaltetes C++ in verwaltetes C++ konvertieren können.

4
Ash

Ich würde mich von P/Invoke fernhalten, da es im Vergleich zu IJW (It Just Works) ziemlich langsam ist. Letzteres ermöglicht es Ihnen, verwaltetes und nicht verwaltetes c ++ nahtlos miteinander zu verknüpfen. Alles, was Sie tun müssen, ist, eine verwaltete c ++ - Assembly zu erstellen, eine verwaltete Klasse zu schreiben, die in c # sichtbar ist, und den nicht verwalteten Code daraus aufzurufen.

Ähm ... OK. Ich hatte den Eindruck, dass P/Invoke-Aufrufe langsamer sind als sie von Natur aus sind. Durch die explizite Kontrolle über das Marshalling können Sie jedoch die Leistung Ihrer C++/CLI-Version in vielen Fällen verbessern.

Hier ist der Artikel von Microsoft zu beiden Mechanismen:

http://msdn.Microsoft.com/en-us/library/ms235282.aspx

Vorteile von IJW

  • Es ist nicht erforderlich, DLLImport-Attributdeklarationen für die vom Programm verwendeten nicht verwalteten APIs zu schreiben. Fügen Sie einfach die Header-Datei hinzu und verknüpfen Sie sie mit der Importbibliothek.
  • Der IJW-Mechanismus ist etwas schneller (z. B. müssen die IJW-Stubs nicht prüfen, ob Datenelemente angeheftet oder kopiert werden müssen, da dies ausdrücklich vom Entwickler vorgenommen wird).
  • Es zeigt deutlich Leistungsprobleme. In diesem Fall die Tatsache, dass Sie von einer Unicode-Zeichenfolge in eine ANSI-Zeichenfolge konvertieren und über eine entsprechende Speicherzuordnung und Freigabe verfügen. In diesem Fall würde ein Entwickler, der den Code mit IJW schreibt, feststellen, dass das Aufrufen von _putws und das Verwenden von PtrToStringChars für die Leistung besser wäre.
  • Wenn Sie viele nicht verwaltete APIs aufrufen, die dieselben Daten verwenden, ist es wesentlich effizienter, sie einmal zu marshallen und die gemarshallte Kopie zu übergeben, als sie jedes Mal neu zu marshallen.

Es gibt auch ästhetische Vorteile:

  • C # -Code sieht aus wie C # -Code ohne jegliche Interoperabilität.
  • Sie müssen kein DLLImport Attribut definieren, Sie müssen keine der Datenstrukturen definieren (auch nicht mit p/aufrufspezifischen Attributen), die so aussehen könnten:

    [StructLayout (LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct DevMode {[MarshalAs (UnmanagedType.ByValTStr, SizeConst = 32)] public string dmDeviceName; }

  • Sie müssen nicht alle primitiven Parametertypen in ihre .NET-Gegenstücke konvertieren (es gibt eine Tabelle auf diese Seite , in der aufgeführt ist, wie verwaltete Typen nicht verwalteten Typen zugeordnet werden).
  • Sie können mit C++/CLI arbeiten, was wirklich Spaß macht und wirklich gut aussieht. Es ist ein langer Weg seit VS 2003 und ist jetzt eine voll funktionsfähige .NET-Sprache. Microsoft-Dokumentation dafür ist ziemlich gut, ebenso wie alle IJW-Informationen.
  • Das Ausführen von C++ - Interop in C++/CLI fühlt sich im Gegensatz zu C # sehr natürlich an. Dies ist völlig subjektiv, aber ich würde es vorziehen, String-Marshalling in C++ durchzuführen, das Marshal.PtrToString(ptr) ausführt.
  • Wenn Sie eine API verfügbar machen, möchten Sie wahrscheinlich alle P/Invoke-Inhalte in einer anderen Ebene einschließen, damit Sie sich nicht mit der Hässlichkeit von P/Invoke auseinandersetzen müssen. Auf diese Weise haben Sie den Overhead aller Rangier- UND C # -Ebenen. Mit C++/CLI befinden sich das Marshalling und die Interop-Abstraktion an einem Ort, und Sie können auswählen, wie viel Marshalling Sie benötigen.

IMHO, wenn Sie eine ungerade Funktion in Windows SDK aufrufen, gehen Sie mit P/Invoke. Wenn Sie der verwalteten Welt eine mäßig komplexe C++ - API zur Verfügung stellen, ist dies definitiv C++/CLI.

3
Igor Zevaka