Freigeben über


Standardmäßiges Marshalling für Arrays

In Anwendungen, die ausschließlich aus verwaltetem Code bestehen, übergibt die Common Language Runtime Arraytypen als In/Out-Parameter. Der Interop-Marshaller übergibt Arrays dagegen standardmäßig als In-Parameter.

Bei Verwendung der Fixierungsoptimierung kann ein blitfähiges Array beim Zusammenwirken mit Objekten in demselben Apartment den Anschein erwecken, dass es als In/Out-Parameter fungiert. Wenn Sie den Code jedoch später in eine Typbibliothek exportieren, mit der der computerübergreifende Proxy generiert wird, und diese Bibliothek dazu verwendet wird, die apartmentübergreifenden Aufrufe zu marshallen, verhalten sich die Aufrufe möglicherweise wieder wie wirkliche In-Parameter.

Arrays sind naturgemäß komplex, und die Unterschiede zwischen verwalteten und nicht verwalteten Arrays bieten mehr Informationen als andere nicht blitfähige Typen. In diesem Thema erhalten Sie folgende Informationen zum Marshalling von Arrays:

  • Verwaltete Arrays

  • Nicht verwaltete Arrays

  • Übergeben von Arrayparametern an .NET-Code

  • Übergeben von Arrays an COM

Verwaltete Arrays

Zwischen verwalteten Arraytypen können Unterschiede bestehen, die Basisklasse aller Arraytypen ist jedoch die System.Array-Klasse. Die System.Array-Klasse enthält Eigenschaften zur Bestimmung des Ranges, der Länge und der Ober- und Untergrenze eines Arrays sowie Methoden zum Abrufen, Sortieren, Suchen, Kopieren und Erstellen von Arrays.

Diese Arraytypen sind dynamisch; für sie sind in der Basisklassenbibliothek keine entsprechenden statischen Typen vorhanden. Sie können sich jede Kombination aus Elementtyp und Rang als einen gesonderten Arraytyp vorstellen. Daher unterscheidet sich der Typ eines eindimensionalen Arrays von ganzen Zahlen von dem eines eindimensionalen Arrays von Double-Typen. In ähnlicher Weise unterscheidet sich ein zweidimensionales Array von ganzen Zahlen von einem eindimensionalen Array von ganzen Zahlen. Beim Vergleichen von Typen werden die Grenzen des Arrays nicht berücksichtigt.

Wie die folgende Tabelle zeigt, muss jede Instanz eines verwalteten Arrays über einen bestimmten Elementtyp, Rang und eine bestimmte Untergrenze verfügen.

Verwalteter Arraytyp Elementtyp Rang Unterer Grenzwert Signaturschreibweise

ELEMENT_TYPE_ARRAY

Durch den Typ angegeben.

Durch den Rang angegeben.

Optional durch Grenzen angegeben.

type [ n,m]

ELEMENT_TYPE_CLASS

Unbekannt

Unbekannt

Unbekannt

System.Array

ELEMENT_TYPE_SZARRAY

Durch den Typ angegeben.

1

0

type [ n ]

Nicht verwaltete Arrays

Nicht verwaltete Arrays sind sichere Arrays im COM-Format oder Arrays mit fester oder variabler Länge im C-Format. Sichere Arrays sind selbstbeschreibende Arrays, die Typ, Rang und Grenzen der zugeordneten Arraydaten enthalten. Arrays im C-Format sind eindimensionale typisierte Arrays mit einer festen Untergrenze 0. Der Marshallingdienst unterstützt beide Arraytypen nur begrenzt.

Übergeben von Arrayparametern an .NET-Code

Sowohl Arrays im C-Format als auch sichere Arrays können als sichere Arrays oder Array im C-Format aus nicht verwaltetem Code an .NET-Code übergeben werden. In der folgenden Tabelle sind der nicht verwaltete Typwert und der importierte Typ aufgelistet.

Nicht verwalteter Typ Importierter Typ

SafeArray( Type )

ELEMENT_TYPE_SZARRAY <KonvertierterTyp>

Rang = 1, Untergrenze = 0. Größe ist nur bekannt, wenn sie in der verwalteten Signatur enthalten ist. Sichere Arrays, bei denen Rang = 1 oder Untergrenze = 0 nicht gilt, können nicht als SZARRAY gemarshallt werden.

