Marshalling von TypenType marshaling

Das Marshallen bezeichnet den Vorgang zum Umwandeln von Typen, wenn diese zwischen verwaltetem und nativem Code wechseln müssen.Marshaling is the process of transforming types when they need to cross between managed and native code.

Das Marshallen ist erforderlich, weil sich die Typen in verwaltetem und nicht verwaltetem Code unterscheiden.Marshaling is needed because the types in the managed and unmanaged code are different. In verwaltetem Code verwenden Sie z.B. einen String-Typ, während Zeichenfolgen im nicht verwalteten Bereich Unicode (Breitzeichen), Nicht-Unicode, mit NULL endend, ASCII usw. sein können. Standardmäßig versucht das P/Invoke-Subsystem basierend auf dem Standardverhalten die richtige Aktion auszuführen. Dieses wird im vorliegenden Artikel beschrieben.In managed code, for instance, you have a String, while in the unmanaged world strings can be Unicode ("wide"), non-Unicode, null-terminated, ASCII, etc. By default, the P/Invoke subsystem tries to do the right thing based on the default behavior, described on this article. In Situationen, in denen Sie zusätzliche Kontrolle benötigen, können Sie das MarshalAs-Attribut verwenden, um anzugeben, welcher Typ auf der nicht verwalteten Seite erwartet wird.However, for those situations where you need extra control, you can employ the MarshalAs attribute to specify what is the expected type on the unmanaged side. Wenn Sie beispielsweise die Zeichenfolge als nicht mit NULL endende ANSI-Zeichenfolge senden möchten, können Sie dies folgendermaßen erreichen:For instance, if you want the string to be sent as a null-terminated ANSI string, you could do it like this:

[DllImport("somenativelibrary.dll")]
static extern int MethodA([MarshalAs(UnmanagedType.LPStr)] string parameter);

Standardregeln für das Marshallen von häufig verwendeten TypenDefault rules for marshaling common types

Allgemein versucht die Runtime, beim Marshallen das „Richtige“ zu tun, damit Sie möglichst wenig Arbeitsaufwand haben.Generally, the runtime tries to do the "right thing" when marshaling to require the least amount of work from you. Die folgenden Tabellen beschreiben das standardmäßige Marshallen der einzelnen Typen bei Verwendung in einem Parameter oder Feld.The following tables describe how each type is marshaled by default when used in a parameter or field. Die Integer- und Zeichentypen mit fester Breite von C99/C++11 werden verwendet, um sicherzustellen, dass die folgende Tabelle für alle Plattformen richtig ist.The C99/C++11 fixed-width integer and character types are used to ensure that the following table is correct for all platforms. Sie können jeden nativen Typen verwenden, der die gleichen Anforderungen an Ausrichtung und Größe aufweist wie diese Typen.You can use any native type that has the same alignment and size requirements as these types.

Die erste Tabelle beschreibt die Zuordnungen für verschiedene Typen, für die das Marshallen für P/Invoke und Feldmarshalling gleich ist.This first table describes the mappings for various types for whom the marshaling is the same for both P/Invoke and field marshaling.

.NET-Typ.NET Type Nativer TypNative Type
byte uint8_t
sbyte int8_t
short int16_t
ushort uint16_t
int int32_t
uint uint32_t
long int64_t
ulong uint64_t
char Entweder char oder char16_t, je nach CharSet von P/Invoke oder der Struktur.Either char or char16_t depending on the CharSet of the P/Invoke or structure. Informationen dazu finden Sie in der Dokumentation zum Zeichensatz.See the charset documentation.
string Entweder char* oder char16_t*, je nach CharSet von P/Invoke oder der Struktur.Either char* or char16_t* depending on the CharSet of the P/Invoke or structure. Informationen dazu finden Sie in der Dokumentation zum Zeichensatz.See the charset documentation.
System.IntPtr intptr_t
System.UIntPtr uintptr_t
.NET-Zeigertypen (z.B..NET Pointer types (ex. void*)void*) void*
Von System.Runtime.InteropServices.SafeHandle abgeleiteter TypType derived from System.Runtime.InteropServices.SafeHandle void*
Von System.Runtime.InteropServices.CriticalHandle abgeleiteter TypType derived from System.Runtime.InteropServices.CriticalHandle void*
bool Win32-BOOL-TypWin32 BOOL type
decimal COM-DECIMAL-StrukturCOM DECIMAL struct
.NET-Delegat.NET Delegate Nativer FunktionszeigerNative function pointer
System.DateTime Win32-DATE-TypWin32 DATE type
System.Guid Win32-GUID-TypWin32 GUID type

