StandardmarshallingverhaltenDefault Marshaling Behavior

Das Interop-Marshalling basiert auf Regeln, die vorgeben, wie sich Daten, die Methodenparametern zugeordnet sind, verhalten, wenn sie zwischen verwaltetem und unverwaltetem Speicher übergeben werden.Interop marshaling operates on rules that dictate how data associated with method parameters behaves as it passes between managed and unmanaged memory. Mit diesen integrierten Regeln werden Marshalling-Aktivitäten wie Datentyptransformationen gesteuert, es wird gesteuert, ob eine aufrufende Instanz die Daten ändern kann, die an sie übergeben werden, und ob diese Änderungen an den Aufrufer zurückgegeben werden, und unter welchen Umständen der Marshaller Leistungsoptimierungen bereitstellt.These built-in rules control such marshaling activities as data type transformations, whether a callee can change data passed to it and return those changes to the caller, and under which circumstances the marshaler provides performance optimizations.

Dieser Abschnitt befasst sich mit den standardmäßigen Verhaltensmerkmalen des Interop-Marshalling-Diensts.This section identifies the default behavioral characteristics of the interop marshaling service. Er enthält detaillierte Informationen zum Marshallen von Arrays, booleschen Typen, Zeichentypen, Delegaten, Klassen, Objekten, Zeichenfolgen und Strukturen.It presents detailed information on marshaling arrays, Boolean types, char types, delegates, classes, objects, strings, and structures.

Hinweis

Das Marshalling von generischen Typen wird nicht unterstützt.Marshaling of generic types is not supported. Weitere Informationen finden Sie unter Interoperating Using Generic Types (Interoperation mit generischen Typen).For more information see, Interoperating Using Generic Types.

Speicherverwaltung mit dem Interop-MarshallerMemory management with the interop marshaler

Der Interop-Marshaller versucht immer, den von nicht verwaltetem Code belegten Speicher freizugeben.The interop marshaler always attempts to free memory allocated by unmanaged code. Dieses Verhalten entspricht den COM-Speicherverwaltungsregeln, unterscheidet sich jedoch von den Regeln, die für systemeigenes C++ gelten.This behavior complies with COM memory management rules, but differs from the rules that govern native C++.

Es kann zu Missverständnissen kommen, wenn Sie das Verhalten von systemeigenem C++ (keine Speicherfreigabe) beim Plattformaufruf erwarten, bei dem automatisch Speicher für Zeiger freigegeben wird.Confusion can arise if you anticipate native C++ behavior (no memory freeing) when using platform invoke, which automatically frees memory for pointers. Wenn Sie beispielsweise die folgende nicht verwaltete Methode aus einer C++-DLL aufrufen, wird kein Speicher automatisch freigegeben.For example, calling the following unmanaged method from a C++ DLL does not automatically free any memory.

Nicht verwaltete SignaturUnmanaged signature

BSTR MethodOne (BSTR b) {  
     return b;  
}  

Wenn Sie die Methode jedoch als einen Prototyp zum Plattformaufruf definieren, jeden BSTR-Typ durch einen String-Typ ersetzen und MethodOne aufrufen, versucht die Common Language Runtime b zweimal freizugeben.However, if you define the method as a platform invoke prototype, replace each BSTR type with a String type, and call MethodOne, the common language runtime attempts to free b twice. Sie können das Marshalling-Verhalten ändern, indem Sie IntPtr-Typen anstelle von Zeichenfolgentypen verwenden.You can change the marshaling behavior by using IntPtr types rather than String types.

Zur Laufzeit wird immer die CoTaskMemFree-Methode zum Freigeben von Speicher verwendet.The runtime always uses the CoTaskMemFree method to free memory. Wenn der Speicher, mit dem Sie arbeiten, nicht der CoTaskMemAlloc-Methode zugeordnet wurde, müssen Sie IntPtr verwenden und den Speicher manuell mit der geeigneten Methode freigeben.If the memory you are working with was not allocated with the CoTaskMemAlloc method, you must use an IntPtr and free the memory manually using the appropriate method. Ebenso können Sie in Situationen, in denen der Speicher niemals freigegeben werden soll, wie bei Verwendung der GetCommandLine-Funktion von Kernel32.dll, die einen Zeiger auf den Kernelspeicher zurückgibt, verhindern, dass Speicher automatisch freigegeben wird.Similarly, you can avoid automatic memory freeing in situations where memory should never be freed, such as when using the GetCommandLine function from Kernel32.dll, which returns a pointer to kernel memory. Details zum manuellen Freigeben von Speicher finden Sie unter Beispiel für Puffer.For details on manually freeing memory, see the Buffers Sample.

Standardmäßiges Marshalling für KlassenDefault marshaling for classes

