Teilen über


Standardmarshallingverhalten

Interop-Marshalling funktioniert mit Regeln, die bestimmen, wie sich Daten, die Methodenparametern zugeordnet sind, verhalten, wenn sie zwischen verwaltetem und nicht verwaltetem Speicher übergeben werden. Diese integrierten Regeln steuern Marshallaktivitäten wie die Transformation von Datentypen, ob ein Angerufener die übergebenen Daten ändern und diese Änderungen an den Aufrufer zurückgeben kann, und unter welchen Umständen der Marshaller Leistungsoptimierungen vornimmt.

In diesem Abschnitt werden die Standardverhaltensmerkmale des Interop-Marshalling-Diensts beschrieben. Er enthält detaillierte Informationen zum Marshallen von Arrays, booleschen Typen, Zeichentypen, Delegaten, Klassen, Objekten, Zeichenfolgen und Strukturen.

Hinweis

Das Marshalling von generischen Typen wird nicht unterstützt. Weitere Informationen finden Sie unter "Interoperating Using Generic Types".

Speicherverwaltung mit dem Interop-Marshaller

Der Interop-Marshaller versucht immer, den von nicht verwaltetem Code belegten Speicher freizugeben. Dieses Verhalten entspricht den COM-Speicherverwaltungsregeln, unterscheidet sich jedoch von den Regeln, die systemeigene C++ regeln.

Es kann zu Verwirrung kommen, wenn Sie das systemeigene Verhalten von C++ (keine Speicherfreigabe) erwarten, beim Verwenden des Plattform-Aufrufs, der automatisch Speicher für Zeiger freigibt. Wenn Sie beispielsweise die folgende nicht verwaltete Methode aus einer C++-DLL aufrufen, wird kein Arbeitsspeicher automatisch freigegeben.

Nicht verwaltete Signatur

BSTR MethodOne (BSTR b) {
     return b;
}

Wenn Sie die Methode jedoch als Plattformaufrufprototyp definieren, ersetzen Sie jeden BSTR Typ durch einen String Typ und rufen Sie MethodOne auf, versucht die Common Language Runtime, b zweimal freizugeben. Sie können das Marshallverhalten ändern, indem Sie IntPtr-Typen anstelle von String-Typen verwenden.

Die Laufzeit verwendet immer die CoTaskMemFree Methode unter Windows und free methode auf anderen Plattformen, um Arbeitsspeicher freizugeben. Wenn der Arbeitsspeicher, mit dem Sie arbeiten, nicht der CoTaskMemAlloc Methode auf Windows oder malloc der Methode auf anderen Plattformen zugeordnet wurde, müssen Sie den IntPtr Speicher manuell mit der entsprechenden Methode freigeben. Ebenso können Sie das automatische Freigeben von Arbeitsspeicher in Situationen vermeiden, in denen Arbeitsspeicher nie freigegeben werden sollte, z. B. bei Verwendung der GetCommandLine Funktion von Kernel32.dll, die einen Zeiger auf den Kernelspeicher zurückgibt. Ausführliche Informationen zum manuellen Freigeben von Arbeitsspeicher finden Sie im Pufferbeispiel.

Standardmäßiges Marshalling für Klassen

Klassen können nur durch COM-Interop gemarshallt werden und werden immer als Schnittstellen gemarshallt. In einigen Fällen wird die Schnittstelle, die zum Marshallen der Klasse verwendet wird, als Klassenschnittstelle bezeichnet. Informationen zum Überschreiben der Klassenschnittstelle mit einer von Ihnen gewählten Schnittstelle finden Sie unter Einführung in die Klassenschnittstelle.

Übergeben von Klassen an 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 erzeugte Klassenschnittstelle an den COM-Methodenaufruf. Der Proxy delegiert dann alle Aufrufe der Klassenschnittstelle zurück an das verwaltete Objekt. Der Proxy macht auch andere Schnittstellen verfügbar, die nicht explizit von der Klasse implementiert werden. Der Proxy implementiert automatisch Schnittstellen wie IUnknown und IDispatch im Auftrag der Klasse.

Übergeben von Klassen an .NET-Code

Coclasses werden in der Regel nicht als Methodenargumente in COM verwendet. Stattdessen wird anstelle der Coclass eine Standardschnittstelle übergeben.

Wenn eine Schnittstelle an verwalteten Code übergeben wird, ist der Interop-Marshaller dafür verantwortlich, die Schnittstelle mit dem richtigen Wrapper umzuschließen und den Wrapper an die verwaltete Methode zu übergeben. Das Bestimmen des zu verwendenden Wrappers kann schwierig sein. Jede Instanz eines COM-Objekts verfügt über einen einzelnen, eindeutigen Wrapper, unabhängig davon, wie viele Schnittstellen das Objekt implementiert. Ein einzelnes COM-Objekt, das fünf unterschiedliche Schnittstellen implementiert, verfügt beispielsweise nur über einen Wrapper. Derselbe Wrapper macht alle fünf Schnittstellen verfügbar. Wenn zwei Instanzen des COM-Objekts erstellt werden, werden zwei Instanzen des Wrappers erstellt.

