Partilhar via


Padrão de empacotamento de matrizes

Em um aplicativo que consiste integralmente em código gerenciado, o common language runtime passa os tipos de matriz como In/Out parâmetros. Em contraste, o empacotador de interoperabilidade passa uma matriz como nos parâmetros por padrão.

Com otimização de fixação, uma matriz de blittable pode aparecer para operar como um In/Out parâmetro ao interagir com objetos no mesmo compartimento. No entanto, se exportar, posteriormente, o código para uma biblioteca de tipos usada para gerar o proxy entre máquinas, e essa biblioteca é usada para empacotar as chamadas entre apartments, as chamadas podem reverter para true no comportamento de parâmetro.

As matrizes são complexas por natureza e as distinções entre arrays gerenciados e garantem a mais informações do que outros tipos de não-blittable. Este tópico fornece as seguintes informações sobre o empacotamento de matrizes:

  • Arrays gerenciados

  • Arrays não gerenciados

  • Passando parâmetros de matriz para.NET de código

  • Arrays de passagem para COM

Arrays gerenciados

Gerenciado de matriz de tipos podem variar; No entanto, o System.Array classe é a classe base de todos os tipos de matriz. O array classe possui propriedades para determinar a classificação, comprimento e limites inferior e superior de uma matriz, bem como os métodos para acessar, classificação, pesquisa, copiando e criação de matrizes.

Esses tipos de matriz são dinâmicos e não têm um tipo estático correspondente, definido na biblioteca de classe base. É conveniente considerar cada combinação de tipo de elemento e a classificação como um tipo distinto de matriz. Portanto, uma matriz unidimensional de inteiros é de um tipo diferente de uma matriz unidimensional de tipos double. Da mesma forma, uma matriz bidimensional de números inteiros é diferente de uma matriz unidimensional de inteiros. Os limites da matriz não são considerados ao comparar tipos.

Como mostra a tabela a seguir, qualquer instância de uma matriz gerenciada deve ser de um tipo de elemento específico, a classificação e o limite inferior.

Gerenciado de tipo de matriz

Tipo de elemento

Classificação

Limite inferior

Notação de assinatura

ELEMENT_TYPE_ARRAY

Especificado pelo tipo.

Especificado pelo posto.

Opcionalmente, especificado por limites.

typen,m

ELEMENT_TYPE_CLASS

Desconhecido

Desconhecido

Desconhecido

System.Array

ELEMENT_TYPE_SZARRAY

Especificado pelo tipo.

1

0

typen

Arrays não gerenciados

Arrays não gerenciados são matrizes seguras de estilo COM ou matrizes de estilo c com comprimento fixo ou variável. Matrizes seguras são autodescritivos arrays que carregam o tipo, classificação e limites de dados array associado. As matrizes de estilo c são matrizes unidimensionais de tipos com um limite inferior fixo 0. O serviço de empacotamento tem suporte limitado para ambos os tipos de arrays.

Passando parâmetros de matriz para.NET de código

Matrizes seguras e arrays de estilo c podem ser passados para.NET resultante do código não gerenciado como uma matriz segura ou uma matriz de estilo C. A tabela a seguir mostra o valor de tipo não gerenciado e o tipo importado.

Tipo não gerenciado

Tipo importado

SafeArray (tipo de)

ELEMENT_TYPE_SZARRAY <ConvertedType>

Classificação = 1, o limite inferior = 0. Tamanho é conhecido somente se fornecido na assinatura gerenciada. Matrizes seguras que não são de classificação = 1 ou o limite inferior = 0 não pode ser empacotado como SZARRAY.

Type []

ELEMENT_TYPE_SZARRAY <ConvertedType>

Classificação = 1, o limite inferior = 0. Tamanho é conhecido somente se fornecido na assinatura gerenciada.

Matrizes seguras

Quando uma matriz segura é importada de uma biblioteca de tipo para um.NET assembly, o array é convertido em uma matriz unidimensional de um tipo conhecido (como int). As mesmas regras de conversão de tipo que se aplicam aos parâmetros também se aplicam a elementos da matriz. Por exemplo, uma matriz segura de BSTR tipos torna-se uma matriz gerenciada de seqüências de caracteres e uma matriz segura de variantes se torna uma matriz gerenciada de objetos. O SAFEARRAY o tipo de elemento é capturado de biblioteca de tipos e salvo no SAFEARRAY valor o UnmanagedType enumeração.

Porque o posto e limites da matriz segura não podem ser determinados de biblioteca de tipos, a classificação é assumido como 1 igual e o limite inferior será considerado 0 igual. Posto e limites devem ser definidos na assinatura gerenciada produzida pela Type Library Importer (Tlbimp. exe). Se a classificação passada para o método em tempo de execução for diferente, um SafeArrayRankMismatchException é lançada. Se o tipo da matriz passada em tempo de execução é diferente, um SafeArrayTypeMismatchException é lançada. O exemplo a seguir mostra as matrizes seguras no código gerenciado e não gerenciado.