Klassen können nur durch COM-Interop gemarshallt werden und werden immer als Schnittstellen gemarshallt.Classes can be marshaled only by COM interop and are always marshaled as interfaces. In einigen Fällen wird die zum Marshallen der Klasse verwendete Schnittstelle als Klassenschnittstelle bezeichnet.In some cases the interface used to marshal the class is known as the class interface. Informationen zum Überschreiben der Klassenschnittstelle mit einer beliebigen Schnittstelle finden Sie unter Einführung in die Klassenschnittstelle.For information about overriding the class interface with an interface of your choice, see Introducing the class interface.

Übergeben von Klassen an COMPassing Classes to COM

Wenn eine verwaltete Klasse an COM übergeben wird, umschließt der Interop-Marshaller die Klasse automatisch mit einem COM-Proxy und übergibt die vom Proxy erstellte Klassenschnittstelle an den COM-Methodenaufruf.When a managed class is passed to COM, the interop marshaler automatically wraps the class with a COM proxy and passes the class interface produced by the proxy to the COM method call. Der Proxy delegiert dann alle Aufrufe der Klassenschnittstelle zurück an das verwaltete Objekt.The proxy then delegates all calls on the class interface back to the managed object. Der Proxy macht zudem auch weitere Schnittstellen verfügbar, die von der Klasse nicht explizit implementiert werden.The proxy also exposes other interfaces that are not explicitly implemented by the class. Der Proxy implementiert automatisch Schnittstellen wie IUnknown und IDispatch für die Klasse.The proxy automatically implements interfaces such as IUnknown and IDispatch on behalf of the class.

Übergeben von Klassen an .NET-CodePassing Classes to .NET Code

Co-Klassen werden in der Regel nicht als Methodenargumente in COM verwendet.Coclasses are not typically used as method arguments in COM. Stattdessen wird normalerweise eine Standardschnittstelle anstelle der Co-Klasse übergeben.Instead, a default interface is usually passed in place of the coclass.

Wenn eine Schnittstelle an verwalteten Code übergeben wird, ist der Interop-Marshaller für das Umschließen der Schnittstelle mit dem geeigneten Wrapper und das Übergeben des Wrappers an die verwaltete Methode zuständig.When an interface is passed into managed code, the interop marshaler is responsible for wrapping the interface with the proper wrapper and passing the wrapper to the managed method. Herauszufinden, welcher Wrapper verwendet werden sollte, kann schwierig sein.Determining which wrapper to use can be difficult. Jede Instanz eines COM-Objekts verfügt über einen einzelnen, eindeutigen Wrapper, ganz gleich, wie viele Schnittstellen das Objekt implementiert.Every instance of a COM object has a single, unique wrapper, no matter how many interfaces the object implements. So hat ein einzelnes COM-Objekt, das fünf unterschiedliche Schnittstellen implementiert, nur einen einzigen Wrapper.For example, a single COM object that implements five distinct interfaces has only one wrapper. Der gleiche Wrapper macht alle fünf Schnittstellen verfügbar.The same wrapper exposes all five interfaces. Wenn zwei Instanzen des COM-Objekts erstellt werden, werden auch zwei Instanzen des Wrappers erstellt.If two instances of the COM object are created, then two instances of the wrapper are created.

Damit der Wrapper über die gesamte Lebensdauer den gleichen Typ beibehält, muss der Interop-Marshaller den korrekten Wrapper beim ersten Mal identifizieren, wenn ein vom Objekt verfügbar gemachte Schnittstelle über den Marshaller übergeben wird.For the wrapper to maintain the same type throughout its lifetime, the interop marshaler must identify the correct wrapper the first time an interface exposed by the object is passed through the marshaler. Der Marshaller identifiziert das Objekt anhand einer der Schnittstellen, die von dem Objekt implementiert werden.The marshaler identifies the object by looking at one of the interfaces the object implements.

So bestimmt der Marshaller beispielsweise, dass der Klassenwrapper zum Umschließen der Schnittstelle verwendet werden soll, die an verwalteten Code übergeben wurde.For example, the marshaler determines that the class wrapper should be used to wrap the interface that was passed into managed code. Wenn die Schnittstelle erstmals über den Marshaller übergeben wird, prüft der Marshaller, ob die Schnittstelle von einem bekannten Objekt stammt.When the interface is first passed through the marshaler, the marshaler checks whether the interface is coming from a known object. Diese Überprüfung erfolgt in zwei Situationen:This check occurs in two situations:

  • Eine Schnittstelle wird von einem anderen verwalteten Objekt implementiert, das an anderer Stelle an COM übergeben wurde.An interface is being implemented by another managed object that was passed to COM elsewhere. Der Marshaller kann die Schnittstellen, die von verwalteten Objekten verfügbar gemacht werden, leicht identifizieren und ist in der Lage, die Schnittstelle mit dem verwalteten Objekt zu vergleichen, das die Implementierung bereitstellt.The marshaler can readily identify interfaces exposed by managed objects and is able to match the interface with the managed object that provides the implementation. Das verwaltete Objekt wird dann an die Methode übergeben, und es wird kein Wrapper benötigt.The managed object is then passed to the method and no wrapper is needed.

  • Ein bereits umschlossenes Objekt implementiert die Schnittstelle.An object that has already been wrapped is implementing the interface. Um festzustellen, ob dies der Fall ist, fragt der Marshaller das Objekt nach seiner IUnknown-Schnittstelle, und vergleicht die zurückgegebene Schnittstelle mit den Schnittstellen von anderen Objekten, die bereits umschlossen sind.To determine whether this is the case, the marshaler queries the object for its IUnknown interface and compares the returned interface to the interfaces of other objects that are already wrapped. Wenn die Schnittstelle die gleiche wie die des anderen Wrappers ist, haben die Objekte die gleiche Identität, und der vorhandene Wrapper wird an die Methode übergeben.If the interface is the same as that of another wrapper, the objects have the same identity and the existing wrapper is passed to the method.

