Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Marshalling ist der Prozess der Transformation von Typen, wenn sie zwischen verwaltetem und systemeigenem Code wechseln müssen.
Marshalling ist erforderlich, da die Typen im verwalteten und nicht verwalteten Code unterschiedlich sind. In verwaltetem Code verfügen Sie beispielsweise über eine string, während nicht verwaltete Zeichenfolgen .NET-Codierung string (UTF-16), ANSI Code Page-Codierung, UTF-8, null-terminated, ASCII usw. sein können. Standardmäßig versucht das P/Invoke-Subsystem, das richtige Zu tun, basierend auf dem Standardverhalten, das in diesem Artikel beschrieben wird. In situationen, in denen Sie zusätzliche Kontrolle benötigen, können Sie jedoch das MarshalAs-Attribut verwenden, um anzugeben, was der erwartete Typ auf der nicht verwalteten Seite ist. Wenn die Zeichenfolge beispielsweise als NULL-beendete UTF-8-Zeichenfolge gesendet werden soll, können Sie dies wie folgt tun:
[LibraryImport("somenativelibrary.dll")]
static extern int MethodA([MarshalAs(UnmanagedType.LPUTF8Str)] string parameter);
// or
[LibraryImport("somenativelibrary.dll", StringMarshalling = StringMarshalling.Utf8)]
static extern int MethodB(string parameter);
Wenn Sie das System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute Attribut auf die Assembly anwenden, gelten die Regeln im folgenden Abschnitt nicht. Informationen dazu, wie .NET-Werte beim Anwenden dieses Attributs für nativen Code verfügbar gemacht werden, finden Sie unter Deaktiviertes Runtimemarshalling.
Standardregeln für das Marshallen von häufig verwendeten Typen
Allgemein versucht die Runtime, beim Marshallen das „Richtige“ zu tun, damit Sie möglichst wenig Arbeitsaufwand haben. In den folgenden Tabellen wird beschrieben, wie jeder Typ standardmäßig gemarshallt wird, wenn er in einem Parameter oder Feld verwendet wird. Die Ganzzahl- und Zeichentypen C99/C++11 mit fester Breite werden verwendet, um sicherzustellen, dass die folgende Tabelle für alle Plattformen korrekt ist. Sie können jeden systemeigenen Typ verwenden, der die gleichen Ausrichtungs- und Größenanforderungen wie diese Typen aufweist.
Die erste Tabelle beschreibt die Zuordnungen für Typen, für die das Marshallen für P/Invoke und Feldmarshalling gleich ist.
| C#-Schlüsselwort | .NET-Typ | Nativer Typ |
|---|---|---|
byte |
System.Byte |
uint8_t |
sbyte |
System.SByte |
int8_t |
short |
System.Int16 |
int16_t |
ushort |
System.UInt16 |
uint16_t |
int |
System.Int32 |
int32_t |
uint |
System.UInt32 |
uint32_t |
long |
System.Int64 |
int64_t |
ulong |
System.UInt64 |
uint64_t |
char |
System.Char |
Entweder char oder char16_t abhängig von der Codierung des P/Invoke oder der Struktur. Weitere Informationen finden Sie in der Zeichensatzdokumentation. |
System.Char |
Entweder char* oder char16_t* abhängig von der Codierung des P/Invoke oder der Struktur. Weitere Informationen finden Sie in der Zeichensatzdokumentation. |
|
nint |
System.IntPtr |
intptr_t |
nuint |
System.UIntPtr |
uintptr_t |
.NET-Zeigertypen (z. B. void*) |
void* |
|
Abgeleitet vom Typ System.Runtime.InteropServices.SafeHandle |
void* |
|
Abgeleitet vom Typ System.Runtime.InteropServices.CriticalHandle |
void* |
|
bool |
System.Boolean |
Win32-Typ BOOL |
decimal |
System.Decimal |
COM-DECIMAL-Struktur |
| .NET-Delegat (Delegierter) | Systemeigener Funktionszeiger | |
System.DateTime |
Win32-Typ DATE |
|
System.Guid |
Win32-Typ GUID |
Einige Marshallingkategorien weisen unterschiedliche Standardwerte auf, wenn Sie das Marshalling als Parameter oder Struktur durchführen.
| .NET-Typ | Nativer Typ (Parameter) | Nativer Typ (Feld) |
|---|---|---|
| .NET-Array | Ein Zeiger auf den Anfang eines Arrays aus nativen Darstellungen der Arrayelemente | Ohne Attribut [MarshalAs] nicht zulässig |
Eine Klasse mit einem LayoutKind-Wert vom Typ Sequential oder Explicit |
Ein Zeiger auf die native Darstellung der Klasse | Die native Darstellung der Klasse |
Die folgende Tabelle enthält die Standard-Marshallingregeln, die nur unter Windows gelten. Auf Nicht-Windows-Plattformen können Sie diese Typen nicht marshallen.
| .NET-Typ | Nativer Typ (Parameter) | Nativer Typ (Feld) |
|---|---|---|
System.Object |
VARIANT |
IUnknown* |
System.Array |
COM-Schnittstelle | Ohne Attribut [MarshalAs] nicht zulässig |
System.ArgIterator |
va_list |
Nicht zulässig |
System.Collections.IEnumerator |
IEnumVARIANT* |
Nicht zulässig |
System.Collections.IEnumerable |
IDispatch* |
Nicht zulässig |
System.DateTimeOffset |
int64_t – repräsentiert die Anzahl von Takten seit dem 1. Januar 1601 um Mitternacht |
int64_t – repräsentiert die Anzahl von Takten seit dem 1. Januar 1601 um Mitternacht |
Einige Typen können nur als Parameter und nicht als Felder gemarshallt werden. Diese Typen sind in der folgenden Tabelle aufgeführt:
| .NET-Typ | Nativer Typ (nur Parameter) |
|---|---|
System.Text.StringBuilder |
Entweder char* oder char16_t*, je nach CharSet des P/Invoke. Weitere Informationen finden Sie in der Zeichensatzdokumentation. |
System.ArgIterator |
va_list (nur unter Windows x86/x64/arm64) |
System.Runtime.InteropServices.ArrayWithOffset |
void* |
System.Runtime.InteropServices.HandleRef |
void* |
Wenn diese Standardeinstellungen nicht genau das tun, was Sie möchten, können Sie anpassen, wie Parameter zugeordnet werden. Der Artikel zum Marshalling von Parametern führt Sie durch das Anpassen, wie verschiedene Parametertypen ge marshallt werden.
Standardmarshalling in COM-Szenarios
Wenn Sie Methoden für COM-Objekte in .NET aufrufen, ändert die .NET-Laufzeit die Standard-Marshallregeln so, dass sie mit allgemeinen COM-Semantiken übereinstimmen. In der folgenden Tabelle sind die Regeln aufgeführt, die .NET-Runtimes in COM-Szenarien verwenden:
| .NET-Typ | Nativer Typ (COM-Methodenaufrufe) |
|---|---|
System.Boolean |
VARIANT_BOOL |
StringBuilder |
LPWSTR |
System.String |
BSTR |
| Delegattypen |
_Delegate* in .NET Framework. In .NET Core und .NET 5+ unzulässig. |
System.Drawing.Color |
OLECOLOR |
| .NET-Array | SAFEARRAY |
System.String[] |
SAFEARRAY aus BSTRs |
Marshallen von Klassen und Strukturen
Ein weiterer Aspekt des Marshallens von Typen ist die Übergabe einer Struktur an eine nicht verwaltete Methode. Beispielsweise erfordern einige der nicht verwalteten Methoden eine Struktur als Parameter. In diesen Fällen müssen Sie eine entsprechende Struktur oder eine Klasse in verwalteten Teilen der Welt erstellen, um sie als Parameter zu verwenden. Das Definieren der Klasse reicht jedoch nicht aus, Sie müssen auch den Marshaller anweisen, wie Felder in der Klasse der nicht verwalteten Struktur zugeordnet werden. Hier wird das StructLayout Attribut nützlich.
using System;
using System.Runtime.InteropServices;
Win32Interop.GetSystemTime(out Win32Interop.SystemTime systemTime);
Console.WriteLine(systemTime.Year);
internal static partial class Win32Interop
{
[LibraryImport("kernel32.dll")]
internal static partial void GetSystemTime(out SystemTime systemTime);
[StructLayout(LayoutKind.Sequential)]
internal ref struct SystemTime
{
public ushort Year;
public ushort Month;
public ushort DayOfWeek;
public ushort Day;
public ushort Hour;
public ushort Minute;
public ushort Second;
public ushort Millisecond;
}
}
Der vorherige Code zeigt ein einfaches Beispiel für das Aufrufen der GetSystemTime() Funktion. Das interessante Bit befindet sich in Zeile 13. Das Attribut gibt an, dass die Felder der Klasse sequenziell der Struktur auf der anderen Seite (nicht verwaltet) zugeordnet werden sollen. Dies bedeutet, dass die Benennung der Felder nicht wichtig ist, nur ihre Reihenfolge ist wichtig, da sie der nicht verwalteten Struktur entsprechen muss, wie im folgenden Beispiel gezeigt:
typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
Manchmal führt das standardmäßige Marshalling für Ihre Struktur nicht zum gewünschten Ergebnis. Im Artikel Anpassen des Marshallens für Strukturen erfahren Sie, wie Sie das Marshalling für Ihre Struktur anpassen.