Dela via


Standard-marshalling för matriser

I ett program som helt består av hanterad kod skickar den vanliga språkkörningen matristyper som in-/ut-parametrar. Däremot skickar interop marshaller en matris som In-parametrar som standard.

Med fästoptimering kan en blittable-matris verka fungera som en in-/ut-parameter när du interagerar med objekt i samma lägenhet. Men om du senare exporterar koden till ett typbibliotek som används för att generera proxyn mellan datorer, och biblioteket används för att konvertera dina anrop mellan lägenheter, kan anropen återgå till sant I-parameterbeteende.

Matriser är komplexa av naturen, och skillnaderna mellan hanterade och ohanterade matriser kräver mer information än andra icke-blittable-typer.

Hanterade matriser

Hanterade matristyper kan variera. Klassen är dock System.Array basklassen för alla matristyper. Klassen System.Array har egenskaper för att fastställa rangordning, längd och nedre och övre gränser för en matris, samt metoder för åtkomst, sortering, sökning, kopiering och skapande av matriser.

Dessa matristyper är dynamiska och har ingen motsvarande statisk typ definierad i basklassbiblioteket. Det är praktiskt att tänka på varje kombination av elementtyp och rangordning som en distinkt typ av matris. Därför är en endimensionell matris med heltal av en annan typ än en endimensionell matris med dubbla typer. På samma sätt skiljer sig en tvådimensionell matris med heltal från en endimensionell matris med heltal. Matrisens gränser beaktas inte vid jämförelse av typer.

Som följande tabell visar måste alla instanser av en hanterad matris vara av en viss elementtyp, rangordning och lägre bindning.

Hanterad matristyp Elementtyp Rangordning Nedre gräns Signatur notation
ELEMENT_TYPE_ARRAY Anges efter typ. Anges efter rangordning. Du kan också ange gränser. type [ n,m ]
ELEMENT_TYPE_CLASS Okänt Okänt Okänt System.Array
ELEMENT_TYPE_SZARRAY Anges efter typ. 1 0 typ [ n ]

Ohanterade matriser

Ohanterade matriser är antingen com-stil säkra matriser eller C-format matriser med fast eller variabel längd. Säkra matriser är självbeskrivande matriser som har typen, rangordningen och gränserna för associerade matrisdata. Matriser i C-format är endimensionella typmatriser med en fast nedre gräns på 0. Marshalling-tjänsten har begränsat stöd för båda typerna av matriser.

Skicka matrisparametrar till .NET Code

Både C-formatmatriser och säkra matriser kan skickas till .NET-kod från ohanterad kod som antingen en säker matris eller en matris i C-stil. I följande tabell visas det ohanterade typvärdet och den importerade typen.

Ohanterad typ Importerad typ
SafeArray( Typ ) < ELEMENT_TYPE_SZARRAY ConvertedType >

Rank = 1, lägre gräns = 0. Storleken är endast känd om den anges i den hanterade signaturen. Säkra matriser som inte är rangordnade = 1 eller lägre bundna = 0 kan inte ordnas som SZARRAY.
Typ [] < ELEMENT_TYPE_SZARRAY ConvertedType >

Rank = 1, lägre gräns = 0. Storleken är endast känd om den anges i den hanterade signaturen.

Säkra matriser

När en säker matris importeras från ett typbibliotek till en .NET-sammansättning konverteras matrisen till en endimensionell matris av en känd typ (till exempel int). Samma typkonverteringsregler som gäller för parametrar gäller även för matriselement. En säker matris med BSTR-typer blir till exempel en hanterad matris med strängar och en säker matris med varianter blir en hanterad matris med objekt. Elementtypen SAFEARRAY hämtas från typbiblioteket och sparas i SAFEARRAY-värdet för UnmanagedType uppräkningen.

Eftersom rangordningen och gränserna för den säkra matrisen inte kan fastställas från typbiblioteket antas rangordningen vara lika med 1 och den lägre gränsen antas vara lika med 0. Rangordningen och gränserna måste definieras i den hanterade signaturen som skapas av typbiblioteksimportören (Tlbimp.exe). Om rangordningen som skickas till metoden vid körningen skiljer sig åt genereras en SafeArrayRankMismatchException . Om typen av matris som skickades vid körningen skiljer sig åt genereras en SafeArrayTypeMismatchException . I följande exempel visas säkra matriser i hanterad och ohanterad kod.