Wenn die Schnittstelle nicht von einem bekannten Objekt stammt, geht der Marshaller folgendermaßen vor:If an interface is not from a known object, the marshaler does the following:

  1. Der Marshaller fragt das Objekt nach seiner IProvideClassInfo2-Schnittstelle ab.The marshaler queries the object for the IProvideClassInfo2 interface. Wird diese zurückgegeben, verwendet der Marshaller die von IProvideClassInfo2.GetGUID zurückgegebene CLSID, um die Co-Klasse zu identifizieren, die die Schnittstelle bereitstellt.If provided, the marshaler uses the CLSID returned from IProvideClassInfo2.GetGUID to identify the coclass providing the interface. Mit der CLSID kann der Marshaller den Wrapper in der Registrierung finden, wenn die Assembly bereits registriert ist.With the CLSID, the marshaler can locate the wrapper from the registry if the assembly has previously been registered.

  2. Der Marshaller fragt die IProvideClassInfo-Schnittstelle der Schnittstelle ab.The marshaler queries the interface for the IProvideClassInfo interface. Wird diese zurückgegeben, verwendet der Marshaller die von IProvideClassInfo.GetClassinfo zurückgegebene ITypeInfo, um die CLSID der Klasse zu ermitteln, die die Schnittstelle verfügbar macht.If provided, the marshaler uses the ITypeInfo returned from IProvideClassInfo.GetClassinfo to determine the CLSID of the class exposing the interface. Der Marshaller kann die CLSID verwenden, um die Metadaten für den Wrapper zu finden.The marshaler can use the CLSID to locate the metadata for the wrapper.

  3. Wenn der Marshaller die Klasse immer noch nicht identifizieren kann, umschließt er die Schnittstelle mit einer generischen Wrapperklasse mit Namen System.__ComObject.If the marshaler still cannot identify the class, it wraps the interface with a generic wrapper class called System.__ComObject.

Standardmäßiges Marshalling für DelegatenDefault marshaling for delegates

Ein verwalteter Delegat wird als COM-Schnittstelle oder als Funktionszeiger gemarshallt, und zwar basierend auf dem Aufrufmechanismus:A managed delegate is marshaled as a COM interface or as a function pointer, based on the calling mechanism:

  • Für Plattformaufrufe wird ein Delegat standardmäßig als unverwalteter Funktionszeiger gemarshallt.For platform invoke, a delegate is marshaled as an unmanaged function pointer by default.

  • Für COM-Interop wird ein Delegat standardmäßig als COM-Schnittstelle vom Typ _Delegate gemarshallt.For COM interop, a delegate is marshaled as a COM interface of type _Delegate by default. Die _Delegate-Schnittstelle ist in der Typbibliothek Mscorlib.tlb definiert und enthält die Delegate.DynamicInvoke-Methode, mit der Sie in der Lage sind, die Methode aufzurufen, auf die der Delegat verweist.The _Delegate interface is defined in the Mscorlib.tlb type library and contains the Delegate.DynamicInvoke method, which enables you to call the method that the delegate references.

Die folgende Tabelle zeigt die Marshalling-Optionen für den Datentyp "Verwalteter Delegat".The following table shows the marshaling options for the managed delegate data type. Das MarshalAsAttribute-Attribut stellt mehrere UnmanagedType-Enumerationswerte zum Marshallen von Delegaten bereit.The MarshalAsAttribute attribute provides several UnmanagedType enumeration values to marshal delegates.

EnumerationstypEnumeration type Beschreibung des nicht verwalteten FormatsDescription of unmanaged format
UnmanagedType.FunctionPtrUnmanagedType.FunctionPtr Ein nicht verwaltete Funktionszeiger.An unmanaged function pointer.
UnmanagedType.InterfaceUnmanagedType.Interface Eine Schnittstelle von Typ _Delegate, wie in Mscorlib.tlb definiert.An interface of type _Delegate, as defined in Mscorlib.tlb.

