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




wordpress seo titel (4)

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

Ich habe einige Kommentare darüber gesehen, wie eine verwaltete C ++ - Wrapper-Klasse damit interagieren kann, aber ich weiß nicht, wo ich anfangen soll. Ich weiß auch nicht, wie ich es zusammen mit all dem anderen Code kompilieren würde. Ich kann nicht wirklich ein Tutorial zu diesem Thema finden, und das Zeug, das Google auf verwaltetem C ++ zeigt, scheint nicht wirklich hilfreich zu sein.

Alles da draußen, um mir zu helfen? Das erscheint mir nicht unangemessen.

Bearbeiten Sie versucht m3rLinEz Lösung, aber es gibt mir eine BadImageFormatException, ich denke, es ist, weil die DLL nicht generiert wird. Ich habe alles wie gesagt gemacht, weiß nicht was passiert ist. Irgendwelche Ideen?


Haben Sie sich C ++ / CLI angesehen?

Lassen Sie mich ein sehr kurzes Beispiel geben. Hier ist die Quelldatei aus einem Visual C ++ -> CLR -> Klassenbibliothek Projekt. Es erhält im Grunde Windows-Benutzernamen und gibt es zurück.

Bitte beachten Sie, dass Sie, um dieses kompiliert zu bekommen, in die Projekteinstellungen gehen und "Zusätzliche Abhängigkeiten" als "Übernehmen von Eltern" 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!");
            }
        }
    };
}

Erstellt jetzt ein neues C # -Projekt und fügt eine Referenz zu unserem ersten C ++ / CLI-Klassenbibliotheksprojekt hinzu. Und dann rufe die Instanzmethode auf.

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

Dies ergab das folgende Ergebnis auf meiner Maschine:

Hallo m3rline!

C ++ / CLI ist im Grunde eine verwaltete Erweiterung über C ++ - Standard. Es ermöglicht Ihnen, CLR-Klassen und -Datentypen in Ihrem C ++ / CLI-Projekt zu verwenden und diese auch der verwalteten Sprache zur Verfügung zu stellen. Sie können damit einen verwalteten Wrapper für Ihre alte C ++ - Bibliothek erstellen. Es gibt einige seltsame Syntax wie String^ , um einen Referenztyp für CLR String zu definieren. Ich finde "Quick C ++ / CLI - Lerne C ++ / CLI in weniger als 10 Minuten" , um hier nützlich zu sein.


Ich würde von P / Invoke fern bleiben, 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 verweben. Alles, was Sie tun müssen, ist eine verwaltete C ++ - Assembly zu erstellen, eine verwaltete Klasse zu schreiben, die aus c # sichtbar ist, und den nicht verwalteten Code daraus aufzurufen.

Ähm ... OK. Ich hatte den Eindruck, dass P / Invoke-Aufrufe langsamer waren, was in der Regel nicht der Fall ist. Durch explizite Kontrolle über das Marshalling können Sie jedoch Ihre C ++ / CLI-Version in vielen Fällen leistungsfähiger machen.

Hier ist Microsofts Artikel über beide 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 ein und verknüpfen Sie sie mit der Import-Bibliothek.
  • Der IJW-Mechanismus ist etwas schneller (beispielsweise müssen die IJW-Stubs nicht prüfen, ob Datenelemente fixiert oder kopiert werden müssen, da dies explizit vom Entwickler durchgeführt wird).
  • Es veranschaulicht deutlich Leistungsprobleme. In diesem Fall ist es die Tatsache, dass Sie von einer Unicode-Zeichenfolge in eine ANSI-Zeichenfolge übersetzen und dass Sie eine Speicherzuweisung und -zuordnung haben. In diesem Fall würde ein Entwickler, der den Code unter Verwendung von IJW schreibt, erkennen, dass das Aufrufen von _putws und das Verwenden von PtrToStringChars für die Leistung besser wäre.
  • Wenn Sie viele nicht verwaltete APIs mit denselben Daten aufrufen, ist ein einmaliges Marshalling und das Übergeben der Marshalling-Kopie viel effizienter als das erneute Marshalling.

Es gibt auch ästhetische Vorteile:

  • C # -Code sieht wie C # -Code ohne Interop'y-Seltsamkeit aus.
  • Sie müssen das DLLImport Attribut nicht definieren, Sie müssen keine der Datenstrukturen definieren (auch mit p / invoke-spezifischen Attributen), die wie DLLImport aussehen könnten:

    [StructLayout (LayoutKind.Sequential, CharSet = CharSet.Ansi)] öffentliche Struktur DevMode {[MarshalAs (UnmanagedType.ByValTStr, SizeConst = 32)] öffentliche Zeichenfolge dmDeviceName; }

  • Sie müssen nicht alle Parameterprimitivtypen in ihre .NET-Gegenstücke konvertieren (es gibt eine Tabelle auf dieser Seite , die auflistet, wie verwaltete Typen nicht verwalteten Typen zugeordnet werden).
  • Sie können mit C ++ / CLI arbeiten, was wirklich Spaß macht zu lernen und ist wirklich poliert. Es ist ein langer Weg seit VS 2003 und ist jetzt eine voll funktionsfähige .NET-Sprache. Microsoft-Dokumentation dafür ist ziemlich gut, wie alle IJW-Informationen.
  • Doing C ++ - Interop in C ++ / CLI fühlt sich sehr natürlich im Gegensatz zu C #. Das ist völlig subjektiv, aber ich würde lieber lieber String-Marshalling in C ++ machen, der Marshal.PtrToString(ptr) .
  • Wenn Sie eine API offen legen, würden Sie wahrscheinlich alle P / Invoke-Dateien in einer anderen Ebene einpacken, so dass Sie sich nicht mit P / Invoke hässlich beschäftigen müssen. Auf diese Weise haben Sie den Overhead des gesamten Ranging und der C # -Schicht um ihn herum. Mit C ++ / CLI sind das Marshalling und die Interop-Abstraktion an einem Ort, und Sie können wä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, definitiv C ++ / CLI.


Ich würde eine Standard (nicht COM / Managed) Dynamic Link Library wie 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. Diese Modifikatoren ermöglichen es, dass die Methode von der DLL exportiert wird, sodass 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 Registrierung usw. (die DLL kann einfach in das Anwendungsverzeichnis gelegt werden).

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


Es gibt mindestens drei Möglichkeiten zum Aufrufen von nicht verwaltetem Code aus dem gleichen Prozess:

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

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





managed-c++