Type []

ELEMENT_TYPE_SZARRAY <KonvertierterTyp>

Rang = 1, Untergrenze = 0. Größe ist nur bekannt, wenn sie in der verwalteten Signatur enthalten ist.

Sichere Arrays

Wenn ein sicheres Array aus einer Typbibliothek in eine .NET-Assembly importiert wird, wird das Array in ein eindimensionales Array eines bekannten Typs (z. B. int) umgewandelt. Für Arrayelemente gelten dieselben Typumwandlungsregeln wie für Parameter. So wird ein sicheres Array von BSTR-Typen beispielsweise in ein verwaltetes Array von Zeichenfolgen und ein sicheres Array von Varianten in ein verwaltetes Array von Objekten umgewandelt. Der SAFEARRAY-Elementtyp wird aus der Typbibliothek abgerufen und im SAFEARRAY-Wert der UnmanagedType-Enumeration gespeichert.

Da der Rang und die Grenzen des sicheren Arrays über die Typbibliothek nicht bestimmt werden können, wird für den Rang ein Wert von 1 und für die Untergrenze ein Wert von 0 angenommen. Rang und Grenzen müssen in der durch das Type Library Importer-Tool (Tlbimp.exe) erstellten verwalteten Signatur definiert sein. Wenn sich der zur Laufzeit an die Methode übergebene Rang von diesem Wert unterscheidet, wird eine SafeArrayRankMismatchException ausgelöst. Wenn sich der zur Laufzeit übergebene Arraytyp von diesem Wert unterscheidet, wird eine SafeArrayTypeMismatchException ausgelöst. Im folgenden Beispiel werden sichere Arrays in verwaltetem und nicht verwaltetem Code gezeigt.

Nicht verwaltete Signatur

HRESULT New1([in] SAFEARRAY( int ) ar);
HRESULT New2([in] SAFEARRAY( DATE ) ar);
HRESULT New3([in, out] SAFEARRAY( BSTR ) *ar);

Verwaltete Signatur

Sub New1(<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VT_I4)> _
   ar() As Integer)
Sub New2(<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VT_DATE)> _ 
   ar() As DateTime)
Sub New3(ByRef <MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VT_BSTR)> _ 
   ar() As String)
void New1([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_I4)] int[] ar) ;
void New2([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_DATE)] 
   DateTime[] ar);
void New3([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_BSTR)] 
   ref String[] ar);

Mehrdimensionale sichere Arrays oder sichere Arrays mit einem Grenzwert ungleich 0 können in verwalteten Code gemarshallt werden, wenn die durch Tlbimp.exe erstellte Methodensignatur so geändert wird, dass sie anstelle des Elementtyps ELEMENT_TYPE_SZARRAY den Elementtyp ELEMENT_TYPE_ARRAY angibt. Alternativ dazu können Sie den /sysarray-Schalter mit Tlbimp.exe verwenden, um alle Arrays als System.Array-Objekte zu importieren. Wenn bekannt ist, dass das zu übergebende Array mehrdimensional ist, können Sie den von Tlbimp.exe erzeugten MSIL-Code (Microsoft Intermediate Language-Code) bearbeiten und anschließend neu kompilieren. Ausführliche Informationen zu Möglichkeiten, den MSIL-Code zu ändern, finden Sie unter Anpassen von durch die Laufzeit aufrufbaren Wrappern.

Arrays im C-Format

Wenn ein Array im C-Format aus einer Typbibliothek in eine .NET-Assembly importiert wird, wird das Array in ELEMENT_TYPE_SZARRAY umgewandelt.

Der Elementtyp des Arrays wird durch die Typbibliothek bestimmt und während des Imports beibehalten. Für Arrayelemente gelten dieselben Umwandlungsregeln wie für Parameter. Ein Array von LPStr-Typen wird beispielsweise in ein Array von String-Typen umgewandelt. Tlbimp.exe erfasst den Elementtyp des Arrays und wendet das MarshalAsAttribute-Attribut auf den Parameter an.

Für den Rang des Arrays wird der Wert 1 angenommen. Wenn der Rang größer als 1 ist, wird das Array als eindimensionales Array in der Reihenfolge der Spaltengröße gemarshallt. Die Untergrenze ist immer gleich 0.