Einige Marshallingkategorien weisen unterschiedliche Standardwerte auf, wenn Sie das Marshalling als Parameter oder Struktur durchführen.A few categories of marshaling have different defaults if you're marshaling as a parameter or structure.

.NET-Typ.NET Type Nativer Typ (Parameter)Native Type (Parameter) Nativer Typ (Feld)Native Type (Field)
.NET-Array.NET array Ein Zeiger auf den Anfang eines Arrays aus nativen Darstellungen der ArrayelementeA pointer to the start of an array of native representations of the array elements. Ohne [MarshalAs]-Attribut nicht zulässigNot allowed without a [MarshalAs] attribute
Eine Klasse mit einem LayoutKind-Wert vom Typ Sequential oder ExplicitA class with a LayoutKind of Sequential or Explicit Ein Zeiger auf die native Darstellung der KlasseA pointer to the native representation of the class Die native Darstellung der KlasseThe native representation of the class

Die folgende Tabelle enthält die standardmäßigen Marshallingregeln, die nur für Windows gelten.The following table includes the default marshaling rules that are Windows-only. Auf Nicht-Windows-Plattformen können Sie diese Typen nicht marshallen.On non-Windows platforms, you cannot marshal these types.

.NET-Typ.NET Type Nativer Typ (Parameter)Native Type (Parameter) Nativer Typ (Feld)Native Type (Field)
object VARIANT IUnknown*
System.Array COM-SchnittstelleCOM interface Ohne [MarshalAs]-Attribut nicht zulässigNot allowed without a [MarshalAs] attribute
System.ArgIterator va_list Nicht zulässigNot allowed
System.Collections.IEnumerator IEnumVARIANT* Nicht zulässigNot allowed
System.Collections.IEnumerable IDispatch* Nicht zulässigNot allowed
System.DateTimeOffset int64_t – repräsentiert die Anzahl von Takten seit dem 1. Januar 1601 um Mitternachtint64_t representing the number of ticks since midnight on January 1, 1601 int64_t – repräsentiert die Anzahl von Takten seit dem 1. Januar 1601 um Mitternachtint64_t representing the number of ticks since midnight on January 1, 1601

Für einige Typen ist das Marshalling nur als Parameter möglich, nicht als Felder.Some types can only be marshaled as parameters and not as fields. Diese Typen werden in der folgenden Tabelle aufgeführt:These types are listed in the following table:

.NET-Typ.NET Type Nativer Typ (nur Parameter)Native Type (Parameter Only)
System.Text.StringBuilder Entweder char* oder char16_t*, je nach CharSet von P/Invoke.Either char* or char16_t* depending on the CharSet of the P/Invoke. Informationen dazu finden Sie in der Dokumentation zum Zeichensatz.See the charset documentation.
System.ArgIterator va_list (nur auf Windows x86/x64/arm64)va_list (on Windows x86/x64/arm64 only)
System.Runtime.InteropServices.ArrayWithOffset void*
System.Runtime.InteropServices.HandleRef void*

Wenn diese Standardwerte nicht exakt Ihren Vorstellungen entsprechen, können Sie angeben, auf welche Weise das Marshalling von Parametern durchgeführt werden soll.If these defaults don't do exactly what you want, you can customize how parameters are marshaled. Im Artikel Marshallen von Parametern erfahren Sie, wie Sie das Marshalling verschiedener Parametertypen anpassen.The parameter marshaling article walks you through how to customize how different parameter types are marshaled.

Standardmarshalling in COM-SzenarienDefault marshaling in COM scenarios