Damit der Wrapper denselben Typ während seiner gesamten Lebensdauer beibehalten kann, muss der Interop-Marshaller den richtigen Wrapper identifizieren, sobald eine Schnittstelle, die vom Objekt bereitgestellt wird, erstmals durch den Marshaller übergeben wird. Der Marshaller identifiziert das Objekt, indem er eine der Schnittstellen betrachtet, die das Objekt implementiert.

So bestimmt der Marshaller beispielsweise, dass der Klassenwrapper zum Umschließen der Schnittstelle verwendet werden soll, die an verwalteten Code übergeben wurde. Wenn die Schnittstelle zum ersten Mal über den Marshaller übergeben wird, überprüft der Marshaller, ob die Schnittstelle von einem bekannten Objekt stammt. Diese Überprüfung erfolgt in zwei Situationen:

  • Eine Schnittstelle wird von einem anderen verwalteten Objekt implementiert, das an COM an anderer Stelle übergeben wurde. Der Marshaller kann schnittstellen, die von verwalteten Objekten verfügbar gemacht werden, leicht identifizieren und die Schnittstelle mit dem verwalteten Objekt abgleichen, das die Implementierung bereitstellt. Das verwaltete Objekt wird dann an die Methode übergeben, und es ist kein Wrapper erforderlich.

  • Ein Objekt, das bereits umschlossen wurde, implementiert die Schnittstelle. Um festzustellen, ob dies der Fall ist, fragt der Marshaller das Objekt für seine IUnknown Schnittstelle ab und vergleicht die zurückgegebene Schnittstelle mit den Schnittstellen anderer Objekte, die bereits umschlossen sind. Wenn die Schnittstelle mit dem eines anderen Wrappers identisch ist, weisen die Objekte dieselbe Identität auf, und der vorhandene Wrapper wird an die Methode übergeben.

Wenn eine Schnittstelle nicht aus einem bekannten Objekt stammt, führt der Marshaller die folgenden Aktionen aus:

  1. Der Marshaller fragt das Objekt nach seiner IProvideClassInfo2-Schnittstelle ab. Wenn angegeben, verwendet der Marshaller die von IProvideClassInfo2.GetGUID zurückgegebene CLSID, um die coclass zu identifizieren, die die Schnittstelle bereitstellt. Mit der CLSID kann der Marshaller den Wrapper in der Registrierung finden, wenn die Assembly bereits registriert ist.

  2. Der Marshaller fragt die Schnittstelle für die IProvideClassInfo Schnittstelle ab. Wenn vorhanden, verwendet der Marshaller die von IProvideClassInfo.GetClassinfo zurückgegebene ITypeInfo, um die CLSID der Klasse zu ermitteln, die die Schnittstelle bereitstellt. Der Marshaller kann die CLSID verwenden, um die Metadaten für den Wrapper zu finden.

  3. Wenn der Marshaller die Klasse immer noch nicht identifizieren kann, wird die Schnittstelle mit einer generischen Wrapperklasse namens System.__ComObject umschlossen.

Standardmäßiges Marshalling für Delegaten

Ein verwalteter Delegat wird als COM-Schnittstelle oder als Funktionszeiger gemarshallt, und zwar basierend auf dem Aufrufmechanismus:

  • Für Plattformaufrufe wird ein Delegat standardmäßig als nicht verwalteter Funktionszeiger gemarshallt.

  • Bei COM-Interoperabilität wird ein Delegat standardmäßig als COM-Schnittstelle vom Typ _Delegate gemarshallt. Die _Delegate Schnittstelle ist in der Mscorlib.tlb-Typbibliothek definiert und enthält die Delegate.DynamicInvoke Methode, die es Ihnen ermöglicht, die Methode aufzurufen, auf die der Delegat verweist.

In der folgenden Tabelle sind die Marshalloptionen für den Datentyp "Verwaltete Stellvertretung" aufgeführt. Das MarshalAsAttribute-Attribut stellt mehrere UnmanagedType-Enumerationswerte zum Marshallen von Delegaten bereit.

Enumerationstyp Beschreibung des nicht verwalteten Formats
UnmanagedType.FunctionPtr Ein nicht verwalteter Funktionszeiger.
UnmanagedType.Interface Eine Schnittstelle vom Typ _Delegate, wie in Mscorlib.tlb definiert.