Typbibliotheken können Arrays fester oder variabler Länge enthalten. Tlbimp.exe kann nur Arrays mit fester Länge aus Typbibliotheken importieren, weil Typbibliotheken nicht die zum Marshallen von Arrays mit variabler Länge erforderlichen Informationen enthalten. Bei Arrays mit fester Länge wird die Größe aus der Typbibliothek importiert und im MarshalAsAttribute, das auf den Parameter angewendet wird, erfasst.

Typbibliotheken mit Arrays mit variabler Länge müssen manuell definiert werden (siehe folgendes Beispiel).

Nicht verwaltete Signatur

HRESULT New1(int ar[10]);
HRESULT New2(double ar[10][20]);
HRESULT New3(LPWStr ar[10]);

Verwaltete Signatur

Sub New1(<MarshalAs(UnmanagedType.LPArray, SizeConst=10)> _
   ar() As Integer)
Sub New2(<MarshalAs(UnmanagedType.LPArray, SizeConst=200)> _
   ar() As Double)
Sub New2(<MarshalAs(UnmanagedType.LPArray, _
   ArraySubType=UnmanagedType.LPWStr, SizeConst=10)> _
   ar() As String)
void New1([MarshalAs(UnmanagedType.LPArray, SizeConst=10)] int[] ar);
void New2([MarshalAs(UnmanagedType.LPArray, SizeConst=200)] double[] ar);
void New2([MarshalAs(UnmanagedType.LPArray, 
   ArraySubType=UnmanagedType.LPWStr, SizeConst=10)] String[] ar);

Obwohl Sie das size_is-Attribut oder das length_is-Attribut auf ein Array in der Schnittstellendefinitionsquelle (IDL, Interface Definition Language) anwenden können, um einem Client die Größe mitzuteilen, überträgt der MIDL-Compiler (Microsoft Interface Definition Language-Compiler) diese Informationen nicht an die Typbibliothek. Ohne die Größe zu kennen, kann der Interop-Marshallingdienst die Arrayelemente nicht marshallen. Infolgedessen werden Arrays variabler Länge als Verweisargumente importiert. Beispiel:

Nicht verwaltete Signatur

HRESULT New1(int ar[]);
HRESULT New2(int ArSize, [size_is(ArSize)] double ar[]);
HRESULT New3(int ElemCnt, [length_is(ElemCnt)] LPStr ar[]);

Verwaltete Signatur

Sub New1(ByRef ar As Integer)
Sub New2(ByRef ar As Double)
Sub New3(ByRef ar As String)
void New1(ref int ar);  
void New2(ref double ar);  
void New3(ref String ar); 

Sie können dem Marshaller die Arraygröße zur Verfügung stellen, indem Sie den durch Tlbimp.exe erzeugten MSIL-Code (Microsoft Intermediate Language-Code) bearbeiten und anschließend neu kompilieren. Ausführliche Informationen zu Möglichkeiten, den MSIL-Code zu ändern, finden Sie unter Anpassen von durch die Laufzeit aufrufbaren Wrappern. Um die Anzahl der Elemente im Array anzuzeigen, wenden Sie das MarshalAsAttribute durch eine der folgenden Vorgehensweisen auf den Arrayparameter der verwalteten Methodendefinition an:

  • Geben Sie einen weiteren Parameter an, der die Anzahl der Elemente im Array enthält. Die Parameter werden nach Position angegeben. Dabei wird mit dem ersten Parameter als Nummer 0 begonnen. Das gesteuerte Array kann nicht als ref- oder out-Parameter übergeben werden. Ähnlich muss der Parameter, der die Größe des Arrays enthält, durch einen Wert übergeben werden (das SizeParamIndex-Feld kann nicht auf einen ref- oder out-Parameter verweisen). Beispiel:

    Sub [New](ElemCnt As Integer, _
       <MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> _
       ar() As Integer)
    
    void New(
       int ElemCnt, 
       [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] int[] ar );
    
  • Definieren Sie die Arraygröße als Konstante. Beispiel:

    Sub [New](<MarshalAs(UnmanagedType.LPArray, SizeConst:=128)> _
       ar() As Integer)
    
    void New(
       [MarshalAs(UnmanagedType.LPArray, SizeConst=128)] int[] ar );
    