Wenn Sie Methoden in COM-Objekten in .NET aufrufen, ändert die .NET-Runtime die standardmäßigen Marshallingregeln, um der allgemeinen COM-Semantik zu entsprechen.When you are calling methods on COM objects in .NET, the .NET runtime changes the default marshaling rules to match common COM semantics. In der folgenden Tabelle werden die Regeln aufgeführt, die die .NET-Runtime in COM-Szenarien verwendet:The following table lists the rules that .NET runtimes uses in COM scenarios:

.NET-Typ.NET Type Nativer Typ (COM-Methodenaufrufe)Native Type (COM method calls)
bool VARIANT_BOOL
StringBuilder LPWSTR
string BSTR
DelegattypenDelegate types _Delegate* in .NET Framework._Delegate* in .NET Framework. In .NET Core nicht zulässig.Disallowed in .NET Core.
System.Drawing.Color OLECOLOR
.NET-Array.NET array SAFEARRAY
string[] SAFEARRAY aus BSTRsSAFEARRAY of BSTRs

Marshallen von Klassen und StrukturenMarshaling classes and structs

Ein weiterer Aspekt des Marshallens von Typen ist die Übergabe einer Struktur an eine nicht verwaltete Methode.Another aspect of type marshaling is how to pass in a struct to an unmanaged method. Einige der nicht verwalteten Methoden erfordern beispielsweise eine Struktur als Parameter.For instance, some of the unmanaged methods require a struct as a parameter. In diesen Fällen müssen Sie eine entsprechende Struktur oder eine Klasse im verwalteten Bereich erstellen, um sie als Parameter zu verwenden.In these cases, you need to create a corresponding struct or a class in managed part of the world to use it as a parameter. Allerdings reicht das Definieren der Klasse nicht aus, Sie müssen dem Marshaller außerdem mitteilen, wie Felder in der Klasse der nicht verwalteten Struktur zuzuordnen sind.However, just defining the class isn't enough, you also need to instruct the marshaler how to map fields in the class to the unmanaged struct. Hierbei ist das StructLayout-Attribut nützlich.Here the StructLayout attribute becomes useful.

[DllImport("kernel32.dll")]
static extern void GetSystemTime(SystemTime systemTime);

[StructLayout(LayoutKind.Sequential)]
class SystemTime {
    public ushort Year;
    public ushort Month;
    public ushort DayOfWeek;
    public ushort Day;
    public ushort Hour;
    public ushort Minute;
    public ushort Second;
    public ushort Milsecond;
}

public static void Main(string[] args) {
    SystemTime st = new SystemTime();
    GetSystemTime(st);
    Console.WriteLine(st.Year);
}

Der obige Code zeigt ein einfaches Beispiel für einen Aufruf in der GetSystemTime()-Funktion.The previous code shows a simple example of calling into GetSystemTime() function. Der interessante Teil befindet sich in Zeile 4.The interesting bit is on line 4. Das Attribut gibt an, dass die Felder der Klasse sequenziell der Struktur auf der anderen (nicht verwalteten) Seite zugeordnet werden sollen.The attribute specifies that the fields of the class should be mapped sequentially to the struct on the other (unmanaged) side. Dies bedeutet, dass die Benennung der Felder nicht wichtig ist, sondern nur deren Reihenfolge, da diese der nicht verwalteten Struktur entsprechen muss, wie im folgenden Beispiel gezeigt:This means that the naming of the fields isn't important, only their order is important, as it needs to correspond to the unmanaged struct, shown in the following example:

typedef struct _SYSTEMTIME {
  WORD wYear;
  WORD wMonth;
  WORD wDayOfWeek;
  WORD wDay;
  WORD wHour;
  WORD wMinute;
  WORD wSecond;
  WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;

Manchmal führt das standardmäßige Marshalling für Ihre Struktur nicht zum gewünschten Ergebnis.Sometimes the default marshaling for your structure doesn't do what you need. Im Artikel Anpassen des Marshallens für Strukturen erfahren Sie, wie Sie das Marshalling für Ihre Struktur anpassen.The Customizing structure marshaling article teaches you how to customize how your structure is marshaled.