Schauen Sie sich den folgenden Beispielcode an, in dem Methoden von DelegateTestInterface in eine COM-Typbibliothek exportiert werden.Consider the following example code in which the methods of DelegateTestInterface are exported to a COM type library. Beachten Sie, dass nur Delegaten, die mit dem Schlüsselwort ref (oder ByRef) gekennzeichnet sind, als In/Out-Parameter übergeben werden.Notice that only delegates marked with the ref (or ByRef) keyword are passed as In/Out parameters.

using System;  
using System.Runtime.InteropServices;  
  
public interface DelegateTest {  
void m1(Delegate d);  
void m2([MarshalAs(UnmanagedType.Interface)] Delegate d);     
void m3([MarshalAs(UnmanagedType.Interface)] ref Delegate d);    
void m4([MarshalAs(UnmanagedType.FunctionPtr)] Delegate d);   
void m5([MarshalAs(UnmanagedType.FunctionPtr)] ref Delegate d);     
}  

Darstellung der TypbibliothekType library representation

importlib("mscorlib.tlb");  
interface DelegateTest : IDispatch {  
[id(…)] HRESULT m1([in] _Delegate* d);  
[id(…)] HRESULT m2([in] _Delegate* d);  
[id(…)] HRESULT m3([in, out] _Delegate** d);  
[id()] HRESULT m4([in] int d);  
[id()] HRESULT m5([in, out] int *d);  
   };  

Ein Funktionszeiger kann dereferenziert werden, wie jeder andere nicht verwaltete Funktionszeiger dereferenziert werden kann.A function pointer can be dereferenced, just as any other unmanaged function pointer can be dereferenced.

In diesem Beispiel ist das Ergebnis ein int-Typ und ein Zeiger auf einen int-Typ, wenn zwei Delegaten als UnmanagedType.FunctionPtr gemarshallt werden.In this example, when the two delegates are marshaled as UnmanagedType.FunctionPtr, the result is an int and a pointer to an int. Da Delegattypen gemarshallt werden, stellt int hier einen Zeiger auf einen void*-Typ dar, der der Adresse des Delegaten im Arbeitsspeicher entspricht.Because delegate types are being marshaled, int here represents a pointer to a void (void*), which is the address of the delegate in memory. Das Ergebnis bezieht sich also auf 32-Bit-Windows-Systeme, da int in diesem Fall die Größe des Funktionszeigers darstellt.In other words, this result is specific to 32-bit Windows systems, since int here represents the size of the function pointer.

Hinweis

Ein Verweis auf den Funktionszeiger auf einen verwalteten Delegaten in nicht verwaltetem Code hindert die Common Language Runtime nicht daran, eine Garbage Collection für das verwaltete Objekt durchzuführen.A reference to the function pointer to a managed delegate held by unmanaged code does not prevent the common language runtime from performing garbage collection on the managed object.

Der folgende Code ist beispielsweise falsch, da der Verweis auf das cb-Objekt, der an die SetChangeHandler-Methode übergeben wurde, cb nicht über die Lebensdauer der Test-Methode hinaus gültig hält.For example, the following code is incorrect because the reference to the cb object, passed to the SetChangeHandler method, does not keep cb alive beyond the life of the Test method. Nachdem die Garbage Collection des cb-Objekts erfolgt ist, ist der an SetChangeHandler übergebene Funktionszeiger nicht mehr gültig.Once the cb object is garbage collected, the function pointer passed to SetChangeHandler is no longer valid.