Wenn Arrays aus nicht verwaltetem an verwalteten Code gemarshallt werden, überprüft der Marshaller das dem Parameter zugeordnete MarshalAsAttribute, um die Arraygröße zu bestimmen. Wenn die Arraygröße nicht angegeben ist, wird nur ein Element gemarshallt.

Hinweis

MarshalAsAttribute wirkt sich nicht auf das Marshallen verwalteter Arrays an nicht verwalteten Code aus. In dieser Richtung wird die Arraygröße durch Untersuchung festgestellt. Untergruppen verwalteter Arrays können nicht gemarshallt werden.

Um einen Speicherplatz zu reservieren und abzurufen, verwendet der Interop-Marshaller die CoTaskMemAlloc-Methode und die CoTaskMemFree-Methode. Diese Methoden müssen auch bei der Speicherreservierung durch nicht verwalteten Code verwendet werden.

Übergeben von Arrays an COM

Alle verwalteten Arraytypen können von verwaltetem Code an nicht verwalteten Code übergeben werden. In Abhängigkeit vom verwalteten Typ und den auf diesen Typ angewendeten Attributen kann das Array als sicheres Array oder als Array im C-Format abgerufen werden (siehe folgende Tabelle).

Verwalteter Arraytyp Exportiert als

ELEMENT_TYPE_SZARRAY <Typ>

UnmanagedType .SafeArray( type )

UnmanagedType.LPArray

Typ wird in der Signatur angegeben. Rang ist immer gleich 1, Untergrenze ist immer gleich 0. Größe ist immer zur Laufzeit bekannt.

ELEMENT_TYPE_ARRAY <Typ> <Rang>[<Grenzen>]

UnmanagedType.SafeArray( type )

UnmanagedType.LPArray

Typ, Rang und Grenzen werden in der Signatur angegeben. Größe ist immer zur Laufzeit bekannt.

ELEMENT_TYPE_CLASS <System.Array>

UT_Interface

UnmanagedType.SafeArray( type )

Typ, Rang, Grenzen und Größe sind immer zur Laufzeit bekannt.

ELEMENT_TYPE_SZARRAY

Wenn eine Methode mit einem ELEMENT_TYPE_SZARRAY-Parameter (eindimensionales Array) aus einer .NET-Assembly in eine Typbibliothek exportiert wird, wird der Arrayparameter in ein SAFEARRAY eines gegebenen Typs umgewandelt. Für Arrayelementtypen gelten dieselben Umwandlungsregeln. Der Inhalt des verwalteten Arrays wird automatisch aus dem verwalteten Speicher in das SAFEARRAY kopiert. Beispiel:

Verwaltete Signatur

Sub [New](ar() As Long)
Sub [New](ar() As String)
void New(long[] ar );
void New(String[] ar );

Nicht verwaltete Signatur

HRESULT New([in] SAFEARRAY( long ) ar); 
HRESULT New([in] SAFEARRAY( BSTR ) ar);

Der Rang des sicheren Arrays ist immer gleich 1 und die Untergrenze ist immer gleich 0. Die Größe wird zur Laufzeit anhand der Größe des übergebenen verwalteten Arrays bestimmt.

Bei Verwendung des MarshalAsAttribute-Attributs kann das Array auch als Array im C-Format gemarshallt werden. Beispiel:

Verwaltete Signatur

Sub [New](<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> _
   ar() As Long, size as Integer )
Sub [New](<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> _
   ar() As String, size as Integer )
Sub [New](<MarshalAs(UnmanagedType.LPArray, _
   ArraySubType= UnmanagedType.LPStr, SizeParamIndex:=1)> _
   ar() As String, size as Integer )
void New([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] 
   long [] ar, int size );
void New([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] 
   String [] ar, int size );
void New([MarshalAs(UnmanagedType.LPArray, ArraySubType= 
   UnmanagedType.LPStr, SizeParamIndex=1)] 
   String [] ar, int size );

Nicht verwaltete Signatur

HRESULT New(long ar[]); 
HRESULT New(BSTR ar[]); 
HRESULT New(LPStr ar[]);

Obwohl der Marshaller über die zum Marshallen des Arrays erforderlichen Längeninformationen verfügt, wird die Arraylänge normalerweise als separates Argument übergeben, um die Länge dem Aufgerufenen mitzuteilen.

ELEMENT_TYPE_ARRAY