Betrachten Sie den folgenden Beispielcode, in dem die Methoden DelegateTestInterface in eine COM-Typbibliothek exportiert werden. Beachten Sie, dass nur Delegaten, die mit dem ref Schlüsselwort (oder ByRef) gekennzeichnet sind, als In/Out-Parameter übergeben werden.

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 Typbibliothek

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, genauso wie jeder andere nicht verwaltete Funktionszeiger dereferenziert werden kann.

In diesem Beispiel ist das Ergebnis ein UnmanagedType.FunctionPtr-Typ und ein Zeiger auf einen int-Typ, wenn zwei Delegaten als int gemarshallt werden. Da Delegattypen gemarshallt werden, stellt int hier einen Zeiger auf einen void*-Typ dar, der der Adresse des Delegaten im Arbeitsspeicher entspricht. Mit anderen Worten, dieses Ergebnis ist spezifisch für 32-Bit-Windows-Systeme, da int hier die Größe des Funktionszeigers darstellt.

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.

Der folgende Code ist beispielsweise falsch, da der Verweis auf das cb Objekt, das an die SetChangeHandler Methode übergeben wird, nicht über die Lebensdauer der cb Methode hinaus erhalten bleibtTest. Nachdem die Garbage Collection des cb-Objekts erfolgt ist, ist der an SetChangeHandler übergebene Funktionszeiger nicht mehr gültig.

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. Optional können Sie den nicht verwalteten Code benachrichtigen lassen, wenn der Funktionszeiger nicht mehr benötigt wird, wie im folgenden Beispiel gezeigt.

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 Werttypen

Die meisten Werttypen, z. B. Ganze Zahlen und Gleitkommazahlen, sind blittbar und erfordern kein Marshalling. Andere, nicht blitfähige Typen werden im verwalteten und im nicht verwalteten Speicher unterschiedlich dargestellt und müssen gemarshallt werden. Für andere Typen ist eine explizite Formatierung über die Interoperationsgrenze erforderlich.

Dieser Abschnitt enthält Informationen zu den folgenden formatierten Werttypen:

Zusätzlich zur Beschreibung formatierter Typen identifiziert dieses Thema Systemwerttypen , die ein ungewöhnliches Marshallverhalten aufweisen.

Ein formatierter Typ ist ein komplexer Typ, der Informationen enthält, die das Layout seiner Elemente im Arbeitsspeicher explizit steuern. Informationen zum Memberlayout werden mit dem StructLayoutAttribute-Attribut bereitgestellt. Das Layout kann einen der folgenden LayoutKind-Enumerationswerte aufweisen:

  • LayoutKind.Auto

    Gibt an, dass die Common Language Runtime die Member dieses Typs aus Gründen der Effizienz frei neu anordnen kann. Wenn jedoch ein Werttyp an nicht verwalteten Code übergeben wird, ist das Layout der Member vorhersehbar. Ein Versuch, eine solche Struktur zu marshallen, verursacht automatisch eine Ausnahme.

  • LayoutKind.Sequenziell

    Gibt an, dass die Elemente des Typs in nicht verwaltetem Speicher in derselben Reihenfolge angeordnet werden sollen, in der sie in der Definition des verwalteten Typs angezeigt werden.

  • LayoutKind.Explicit

    Gibt an, dass die Mitglieder gemäß dem mit jedem Feld bereitgestellten FieldOffsetAttribute angeordnet sind.

Werttypen, die im Plattform-Aufruf verwendet werden

Im folgenden Beispiel stellen die Typen Point und Rect Memberlayoutinformationen mithilfe von StructLayoutAttribute bereit.

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. Dies bietet eine einfache Möglichkeit, eine nicht verwaltete API mit Strukturargumenten aufzurufen. Beispielsweise können die POINT Strukturen und RECT Strukturen wie folgt an die Microsoft Windows-API-Funktion PtInRect übergeben werden:

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

Sie können Strukturen mithilfe der folgenden Plattform-Aufrufdefinition übergeben:

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 Rect Werttyp muss per Verweis übergeben werden, da die nicht verwaltete API erwartet, dass ein Zeiger auf eine RECT an die Funktion übergeben wird. Der Werttyp Point wird nach Wert übergeben, da die nicht verwaltete API erwartet, dass POINT im Stack übergeben wird. Dieser subtile Unterschied ist sehr wichtig. Verweise werden als Zeiger an nicht verwalteten Code übergeben. Werte werden an nicht verwalteten Code im Stapel übergeben.

Hinweis

Wenn ein formatierter Typ als Struktur ge marshallt wird, sind nur die Felder innerhalb des Typs zugänglich. Wenn der Typ Über Methoden, Eigenschaften oder Ereignisse verfügt, können sie von nicht verwaltetem Code nicht darauf zugreifen.