Assinatura não gerenciada

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

Assinatura gerenciada

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

Matrizes seguras multidimensionais ou vinculado a diferente de zero, pode ser empacotado para código gerenciado se a assinatura do método produzida pelo Tlbimp. exe é modificada para indicar um tipo de elemento de ELEMENT_TYPE_ARRAY em vez de ELEMENT_TYPE_SZARRAY. Como alternativa, você pode usar o /sysarray switch com Tlbimp. exe para importar todos os arrays como System.Array objetos. Em casos onde a matriz que está sendo passada é conhecida como sendo multidimensional, você pode editar o Microsoft intermediate language (MSIL) código produzido pelo Tlbimp. exe e, em seguida, recompilá-lo. Para obter detalhes sobre como modificar o código MSIL, consulte Personalizando Runtime Callable Wrappers.

Matrizes de estilo c

Quando uma matriz de estilo c é importada de uma biblioteca de tipo para um.NET assembly, o array é convertido em ELEMENT_TYPE_SZARRAY.

O tipo de elemento da matriz é determinado a partir da biblioteca de tipos e preservado durante a importação. As mesmas regras de conversão que se aplicam aos parâmetros também se aplicam a elementos da matriz. Por exemplo, uma matriz de LPStr tipos torna-se uma matriz de seqüência de caracteres tipos. O tipo de elemento de matriz de captura de Tlbimp. exe e aplica a MarshalAsAttribute atributo para o parâmetro.

A classificação da matriz será considerada igual a 1. Se a classificação for maior que 1, a matriz é empacotada como uma matriz unidimensional na ordem da coluna principal. O limite inferior é sempre igual a 0.

Bibliotecas de tipos podem conter as matrizes de comprimento fixo ou variável. Tlbimp. exe pode importar matrizes de comprimento apenas fixo de bibliotecas de tipos, porque as informações necessárias para empacotar matrizes de comprimento variável de falta de bibliotecas de tipos. Com matrizes de comprimento fixo, o tamanho é importado da biblioteca de tipos e capturado no MarshalAsAttribute que é aplicado ao parâmetro.

Você deve definir manualmente as bibliotecas de tipos que contêm matrizes de comprimento variável, conforme mostrado no exemplo a seguir.

Assinatura não gerenciada

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

Assinatura gerenciada

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

Embora seja possível aplicar o size_is ou length_is atributos a uma matriz na fonte de Interface Definition Language (IDL) para transmitir o tamanho para um cliente, o compilador de linguagem de definição de Interface da Microsoft (MIDL) não se propaga essas informações para a biblioteca de tipos. Sem saber o tamanho, a serviço de empacotamento de interoperabilidade não é possível empacotar os elementos da matriz. Conseqüentemente, as matrizes de comprimento variável são importadas como argumentos de referência. Por exemplo:

Assinatura não gerenciada

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

Assinatura gerenciada

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

Editando a Microsoft intermediate language (MSIL) código produzido pelo Tlbimp. exe e, em seguida, recompilá-la, você pode fornecer o empacotador com o tamanho da matriz. Para obter detalhes sobre como modificar o código MSIL, consulte Personalizando Runtime Callable Wrappers. Para indicar o número de elementos na matriz, aplicar o MarshalAsAttribute tipo de parâmetro de matriz da definição do método gerenciado em uma das seguintes maneiras:

  • Identifique o outro parâmetro que contém o número de elementos na matriz. Os parâmetros são identificados por posição, iniciando com o primeiro parâmetro, como o número 0. [Visual Basic]

    Sub [New](ElemCnt As Integer, _
       <MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> _
       ar() As Integer)
    
    void New(
       int ElemCnt, 
       [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] int[] ar );
    
  • Defina o tamanho da matriz como uma constante. Por exemplo:

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

Quando o empacotamento de matrizes do código não gerenciado para código gerenciado, o empacotador verifica o MarshalAsAttribute associados ao parâmetro para determinar o tamanho da matriz. Se o tamanho da matriz não for especificado, somente um elemento é empacotado.

Observação

O MarshalAsAttribute tem nenhum efeito sobre empacotamento gerenciados arrays para código não gerenciado.Nesse sentido, o tamanho da matriz é determinado pelo exame.Não há nenhuma maneira de empacotar um subconjunto de uma matriz gerenciada.

O empacotador de interoperabilidade usa a CoTaskMemAlloc e CoTaskMemFree métodos para alocar e recuperar a memória. Alocação de memória executada pelo código não gerenciado também deve usar esses métodos.

Arrays de passagem para COM