public class ExternalAPI {  
   [DllImport("External.dll")]  
   public static extern void SetChangeHandler(  
      [MarshalAs(UnmanagedType.FunctionPtr)]ChangeDelegate d);  
}  
public delegate bool ChangeDelegate([MarshalAs(UnmanagedType.LPWStr) string S);  
public class CallBackClass {  
   public bool OnChange(string S){ return true;}  
}  
internal class DelegateTest {  
   public static void Test() {  
      CallBackClass cb = new CallBackClass();  
      // Caution: The following reference on the cb object does not keep the   
      // object from being garbage collected after the Main method   
      // executes.  
      ExternalAPI.SetChangeHandler(new ChangeDelegate(cb.OnChange));     
   }  
}  

Um der unerwarteten Garbage Collection entgegenzuwirken, muss der Aufrufer sicherstellen, dass das cb-Objekt gültig bleibt, solange der nicht verwaltete Funktionszeiger verwendet wird.To compensate for unexpected garbage collection, the caller must ensure that the cb object is kept alive as long as the unmanaged function pointer is in use. Optional können Sie dafür sorgen, dass der nicht verwaltete Code den verwalteten Code benachrichtigt, wenn der Funktionszeiger nicht mehr benötigt wird, wie das folgende Beispiel zeigt.Optionally, you can have the unmanaged code notify the managed code when the function pointer is no longer needed, as the following example shows.

internal class DelegateTest {  
   CallBackClass cb;  
   // Called before ever using the callback function.  
   public static void SetChangeHandler() {  
      cb = new CallBackClass();  
      ExternalAPI.SetChangeHandler(new ChangeDelegate(cb.OnChange));  
   }  
   // Called after using the callback function for the last time.  
   public static void RemoveChangeHandler() {  
      // The cb object can be collected now. The unmanaged code is   
      // finished with the callback function.  
      cb = null;  
   }  
}  

Standardmäßiges Marshalling für WerttypenDefault marshaling for value types

Die meisten Werttypen, wie ganze Zahlen und Gleitkommazahlen, sind blitfähig und müssen nicht gemarshallt werden.Most value types, such as integers and floating-point numbers, are blittable and do not require marshaling. Andere, nicht blitfähige Typen werden im verwalteten und im nicht verwalteten Speicher unterschiedlich dargestellt und müssen gemarshallt werden.Other non-blittable types have dissimilar representations in managed and unmanaged memory and do require marshaling. Wieder andere Typen erfordern eine explizite, über die Grenzen der Interoperation hinausgehende Formatierung.Still other types require explicit formatting across the interoperation boundary.

Dieser Abschnitt enthält Informationen zu den folgenden formatierten Werttypen:This section provides information on the following formatted value types:

Neben einer Beschreibung formatierter Typen befasst sich dieses Thema mit Systemwerttypen, die ein ungewöhnliches Marshallingverhalten aufweisen.In addition to describing formatted types, this topic identifies System Value Types that have unusual marshaling behavior.

Ein formatierter Typ ist ein komplexer Typ, der Informationen enthält, mit denen explizit das Layout seiner Member im Speicher gesteuert wird.A formatted type is a complex type that contains information that explicitly controls the layout of its members in memory. Informationen zum Memberlayout werden mit dem StructLayoutAttribute-Attribut bereitgestellt.The member layout information is provided using the StructLayoutAttribute attribute. Das Layout kann einen der folgenden LayoutKind-Enumerationswerte aufweisen:The layout can be one of the following LayoutKind enumeration values:

  • LayoutKind.AutomaticLayoutKind.Automatic

    Gibt an, dass die Common Language Runtime die Member dieses Typs aus Gründen der Effizienz frei neu anordnen kann.Indicates that the common language runtime is free to reorder the members of the type for efficiency. Wenn ein Werttyp allerdings an nicht verwalteten Code übergeben wird, ist das Layout der Member vorhersehbar.However, when a value type is passed to unmanaged code, the layout of the members is predictable. Der Versuch, eine solche Struktur automatisch zu marshallen, bewirkt eine Ausnahme.An attempt to marshal such a structure automatically causes an exception.

  • LayoutKind.SequentialLayoutKind.Sequential

    Gibt an, dass die Member des Typs im nicht verwalteten Speicher in der gleichen Reihenfolge angeordnet werden sollen, in der sie in der Definition des verwalteten Typs erscheinen.Indicates that the members of the type are to be laid out in unmanaged memory in the same order in which they appear in the managed type definition.

  • LayoutKind.ExplicitLayoutKind.Explicit

    Gibt an, dass die Member entsprechend dem FieldOffsetAttribute angeordnet werden, das mit jedem Feld angegeben wird.Indicates that the members are laid out according to the FieldOffsetAttribute supplied with each field.

Im Plattformaufruf verwendete WerttypenValue Types Used in Platform Invoke

Im folgenden Beispiel stellen die Typen Point und Rect Memberlayoutinformationen mithilfe von StructLayoutAttribute bereit.In the following example the Point and Rect types provide member layout information using the StructLayoutAttribute.

Imports System.Runtime.InteropServices  
<StructLayout(LayoutKind.Sequential)> Public Structure Point  
   Public x As Integer  
   Public y As Integer  
End Structure  
<StructLayout(LayoutKind.Explicit)> Public Structure Rect  
   <FieldOffset(0)> Public left As Integer  
   <FieldOffset(4)> Public top As Integer  
   <FieldOffset(8)> Public right As Integer  
   <FieldOffset(12)> Public bottom As Integer  
End Structure  
using System.Runtime.InteropServices;  
[StructLayout(LayoutKind.Sequential)]  
public struct Point {  
   public int x;  
   public int y;  
}     
  
[StructLayout(LayoutKind.Explicit)]  
public struct Rect {  
   [FieldOffset(0)] public int left;  
   [FieldOffset(4)] public int top;  
   [FieldOffset(8)] public int right;  
   [FieldOffset(12)] public int bottom;  
}  

Beim Marshallen an nicht verwalteten Code werden diese formatierten Typen als Strukturen im C-Stil gemarshallt.When marshaled to unmanaged code, these formatted types are marshaled as C-style structures. Dies bietet eine einfache Möglichkeit zum Aufrufen einer nicht verwalteten API, die über Strukturargumente verfügt.This provides an easy way of calling an unmanaged API that has structure arguments. So können die Strukturen POINT und RECT beispielsweise folgendermaßen an die PtInRect-Funktion der Microsoft Windows-API übergeben werden:For example, the POINT and RECT structures can be passed to the Microsoft Windows API PtInRect function as follows:

BOOL PtInRect(const RECT *lprc, POINT pt);  

Sie können Strukturen unter Verwendung der folgenden Definition des Plattformaufrufs übergeben:You can pass structures using the following platform invoke definition:

Friend Class NativeMethods
    Friend Declare Auto Function PtInRect Lib "User32.dll" (
        ByRef r As Rect, p As Point) As Boolean
End Class
internal static class NativeMethods
{
   [DllImport("User32.dll")]
   internal static extern bool PtInRect(ref Rect r, Point p);
}

Der Werttyp Rect muss mit einem Verweis übergeben werden, da die nicht verwaltete API einen Zeiger auf ein RECT erwartet, der an die Funktion übergeben wird.The Rect value type must be passed by reference because the unmanaged API is expecting a pointer to a RECT to be passed to the function. Der Werttyp Point wird nach Wert übergeben, da die nicht verwaltete API erwartet, dass POINT im Stack übergeben wird.The Point value type is passed by value because the unmanaged API expects the POINT to be passed on the stack. Dieser feine Unterschied ist sehr wichtig.This subtle difference is very important. Verweise werden als Zeiger an nicht verwalteten Code übergeben.References are passed to unmanaged code as pointers. Werte werden im Stack an nicht verwalteten Code übergeben.Values are passed to unmanaged code on the stack.

Hinweis

Wenn ein formatierter Typ als Struktur gemarshallt wird, kann nur auf die Felder im Typ zugegriffen werden.When a formatted type is marshaled as a structure, only the fields within the type are accessible. Wenn der Typ Methoden, Eigenschaften oder Ereignisse aufweist, kann auf diese vom nicht verwalteten Code nicht zugegriffen werden.If the type has methods, properties, or events, they are inaccessible from unmanaged code.

Klassen können ebenfalls an nicht verwalteten Code als Strukturen im C-Stil gemarshallt werden, vorausgesetzt, sie weisen ein festes Memberlayout auf.Classes can also be marshaled to unmanaged code as C-style structures, provided they have fixed member layout. Die Memberlayoutinformationen für eine Klasse werden ebenfalls mit dem StructLayoutAttribute-Attribut bereitgestellt.The member layout information for a class is also provided with the StructLayoutAttribute attribute. Der Hauptunterschied zwischen Werttypen mit festen Layout und Klassen mit festem Layout ist die Art und Weise, wie diese an nicht verwalteten Code gemarshallt werden.The main difference between value types with fixed layout and classes with fixed layout is the way in which they are marshaled to unmanaged code. Werttypen werden nach Wert (im Stack) übergeben, und dementsprechend werden Änderungen, die von der aufgerufenen Instanz an Membern dieses Typs vorgenommen werden, dem Aufrufer nicht angezeigt.Value types are passed by value (on the stack) and consequently any changes made to the members of the type by the callee are not seen by the caller. Verweistypen werden als Verweis übergeben (ein Verweis auf den Typ wird in den Stack übergeben); dementsprechend werden alle Änderungen, die von der aufgerufenen Instanz an blitfähigen Membern des Typs vorgenommen werden, für den Aufrufer angezeigt.Reference types are passed by reference (a reference to the type is passed on the stack); consequently, all changes made to blittable-type members of a type by the callee are seen by the caller.

Hinweis

Wenn ein Verweistyp nicht blitfähige Typen als Member enthält, muss die Konvertierung zwei Mal erfolgen: Das erste Mal, wenn ein Argument an die nicht verwaltete Seite übergeben wird, zum zweiten Mal bei der Rückgabe aus dem Aufruf.If a reference type has members of non-blittable types, conversion is required twice: the first time when an argument is passed to the unmanaged side and the second time on return from the call. Aufgrund dieses zusätzlichen Aufwands müssen In/Out-Parameter explizit auf ein Argument angewendet werden, wenn der Aufrufer Änderungen sehen möchte, die von der aufgerufenen Instanz vorgenommen wurden.Due to this added overhead, In/Out parameters must be explicitly applied to an argument if the caller wants to see changes made by the callee.

Im folgenden Beispiel hat die SystemTime-Klasse ein sequenzielles Memberlayout und kann an die GetSystemTime-Funktion der Windows-API übergeben werden.In the following example, the SystemTime class has sequential member layout and can be passed to the Windows API GetSystemTime function.

<StructLayout(LayoutKind.Sequential)> Public Class SystemTime  
   Public wYear As System.UInt16  
   Public wMonth As System.UInt16  
   Public wDayOfWeek As System.UInt16  
   Public wDay As System.UInt16  
   Public wHour As System.UInt16  
   Public wMinute As System.UInt16  
   Public wSecond As System.UInt16  
   Public wMilliseconds As System.UInt16  
End Class  
[StructLayout(LayoutKind.Sequential)]  
   public class SystemTime {  
   public ushort wYear;   
   public ushort wMonth;  
   public ushort wDayOfWeek;   
   public ushort wDay;   
   public ushort wHour;   
   public ushort wMinute;   
   public ushort wSecond;   
   public ushort wMilliseconds;   
}  

Die GetSystemTime-Funktion ist wie folgt definiert:The GetSystemTime function is defined as follows:

void GetSystemTime(SYSTEMTIME* SystemTime);  

Die entsprechende Definition des Plattformaufrufs für GetSystemTime lautet wie folgt:The equivalent platform invoke definition for GetSystemTime is as follows:

Friend Class NativeMethods
    Friend Declare Auto Sub GetSystemTime Lib "Kernel32.dll" (
        ByVal sysTime As SystemTime)
End Class
internal static class NativeMethods
{
   [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
   internal static extern void GetSystemTime(SystemTime st);
}

Beachten Sie, dass das SystemTime-Argument nicht als Verweisargument typisiert ist, da SystemTime eine Klasse und kein Werttyp ist.Notice that the SystemTime argument is not typed as a reference argument because SystemTime is a class, not a value type. Im Gegensatz zu Werttypen werden Klassen im durch Verweis übergeben.Unlike value types, classes are always passed by reference.

Das folgende Codebeispiel zeigt eine andere Point-Klasse, die eine Methode mit Namen SetXY aufweist.The following code example shows a different Point class that has a method called SetXY. Der der Typ über ein sequenzielles Layout verfügt, kann er an nicht verwalteten Code übergeben und als Struktur gemarshallt werden.Because the type has sequential layout, it can be passed to unmanaged code and marshaled as a structure. Der SetXY-Member kann jedoch nicht von nicht verwaltetem Code aufgerufen werden, obwohl das Objekt durch Verweis übergeben wird.However, the SetXY member is not callable from unmanaged code, even though the object is passed by reference.

<StructLayout(LayoutKind.Sequential)> Public Class Point  
   Private x, y As Integer  
   Public Sub SetXY(x As Integer, y As Integer)  
      Me.x = x  
      Me.y = y  
   End Sub  
End Class  
[StructLayout(LayoutKind.Sequential)]  
public class Point {  
   int x, y;  
   public void SetXY(int x, int y){   
      this.x = x;  
      this.y = y;  
   }  
}  

In COM-Interop verwendete WerttypenValue Types Used in COM Interop

Formatierte Typen können auch an COM-Interop-Methodenaufrufe übergeben werden.Formatted types can also be passed to COM interop method calls. Tatsache ist, dass Werttypen automatisch in Strukturen konvertiert werden, wenn sie in eine Typbibliothek exportiert werden.In fact, when exported to a type library, value types are automatically converted to structures. Wie im folgenden Beispiel gezeigt, wird der Point-Werttyp zu einer Typdefinition (typedef) mit Namen Point.As the following example shows, the Point value type becomes a type definition (typedef) with the name Point. Alle Verweise auf den Point-Werttyp an anderer Stelle in der Typbibliothek werden durch die Point-Typdefinition ersetzt.All references to the Point value type elsewhere in the type library are replaced with the Point typedef.

Darstellung der TypbibliothekType library representation

typedef struct tagPoint {  
   int x;  
   int y;  
} Point;  
interface _Graphics {  
   …  
   HRESULT SetPoint ([in] Point p)  
   HRESULT SetPointRef ([in,out] Point *p)  
   HRESULT GetPoint ([out,retval] Point *p)  
}  

Die gleichen Regeln, die zum Marshallen von Werten und Verweisen an Plattformaufrufe gelten, gelten auch beim Marshallen über COM-Schnittstellen.The same rules used to marshal values and references to platform invoke calls are used when marshaling through COM interfaces. Wenn eine Instanz des Point-Werttyps von .NET Framework an COM übergeben wird, wird der Point nach Wert übergeben.For example, when an instance of the Point value type is passed from the .NET Framework to COM, the Point is passed by value. Wenn der Point-Werttyp durch Verweis übergeben wird, wird ein Zeiger auf den Point in den Stack übergeben.If the Point value type is passed by reference, a pointer to a Point is passed on the stack. Der Interop-Marshaller unterstützt kein höheres Maß an Dereferenzierung (Point **) in beide Richtungen.The interop marshaler does not support higher levels of indirection (Point **) in either direction.

Hinweis

Strukturen, bei denen der LayoutKind-Enumerationswert auf Explicit (Explizit) festgelegt ist, können in COM-Interop nicht verwendet werden, da die exportierte Typbibliothek kein explizites Layout darstellen kann.Structures having the LayoutKind enumeration value set to Explicit cannot be used in COM interop because the exported type library cannot express an explicit layout.

SystemwerttypenSystem Value Types

Der System-Namespace enthält mehrere Werttypen, die für die geschaltete Form von primitiven Datentypen der Laufzeit stehen.The System namespace has several value types that represent the boxed form of the runtime primitive types. Beispielsweise steht die Werttypstruktur System.Int32 für die geschachtelte Form von ELEMENT_TYPE_I4.For example, the value type System.Int32 structure represents the boxed form of ELEMENT_TYPE_I4. Anstatt diese Typen als Strukturen zu marshallen, wie dies bei anderen formatierten Typen der Fall ist, marshallen Sie sie in der gleichen Weise wie die primitiven Datentypen, die sie schachteln.Instead of marshaling these types as structures, as other formatted types are, you marshal them in the same way as the primitive types they box. System.Int32 wird daher als ELEMENT_TYPE_I4 anstatt als eine Struktur gemarshallt, die ein einziges Mitglied vom Typ long enthält.System.Int32 is therefore marshaled as ELEMENT_TYPE_I4 instead of as a structure containing a single member of type long. Die folgende Tabelle enthält eine Liste der Werttypen im Namespace System, bei denen es sich um geschachtelte Darstellungen von primitiven Datentypen handelt.The following table contains a list of the value types in the System namespace that are boxed representations of primitive types.

SystemwerttypSystem value type ElementtypElement type
System.Boolean ELEMENT_TYPE_BOOLEANELEMENT_TYPE_BOOLEAN
System.SByte ELEMENT_TYPE_I1ELEMENT_TYPE_I1
System.Byte ELEMENT_TYPE_UI1ELEMENT_TYPE_UI1
System.Char ELEMENT_TYPE_CHARELEMENT_TYPE_CHAR
System.Int16 ELEMENT_TYPE_I2ELEMENT_TYPE_I2
System.UInt16 ELEMENT_TYPE_U2ELEMENT_TYPE_U2
System.Int32 ELEMENT_TYPE_I4ELEMENT_TYPE_I4
System.UInt32 ELEMENT_TYPE_U4ELEMENT_TYPE_U4
System.Int64 ELEMENT_TYPE_I8ELEMENT_TYPE_I8
System.UInt64 ELEMENT_TYPE_U8ELEMENT_TYPE_U8
System.Single ELEMENT_TYPE_R4ELEMENT_TYPE_R4
System.Double ELEMENT_TYPE_R8ELEMENT_TYPE_R8
System.String ELEMENT_TYPE_STRINGELEMENT_TYPE_STRING
System.IntPtr ELEMENT_TYPE_IELEMENT_TYPE_I
System.UIntPtr ELEMENT_TYPE_UELEMENT_TYPE_U

Einige andere Werttypen im Namespace System werden anders verarbeitet.Some other value types in the System namespace are handled differently. Da der nicht verwaltete Code bereits über gut eingeführte Formate für diese Typen verfügt, geht der Marshaller nach speziellen Regel beim Marshallen dieser Typen vor.Because the unmanaged code already has well-established formats for these types, the marshaler has special rules for marshaling them. Die folgende Tabelle führt die speziellen Werttypen im Namespace System sowie den nicht verwalteten Typ auf, an den sie gemarshallt werden.The following table lists the special value types in the System namespace, as well as the unmanaged type they are marshaled to.

SystemwerttypSystem value type IDL-TypIDL type
System.DateTime DATEDATE
System.Decimal DECIMALDECIMAL
System.Guid GUIDGUID
System.Drawing.Color OLE_COLOROLE_COLOR

Der folgende Code zeigt die Definition der nicht verwalteten Typen DATE, GUID, DECIMAL und OLE_COLOR in der Stdole2-Typbibliothek.The following code shows the definition of the unmanaged types DATE, GUID, DECIMAL, and OLE_COLOR in the Stdole2 type library.

Darstellung der TypbibliothekType library representation

typedef double DATE;  
typedef DWORD OLE_COLOR;  
  
typedef struct tagDEC {  
    USHORT    wReserved;  
    BYTE      scale;  
    BYTE      sign;  
    ULONG     Hi32;  
    ULONGLONG Lo64;  
} DECIMAL;  
  
typedef struct tagGUID {  
    DWORD Data1;  
    WORD  Data2;  
    WORD  Data3;  
    BYTE  Data4[ 8 ];  
} GUID;  

Der folgende Code zeigt die entsprechenden Definitionen in der verwalteten IValueTypes-Schnittstelle.The following code shows the corresponding definitions in the managed IValueTypes interface.

Public Interface IValueTypes  
   Sub M1(d As System.DateTime)  
   Sub M2(d As System.Guid)  
   Sub M3(d As System.Decimal)  
   Sub M4(d As System.Drawing.Color)  
End Interface  
public interface IValueTypes {  
   void M1(System.DateTime d);  
   void M2(System.Guid d);  
   void M3(System.Decimal d);  
   void M4(System.Drawing.Color d);  
}  

Darstellung der TypbibliothekType library representation

[…]  
interface IValueTypes : IDispatch {  
   HRESULT M1([in] DATE d);  
   HRESULT M2([in] GUID d);  
   HRESULT M3([in] DECIMAL d);  
   HRESULT M4([in] OLE_COLOR d);  
};  

Siehe auchSee also