Wie erfolgt das Marshalling, wenn C ++ - Code von C ++ / CLI aufgerufen wird?

8

Nach dieser Frage ist es möglich kombinieren Sie verwalteten und nicht verwalteten Code nahtlos mit C ++ / CLI. Ich verstehe es nicht ganz - sollte es nicht irgendwo zwischen verwalteten und unmanaged Marshalling sein?

Zum Beispiel habe ich InnerLibrary, das als native C ++ - DLL kompiliert wird, wobei ein Header veröffentlicht und C ++ / CLI OuterLibrary den Code von InnerLibrary aufruft. Wird es Marshalling geben? Wer wird es umsetzen und wie teuer wird es sein?

    
sharptooth 16.08.2010, 10:48
quelle

6 Antworten

5

Nun, es ist eine Funktion, die in den C ++ / CLI-Compiler namens C ++ - Interop eingebaut ist. Es ist viel weniger schwarze Magie beteiligt, als du vielleicht denkst. Der JIT-Compiler generiert genau die gleiche Art von Maschinencode wie Ihr C ++ - Compiler generiert. Alle .NET-Werttypen haben eine direkte Entsprechung in C ++, sodass keine Konvertierung erforderlich ist. Wenn not automatisch Referenztypen behandelt, müssen Sie dies selbst tun. pin_ptr & lt; & gt; typischerweise.

Alles, was wirklich tut, ist ein bisschen Code, der den Übergang von einem verwalteten Stack-Frame zu einem nicht verwalteten Stack-Frame behandelt. Dieser Code setzt einen speziellen "Cookie" auf den Stack, der vom Garbage Collector erkannt wird. Dies verhindert, dass es in die nicht verwalteten Frames übergeht und nicht verwaltete Zeiger als Objektreferenzen falsch identifiziert. Es gibt nicht viel zu diesem Code, dauert etwa 5 Nanosekunden im Release-Build, geben oder nehmen.

    
Hans Passant 16.08.2010 12:05
quelle
3

Es muss kein Marshalling erfolgen, da C ++ / CLI unsafe-Code ausgeben kann, der den Aufruf direkt ausführt. Sehen Sie sich einen C ++ / CLI-Code in Reflector an - er wird sich sehr von C # unterscheiden.

Das ist etwas, das C # nicht kann (zumindest nicht ohne das Schlüsselwort unsafe und einige Zeiger-Hacks), und es ist auch etwas, was C ++ / CLI im reinen Modus nicht kann (aus dem gleichen Grund wie C #).

Der unsichere .NET-Code kann direkte Aufrufe von nicht verwalteten Funktionen ausführen. Es ist nur, dass diese Fähigkeit nicht bequem verfügbar ist, außer durch C ++ / CLI.

    
Tim Robinson 16.08.2010 10:58
quelle
3

Marshalling ist der Prozess, um nicht verwaltete Daten oder Anrufe in die verwaltete Welt zu bringen. Es ist nur sozusagen eine Übersetzung zwischen beiden.

Mit C ++ / CLI können Sie mischen und anpassen. Das bedeutet, wenn Sie Ihre Bibliothek direkt verwenden, die * .h-Datei verwenden und herkömmlichen C ++ - Code verwenden, wird sie nicht verwaltet und ohne Marshalling. Wenn Sie über BCL-Klassen oder Ihren eigenen verwalteten Code auf diese Daten zugreifen, fügen Sie die Marshalling-Ebene von Hand hinzu, aber nur bei Bedarf. Das heißt, ein LPTSTR muss in eine verwaltete Zeichenfolge übersetzt werden, um als eine verwendet zu werden. Mit C ++ / CLI können Sie diesen Schritt überspringen und sich an den traditionellen C ++ - Code halten, indem Sie schnelleren und milderen Code erstellen, ohne sicheren, überprüften verwalteten Code zu verwenden.

    
Abel 16.08.2010 11:07
quelle
2

Es wird invovled maskiert, aber Sie (d. h. der Programmierer) müssen es explizit tun.

Wenn Ihre C ++ CLI OuterLibrary-Aufrufe eine Funktion haben, die ein System.String / System::String^ verwendet, erfordert das C ++ - Typsystem eine Typkonvertierung, bevor es an eine InnerLibrary-Funktion übergeben wird, die ein const char* verwendet. Sie müssen die Konvertierung selbst durchführen - das ist das Marshalling.

Microsoft ship something nennt sich C ++ Support Library , welches Funktionen zur Verfügung stellt, die mit C ++ & lt; - & gt; C ++ - CLI-Interaktion.

    
Joe Gauterin 16.08.2010 11:15
quelle
0

Es hängt von den beteiligten Datentypen ab.

Intrinsische Typen wie int , double usw. ( string sind nicht qualifiziert) haben dieselbe Darstellung sowohl im nativen als auch im verwalteten Code. Es ist kein Marshalling erforderlich. Arrays mit intrinsischen Typen sind ebenfalls auf dieselbe Weise angelegt (wenn wir die Metadaten-.NET-Speicher ignorieren, die jedoch vom Array-Inhalt getrennt sind).

Werttypen, die explizite Layout-Attribute verwenden, bei denen alle Elemente intrinsische Typen sind, sind ebenfalls mit dem Speicherlayout kompatibel.

Das Pinning kann erforderlich sein, wenn die Daten in einem Objekt auf dem verwalteten Heap gespeichert werden (dies gilt für alle Arrays).

Klassentypen hingegen müssen konvertiert / übersetzt werden.

    
Ben Voigt 16.08.2010 11:09
quelle
0

Hier gibt es zwei Punkte:

1) Übergang zwischen verwaltetem und nicht verwaltetem Code: Jeder Übergang hat seine festen Kosten. Wenn C ++ / CLI-Code in einer einzelnen Assembly kompiliert wird, versucht der Compiler, den gesamten verwalteten Code möglichst zu minimieren. Wenn externe nicht verwaltete DLL aus C ++ / CLI-Code aufgerufen wird, ist eine solche Optimierung unmöglich. Daher ist es eine gute Idee, solche Übergänge zumindest in zeitkritischen Abschnitten zu minimieren. Sehen Sie mehr dazu hier: Ссылка , Leistung und die Position Ihrer Interop-Grenze

2) Parameter-Marshalling. Dies hängt vom Parametertyp ab. Einige Parameter müssen nicht gemarshallt werden, z. B. einfache Typen wie int. Strings sollten gemarshallt werden. Einige Tricks, wie das Anheften von Zeigern, können das Array-Marshalling von einfachen Typen verhindern.

    
Alex F 16.08.2010 11:17
quelle