Ohanterad signatur

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

Hanterad 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);

Flerdimensionella eller icke-zero-bundna säkra matriser kan ordnas i hanterad kod om metodsignaturen som produceras av Tlbimp.exe ändras för att indikera en elementtyp av ELEMENT_TYPE_ARRAY i stället för ELEMENT_TYPE_SZARRAY. Du kan också använda växeln /sysarray med Tlbimp.exe för att importera alla matriser som System.Array objekt. I de fall då matrisen som skickas är känd för att vara flerdimensionell kan du redigera den gemensamma mellanliggande språkkoden (CIL) som skapas av Tlbimp.exe och sedan kompilera om den. Mer information om hur du ändrar CIL-kod finns i Anpassa runtime-anropsbara omslutningar.

Matriser i C-format

När en matris i C-format importeras från ett typbibliotek till en .NET-sammansättning konverteras matrisen till ELEMENT_TYPE_SZARRAY.

Matriselementtypen bestäms från typbiblioteket och bevaras under importen. Samma konverteringsregler som gäller för parametrar gäller även för matriselement. Till exempel blir en matris med LPStr-typer en matris med strängtyper . Tlbimp.exe avbildar matriselementtypen och tillämpar MarshalAsAttribute attributet på parametern.

Matrisrankningen antas vara lika med 1. Om rangordningen är större än 1, ordnas matrisen som en endimensionell matris i kolumn-större ordning. Den nedre bindningen är alltid lika med 0.

Typbibliotek kan innehålla matriser med fast eller variabel längd. Tlbimp.exe kan endast importera matriser med fast längd från typbibliotek eftersom typbibliotek saknar den information som behövs för att konvertera matriser med variabel längd. Med matriser med fast längd importeras storleken från typbiblioteket och samlas in i MarshalAsAttribute som tillämpas på parametern.

Du måste manuellt definiera typbibliotek som innehåller matriser med variabel längd, enligt följande exempel.

Ohanterad signatur

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

Hanterad 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);

Även om du kan använda attributen size_is eller length_is på en matris i IDL-källan (Interface Definition Language) för att förmedla storleken till en klient, sprider inte MIDL-kompilatorn (Microsoft Interface Definition Language) den informationen till typbiblioteket. Utan att känna till storleken kan inte interop marshalling-tjänsten konvertera matriselementen. Därför importeras matriser med variabel längd som referensargument. Till exempel:

Ohanterad signatur

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

Hanterad 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);

Du kan ge marshallern matrisstorleken genom att redigera CIL-koden (Common Intermediate Language) som skapats av Tlbimp.exe och sedan kompilera om den. Mer information om hur du ändrar CIL-kod finns i Anpassa runtime-anropsbara omslutningar. Om du vill ange antalet element i matrisen tillämpar du MarshalAsAttribute typen på matrisparametern för definitionen av den hanterade metoden på något av följande sätt:

  • Identifiera en annan parameter som innehåller antalet element i matrisen. Parametrarna identifieras efter position och börjar med den första parametern som nummer 0.

    Sub [New](ElemCnt As Integer, _
       \<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> _
       ar() As Integer)
    
    void New(
       int ElemCnt,
       [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] int[] ar );
    
  • Definiera matrisens storlek som en konstant. Till exempel:

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

När du samlar matriser från ohanterad kod till hanterad kod kontrollerar marshallern marshalasAttribute som är associerad med parametern för att fastställa matrisstorleken. Om matrisstorleken inte har angetts är det bara ett element som är marshallat.

Kommentar

MarshalAsAttribute har ingen effekt på marshalling av hanterade matriser till ohanterad kod. I den riktningen bestäms matrisstorleken genom undersökning. Det finns inget sätt att konvertera en delmängd av en hanterad matris.

Interop marshaller använder metoderna CoTaskMemAlloc och CoTaskMemFree i Windows eller malloc och kostnadsfria metoder på andra operativsystem för att allokera och hämta minne. Minnesallokering som utförs av ohanterad kod måste också använda dessa metoder.

Skicka matriser till COM