Todos os tipos de matriz gerenciada podem ser passados para código não gerenciado a partir do código gerenciado. Dependendo do tipo gerenciado e os atributos aplicados a ele, o array pode ser acessado como uma matriz segura ou uma matriz de estilo C, conforme mostrado na tabela a seguir.

Gerenciado de tipo de matriz

Exportadas como

ELEMENT_TYPE_SZARRAY <tipo de>

UnmanagedType.SafeArray (tipo de)

UnmanagedType. LPArray

Tipo é fornecido na assinatura. Classificação é sempre 1, o limite inferior é sempre 0. Tamanho sempre é conhecido em tempo de execução.

ELEMENT_TYPE_ARRAY <type> <rank><bounds>

UnmanagedType. SafeArray (tipo de)

UnmanagedType. LPArray

Limites de fileiras, tipo, são fornecidos na assinatura. Tamanho sempre é conhecido em tempo de execução.

ELEMENT_TYPE_CLASS <System.Array>

UT_Interface

UnmanagedType. SafeArray (tipo de)

Tipo, classificação, limites e tamanho são sempre conhecidas em tempo de execução.

Há uma limitação na automação OLE relativas a matrizes de estruturas que contêm LPSTR ou LPWSTR. Portanto, seqüência de caracteres campos precisam ser empacotado como UnmanagedType.BSTR. Caso contrário, uma exceção será lançada.

ELEMENT_TYPE_SZARRAY

Quando um método que contém um ELEMENT_TYPE_SZARRAY parâmetro (matriz unidimensional) exportado de um.NET assembly para uma biblioteca de tipos, o parâmetro array é convertido em um SAFEARRAY de um determinado tipo. As mesmas regras de conversão aplicam-se os tipos de elemento de matriz. O conteúdo da matriz gerenciado é automaticamente copiado na memória gerenciada para o SAFEARRAY. Por exemplo:

Assinatura gerenciada

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

Assinatura não gerenciada

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

A classificação das matrizes seguras é sempre 1 e o limite inferior é sempre 0. O tamanho é determinado em tempo de execução pelo tamanho da matriz gerenciado que está sendo passado.

A matriz também pode ser empacotada como uma matriz de estilo C, usando o MarshalAsAttribute atributo. Por exemplo:

Assinatura gerenciada

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

Assinatura não gerenciada

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

Embora o empacotador tenha as informações de comprimento necessárias para empacotar o array, o comprimento da matriz normalmente é passado como um argumento separado para transmitir o comprimento para o receptor.

ELEMENT_TYPE_ARRAY

Quando um método que contém um ELEMENT_TYPE_ARRAY parâmetro é exportado a partir de um.NET assembly para uma biblioteca de tipos, o parâmetro array é convertido em um SAFEARRAY de um determinado tipo. O conteúdo da matriz gerenciado é automaticamente copiado na memória gerenciada para o SAFEARRAY. Por exemplo:

Assinatura gerenciada

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

Assinatura não gerenciada

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

A posição, tamanho e limites das matrizes seguras são determinados em tempo de execução pelas características do array gerenciado.

A matriz também pode ser empacotada como uma matriz de estilo c aplicando o MarshalAsAttribute atributo. Por exemplo:

Assinatura gerenciada

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

Assinatura não gerenciada

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

Não não possível empacotar matrizes aninhadas. Por exemplo, a assinatura a seguir gera um erro quando exportados com o Type Library Exporter (Tlbexp. exe).

Assinatura gerenciada

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

ELEMENT_TYPE_CLASS <System.Array>

Quando um método que contém um System.Array parâmetro exportado de um.NET assembly para uma biblioteca de tipos, o parâmetro array é convertido em um _Array interface. O conteúdo da matriz gerenciado é acessível somente através de métodos e propriedades de _Array interface. System. Array também pode ser empacotado como um SAFEARRAY usando o MarshalAsAttribute atributo. Quando empacotado como uma matriz segura, os elementos da matriz são empacotados como variantes. Por exemplo:

Assinatura gerenciada

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

Assinatura não gerenciada

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

Arrays dentro de estruturas

Estruturas não gerenciadas podem conter matrizes incorporadas. Por padrão, esses campos de matriz incorporada são empacotados como um SAFEARRAY. No exemplo a seguir, s1 é uma matriz de incorporado que é alocada diretamente dentro da estrutura de si mesmo.

Representação não gerenciada

struct MyStruct {
    short s1[128];
}

Arrays podem ser empacotados como UnmanagedType. ByValArray, que requer que você defina a MarshalAsAttribute.SizeConst campo. O tamanho pode ser definido somente como uma constante. O código a seguir mostra a definição gerenciada correspondente do 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;
}

Consulte também

Conceitos

Blittable e tipos de não-Blittable

Atributos direcionais

Copiando e fixando

Outros recursos

Comportamento de empacotamento padrão