Klassen können ebenfalls an nicht verwalteten Code als Strukturen im C-Stil gemarshallt werden, vorausgesetzt, sie weisen ein festes Memberlayout auf. Die Elementlayoutinformationen für eine Klasse werden auch mit dem StructLayoutAttribute Attribut bereitgestellt. Der Hauptunterschied zwischen Werttypen mit festem Layout und Klassen mit festem Layout ist die Art und Weise, in der sie in nicht verwalteten Code gemanshallt werden. 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. 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.

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. Aufgrund dieses zusätzlichen Aufwands müssen die In/Out-Parameter explizit auf ein Argument angewendet werden, wenn der Aufrufer die vom Angerufenen vorgenommenen Änderungen sehen möchte.

Im folgenden Beispiel verfügt die SystemTime Klasse über ein sequenzielles Memberlayout und kann an die Windows-API-Funktion GetSystemTime übergeben werden.

<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 wird wie folgt definiert:

void GetSystemTime(SYSTEMTIME* SystemTime);

Die entsprechende Plattform-Aufrufdefinition lautet GetSystemTime wie folgt:

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 eingegeben wird, da es sich um SystemTime eine Klasse und nicht um einen Werttyp handelt. Im Gegensatz zu Werttypen werden Klassen immer per Verweis übergeben.

Das folgende Codebeispiel zeigt eine andere Point Klasse, die eine Methode mit dem Namen hat SetXY. Der der Typ über ein sequenzielles Layout verfügt, kann er an nicht verwalteten Code übergeben und als Struktur gemarshallt werden. Das SetXY Element kann jedoch nicht aus nicht verwaltetem Code aufgerufen werden, auch wenn das Objekt per Verweis übergeben wird.

<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 der COM-Interoperabilität verwendete Werttypen

Formatierte Typen können auch an COM-Interopmethodenaufrufe übergeben werden. Wenn sie in eine Typbibliothek exportiert werden, werden Werttypen automatisch in Strukturen konvertiert. Wie im folgenden Beispiel gezeigt, wird der Point Werttyp zu einer Typdefinition (typedef) mit dem Namen Point. Alle Verweise auf den Point Werttyp an anderer Stelle in der Typbibliothek werden durch den Point Typedef ersetzt.

Darstellung der Typbibliothek

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. Wenn beispielsweise eine Instanz des Werttyps Point vom .NET Framework an COM übergeben wird, erfolgt die Übergabe des Point-Werts als Wert. Wenn der Point-Werttyp durch Verweis übergeben wird, wird ein Zeiger auf den Point in den Stack übergeben. Der Interop-Marshaller unterstützt kein höheres Maß an Dereferenzierung (Point **) in beide Richtungen.

Hinweis

Strukturen, für die der LayoutKind Enumerationswert auf Explicit festgelegt ist, können in der COM-Interoperabilität nicht verwendet werden, da die exportierte Typbibliothek kein explizites Layout darstellen kann.

Systemwerttypen

Der System Namespace verfügt über mehrere Werttypen, die die Boxform der Laufzeitgrundtypen darstellen. Die Werttypstruktur System.Int32 stellt z. B. die Boxform ELEMENT_TYPE_I4 dar. 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. System.Int32 wird daher als ELEMENT_TYPE_I4 anstelle einer Struktur gemarshallt, die ein einzelnes Element vom Typ long enthält. Die folgende Tabelle enthält eine Liste der Werttypen im System Namespace, die boxte Darstellungen von Grundtyptypen sind.

Systemwerttyp Elementtyp
System.Boolean ELEMENT_TYPE_BOOLEAN
System.SByte ELEMENT_TYPE_I1
System.Byte ELEMENT_TYPE_UI1
System.Char ELEMENT_TYPE_CHAR
System.Int16 ELEMENT_TYPE_I2
System.UInt16 ELEMENT_TYPE_U2
System.Int32 ELEMENT_TYPE_I4
System.UInt32 ELEMENT_TYPE_U4
System.Int64 ELEMENT_TYPE_I8
System.UInt64 ELEMENT_TYPE_U8
System.Single ELEMENT_TYPE_R4
System.Double ELEMENT_TYPE_R8
System.String ELEMENT_TYPE_STRING
System.IntPtr ELEMENT_TYPE_I
System.UIntPtr ELEMENT_TYPE_U

Einige andere Werttypen im System Namespace werden unterschiedlich behandelt. 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. In der folgenden Tabelle sind die speziellen Werttypen im System-Namespace sowie der nicht verwaltete Typ aufgeführt, an den sie gemarshallt werden.

Systemwerttyp IDL-Typ
System.DateTime DATUM
System.Decimal DEZIMAL
System.Guid GUID
System.Drawing.Color OLE_COLOR

Der folgende Code zeigt die Definition der nicht verwalteten Typen DATE, GUID, DECIMAL und OLE_COLOR in der Stdole2-Typbibliothek.

Darstellung der Typbibliothek

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.

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 Typbibliothek

[…]
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 auch