Compartilhar via


Alterações de empacotamento

As seções a seguir fornecem um conjunto selecionado de alterações que você pode fazer em um assembly de interoperabilidade para abordar alguns problemas específicos com a saída do processo de importação:

  • Matrizes de estilo c conformes

  • Estilo C Arrays in/Out

  • Matrizes multidimensionais do estilo c

  • SAFEARRAY de âmbito diferente de zero

  • Preservar a assinatura

  • Passar Null em vez de uma referência ao tipo de valor

Estas seções não representam todos os casos para edição de um assembly de interoperabilidade. Por exemplo, você também pode editar um assembly de interoperabilidade para aprimorar a sua facilidade de uso. A única maneira de determinar as personalizações que são necessárias é realmente escrever o código usando o assembly de interoperabilidade. Para obter instruções sobre a edição de assemblies de interoperabilidade, consulte como: Editar Assemblies de interoperabilidade.

O empacotamento é afetado quando o cliente e servidor estão em apartments incompatíveis. Nos exemplos a seguir, a maioria dos parâmetros empacotadas não é compatível de automação e exige uma das seguintes ações:

  • Confirme se o cliente e o servidor estão no apartments compatíveis (e portanto, não há nenhum COM marshaling envolvidos).

  • Registre o proxy e stub gerado a partir de Interface Definition Language (IDL). Registrar a biblioteca de tipos não ajuda nesses casos porque muitas das informações necessárias para o empacotamento não é propagada de IDL à biblioteca de tipos.

Matrizes de estilo c conformes

A declaração de IDL a seguir mostra uma matriz de estilo C.

HRESULT ConformantArray([in] int cElems, [in, size_is(cElems)] int 
aConf[]);

Porque este tipo não é compatível de automação, informações sobre o tamanho da matriz, como, por exemplo, o link entre o primeiro e o segundo parâmetro, não podem ser expresso na biblioteca de tipos. O importador da biblioteca (Tlbimp. exe) importa o segundo parâmetro, como uma referência para o inteiro e não como uma matriz gerenciada. Você pode ajustar o parâmetro editando o MSIL.

Pesquisar o MSIL para

method public hidebysig newslot virtual 
instance void  ConformantArray([in] int32 cElems,
[in] int32& aConf) runtime managed internalcall

Substituir por

method public hidebysig newslot virtual 
instance void  ConformantArray([in] int32 cElems,
[in] int32[] marshal([]) aConf) runtime managed internalcall

Para chamar a partir do código gerenciado

int[] param1 = { 11, 22, 33 };
tstArrays.ConformantArray( 3, param1 );

Estilo C Arrays in/Out

Mostra um estilo de C In/Out matriz seguinte declaração de IDL.

HRESULT InOutArray([in, out] int* pcElems, [in, out, size_is(,*pcElems)] 
int** ppInOut);

Nesse caso, a matriz pode ser redimensionada e o novo tamanho pode ser passado de volta. Porque este tipo não é compatível de automação, informações sobre o tamanho da matriz, como, por exemplo, o link entre o primeiro e o segundo parâmetro, não podem ser expresso na biblioteca de tipos. Tlbimp. exe importa o segundo parâmetro como um IntPtr. Embora você ainda poderá chamar esse método no código gerenciado, para redimensionar a matriz você deve editar o MSIL e usar métodos da Marshal classe manualmente manipular a alocação e desalocação de memória.

Pesquisar o MSIL para

.method public hidebysig newslot virtual 
instance void  InOutArray([in][out] int32& pcElems,
[in][out] native int ppInOut) runtime managed internalcall

Substituir por

.method public hidebysig newslot virtual 
instance void  InOutArray([in][out] int32& pcElems,
[in][out] native int& ppInOut) runtime managed internalcall

Para chamar a partir do código gerenciado

int[] inArray = { 11, 22, 33 };
int arraySize = inArray.Length;

IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf( typeof( int )) * inArray.Length );
Marshal.Copy( inArray, 0, buffer, inArray.Length );
tstArrays.InOutArray( ref arraySize, ref buffer );
if( arraySize > 0 )
{
int[] arrayRes = new int[ arraySize ];
Marshal.Copy( buffer, arrayRes, 0, arraySize );
Marshal.FreeCoTaskMem( buffer );
}

Matrizes multidimensionais do estilo c

A declaração de IDL a seguir mostra uma matriz bidimensional de estilo C.

HRESULT TwoDimArray([in] int cDim, [in, size_is(cDim)] int aMatrix[][3]);

Porque este tipo não é compatível de automação, informações sobre o tamanho e o número de dimensões da matriz, como, por exemplo, o link entre o primeiro e o segundo parâmetro, não podem ser expresso na biblioteca de tipos. Tlbimp. exe importa o segundo parâmetro como um IntPtr tipo e não como uma matriz multidimensional gerenciada. Você pode ajustar o parâmetro editando o MSIL.

Pesquisar o MSIL para

.method public hidebysig newslot virtual 
instance void  TwoDimArray([in] int32 cDim,
[in] native int aMatrix) runtime managed internalcall