Wenn eine Methode mit einem ELEMENT_TYPE_ARRAY-Parameter aus einer .NET-Assembly in eine Typbibliothek exportiert wird, wird der Arrayparameter in ein SAFEARRAY eines gegebenen Typs umgewandelt. Der Inhalt des verwalteten Arrays wird automatisch aus dem verwalteten Speicher in das SAFEARRAY kopiert. Beispiel:

Verwaltete Signatur

Sub [New]( ar(,) As Long )
Sub [New]( ar(,) As String )
void New( long [,] ar );
void New( String [,] ar );

Nicht verwaltete Signatur

HRESULT New([in] SAFEARRAY( long ) ar); 
HRESULT New([in] SAFEARRAY( BSTR ) ar);

Rang, Größe und Grenzen der sicheren Arrays werden zur Laufzeit anhand der Merkmale des verwalteten Arrays bestimmt.

Das Array kann auch als Array im C-Format gemarshallt werden, indem das MarshalAsAttribute-Attribut angewendet wird. Beispiel:

Verwaltete Signatur

Sub [New]( <MarshalAs(UnmanagedType.LPARRAY, SizeParamIndex:=1)> _
   ar(,) As Long, size As Integer)
Sub [New]( <MarshalAs(UnmanagedType.LPARRAY, _
   ArraySubType:=UnmanagedType.LPStr, SizeParamIndex:=1)> _
   ar(,) As String, size As Integer)
void New([MarshalAs(UnmanagedType.LPARRAY, SizeParamIndex=1)] 
   long [,] ar, int size );
void New([MarshalAs(UnmanagedType.LPARRAY, 
   ArraySubType= UnmanagedType.LPStr, SizeParamIndex=1)] 
   String [,] ar, int size );

Nicht verwaltete Signatur

HRESULT New(long ar[]); 
HRESULT New(LPStr ar[]);

Geschachtelte Arrays können nicht gemarshallt werden. Die folgende Signatur generiert beispielsweise einen Fehler, wenn sie mit dem Type Library Exporter-Tool (Tlbexp.exe) exportiert wird.

Verwaltete Signatur

Sub [New]( ar()()() As Long )
void New(long [][][] ar );

ELEMENT_TYPE_CLASS <System.Array>

Wenn eine Methode mit einem System.Array-Parameter aus einer .NET-Assembly in eine Typbibliothek exportiert wird, wird der Arrayparameter in eine _Array-Schnittstelle umgewandelt. Auf den Inhalt des verwalteten Arrays kann nur mit den Methoden und Eigenschaften der _Array-Schnittstelle zugegriffen werden. System.Array kann auch als SAFEARRAY gemarshallt werden, indem das MarshalAsAttribute-Attribut verwendet wird. Wenn es als sicheres Array gemarshallt wird, werden die Arrayelemente als Varianten gemarshallt. Beispiel:

Verwaltete Signatur

Sub New1( ar As System.Array )
Sub New2( <MarshalAs(UnmanagedType.Safe array)> ar As System.Array )
void New1( System.Array ar );
void New2( [MarshalAs(UnmanagedType.Safe array)] System.Array ar );

Nicht verwaltete Signatur

HRESULT New([in] _Array *ar); 
HRESULT New([in] SAFEARRAY(VARIANT) ar);

Arrays in Strukturen

Nicht verwaltete Strukturen können eingebettete Arrays enthalten. Im folgenden Beispiel ist s1 ein eingebettetes Array, das direkt innerhalb der Struktur selbst reserviert wird.

Nicht verwaltete Repräsentation

struct MyStruct {
    short s1[128];
}

Arrays können als UnmanagedType.ByValArray gemarshallt werden. Dazu müssen Sie das MarshalAsAttribute.SizeConst-Feld einrichten. Die Größe kann nur als Konstante eingerichtet werden. Im folgenden Code wird die entsprechende verwaltete Definition von MyStruct demonstriert.

Public Structure <StructLayout(LayoutKind.Sequential)> MyStruct
   Public <MarshalAs(UnmanagedType.ByValArray, SizeConst := 128)> _
     s1() As Short
End Structure
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct {
   [MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] public short[] s1;
}

Siehe auch

Konzepte

Blitfähige und nicht blitfähige Typen
Direktionale Attribute
Kopieren und Fixieren

Weitere Ressourcen

Standardmäßiges Marshallingverhalten