Alla typer av hanterade matriser kan skickas till ohanterad kod från hanterad kod. Beroende på den hanterade typen och de attribut som tillämpas på den kan matrisen nås som en säker matris eller en C-matris, som du ser i följande tabell.

Hanterad matristyp Exporteras som
< ELEMENT_TYPE_SZARRAY typ > UnmanagedType. SafeArray( typ )

UnmanagedType.LPArray

Typen anges i signaturen. Rangordning är alltid 1, lägre gräns är alltid 0. Storleken är alltid känd vid körning.
ELEMENT_TYPE_ARRAY typrankning < > >[< gränser ] > < UnmanagedType.SafeArray( typ )

UnmanagedType.LPArray

Typ, rangordning, gränser anges i signaturen. Storleken är alltid känd vid körning.
ELEMENT_TYPE_CLASS <System.Array> UT_Interface

UnmanagedType.SafeArray( typ )

Typ, rangordning, gränser och storlek är alltid kända vid körning.

Det finns en begränsning i OLE Automation som rör matriser med strukturer som innehåller LPSTR eller LPWSTR. Därför måste strängfälten vara ordnade som UnmanagedType.BSTR. Annars utlöses ett undantag.

ELEMENT_TYPE_SZARRAY

När en metod som innehåller en ELEMENT_TYPE_SZARRAY parameter (endimensionell matris) exporteras från en .NET-sammansättning till ett typbibliotek konverteras matrisparametern till en SAFEARRAY av en viss typ. Samma konverteringsregler gäller för matriselementtyperna. Innehållet i den hanterade matrisen kopieras automatiskt från hanterat minne till SAFEARRAY. Till exempel:

Hanterad signatur

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

Ohanterad signatur

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

Rangordningen för de säkra matriserna är alltid 1 och den lägre gränsen är alltid 0. Storleken bestäms vid körning av storleken på den hanterade matris som skickas.

Matrisen kan också ordnas som en C-matris med hjälp av attributet MarshalAsAttribute . Till exempel:

Hanterad 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 );

Ohanterad signatur

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

Även om marshaller har den längdinformation som behövs för att konvertera matrisen, skickas matrislängden vanligtvis som ett separat argument för att förmedla längden till anroparen.

ELEMENT_TYPE_ARRAY

När en metod som innehåller en ELEMENT_TYPE_ARRAY-parameter exporteras från en .NET-sammansättning till ett typbibliotek konverteras matrisparametern till en SAFEARRAY av en viss typ. Innehållet i den hanterade matrisen kopieras automatiskt från hanterat minne till SAFEARRAY. Till exempel:

Hanterad signatur

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

Ohanterad signatur

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

Rangordningen, storleken och gränserna för de säkra matriserna bestäms vid körning av egenskaperna för den hanterade matrisen.

Matrisen kan också ordnas som en C-matris genom att använda attributet MarshalAsAttribute . Till exempel:

Hanterad 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 );

Ohanterad signatur

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

Kapslade matriser kan inte ordnas. Följande signatur genererar till exempel ett fel när den exporteras med typbiblioteksexportören (Tlbexp.exe).

Hanterad signatur

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

<ELEMENT_TYPE_CLASS System.Array>

När en metod som innehåller en System.Array parameter exporteras från en .NET-sammansättning till ett typbibliotek konverteras matrisparametern till ett _Array gränssnitt. Innehållet i den hanterade matrisen är endast tillgängligt via metoderna och egenskaperna för _Array-gränssnittet . System.Array kan också ordnas som en SAFEARRAY med hjälp av attributet MarshalAsAttribute . När matriselementen är uppdelade som en säker matris, ordnas de som varianter. Till exempel:

Hanterad signatur

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

Ohanterad signatur

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

Matriser i strukturer

Ohanterade strukturer kan innehålla inbäddade matriser. Som standard är dessa inbäddade matrisfält ordnade som en SAFEARRAY. I följande exempel s1 är en inbäddad matris som allokeras direkt inom själva strukturen.

Ohanterad representation

struct MyStruct {
    short s1[128];
}

Matriser kan ordnas som UnmanagedType, vilket kräver att du anger fältet MarshalAsAttribute . Storleken kan bara anges som en konstant. Följande kod visar motsvarande hanterade definition av MyStruct.

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;
}

Se även