Substituir por

.method public hidebysig newslot virtual 
instance void  TwoDimArray([in] int32 cDim,
[in] int32[,] marshal([]) aMatrix) runtime managed internalcall

Para chamar a partir do código gerenciado

int[,] param = {{ 11, 12, 13 }, { 21, 22, 23 }, { 31, 32, 33 }};
tstArrays.TwoDimArray( 3, param );

SAFEARRAY de âmbito diferente de zero

IDL a declaração a seguir mostra um SAFEARRAY parâmetro.

HRESULT InSArray([in] SAFEARRAY(int) *ppsa);

Considere que esse SAFEARRAY está vinculado diferente de zero. No código gerenciado, tais arrays são representados pela System.Array tipo. No entanto, por padrão, o importador converte todos os SAFEARRAY parâmetros de referências de arrays gerenciados. Você tem duas opções para alterar o comportamento padrão:

  • Importar todos os arrays em uma biblioteca de tipos como array tipos usando Tlbimp. exe com o /sysarray alternar.

  • Importe alguns parâmetros, como array tipos editando manualmente o MSIL, como mostra o exemplo a seguir.

    Pesquisar o MSIL para

    .method public hidebysig newslot virtual 
    instance void  InSArray([in] int32[]&  marshal( safearray int) ppsa) runtime managed internalcall
    

    Substituir por

    .method public hidebysig newslot virtual 
    instance void  InSArray(class [mscorlib]System.Array& marshal( safearray) 
    ppsa) runtime managed internalcall
    

    Chamar do código gerenciado

    int[] lengthsArray = new int[1] { 3 };   
    int[] boundsArray = new int[1] { -1 };
    Array param2 = Array.CreateInstance( typeof(int), lengthsArray, boundsArray );
    for( int i = param2.GetLowerBound( 0 ); i <= param2.GetUpperBound( 0 ); i++ )
    param2.SetValue( i * 10, i ); 
    sum = tstArrays.InSArray( ref param2 );
    

Preservar a assinatura

A declaração de IDL a seguir mostra a assinatura de um método COM.

HRESULT TestPreserveSig2([in] int inParam, [out,retval] int* outParam);

As assinaturas de métodos COM Tlbimp. exe é alterado. Parâmetros são marcados com [out, retval] IDL tornam-se os valores de retorno de métodos gerenciados. Todos os valores HRESULT que indicam a falha são transformados em gerenciado exceções. Às vezes é necessário preservar a assinatura do método COM original, como, por exemplo, quando o método retorna algo diferente de sucesso HRESULTs. A representação gerenciado a seguir mostra um exemplo de uma assinatura que você pode modificar.

Representação gerenciada na MSIL

.method public hidebysig newslot virtual 
instance int32 TestPreserveSig2([in] int32 inParam) runtime managed internalcall
{

Substituir por

.method public hidebysig newslot virtual 
instance int32 TestPreserveSig2([in] int32 inParam, [out] int32& outParam) runtime managed internalcall preservesig

Para ver quais HRESULT é retornado.

int hr = tst.TestPreserveSig2( -3, out retValue );
Console.WriteLine( "Return value is {0}", retValue );
if( hr == 0 )
Console.WriteLine( "HRESULT = S_OK" );
else if ( hr == 1 )
Console.WriteLine( "HRESULT = S_FALSE" );
else
Console.WriteLine( "HRESULT = {0}", hr );

Passar Null em vez de uma referência a um tipo de valor

A declaração de IDL a seguir mostra um ponteiro para uma estrutura de IDL.

HRESULT TestPassingNull([in, unique] Point* refParam);

Tlbimp. exe importa o parâmetro como uma referência para o tipo de valor Point. No C# e Visual Basic 2005, uma referência nula (nada em Visual Basic) não pode ser passado como um parâmetro quando uma referência a um tipo de valor esperada. Se a função COM requer um valor nulo (nada) parâmetro, você pode alterar a assinatura editando o MSIL.

Pesquisar o MSIL para

.method public hidebysig newslot virtual 
instance void  TestPassingNull(
[in] valuetype MiscSrv.tagPoint& refParam) 
runtime managed internalcall

Substituir por

.method public hidebysig newslot virtual 
instance void  TestPassingNull([in] native int) runtime managed internalcall

A assinatura alterada permite passar um valor nulo. No entanto, quando você precisar passar alguns valores reais, você deve usar os métodos do Marshal classe, como mostra o exemplo a seguir.

tagPoint p = new tagPoint();
p.x = 3;
p.y = 9;

IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf( p ));
Marshal.StructureToPtr( p, buffer, false );
tst.TestPassingNull( buffer );
Marshal.FreeCoTaskMem( buffer );
tst.TestPassingNull( IntPtr.Zero );

Consulte também

Tarefas

Como: Editar Assemblies de interoperabilidade

Como: Criar Wrappers manualmente

Referência

Tlbimp. exe (importador da biblioteca)

Conceitos

Personalizando o Runtime Callable Wrappers

Tipos de dados COM

Personalizando COM Callable Wrappers