Compartir a través de


Cambios en el cálculo de referencias

En las secciones siguientes se proporciona una serie de cambios que puede realizar en un ensamblado de interoperabilidad para resolver determinados problemas con el resultado del proceso de importación:

  • Matrices de estilo C compatibles

  • Matrices de estilo C de entrada y salida

  • Matrices de estilo C multidimensionales

  • SAFEARRAY con límite distinto de cero

  • Conservar la firma

  • Pasar Null en lugar de una referencia a un tipo de valor

En estas secciones no se representan todos los casos para modificar un ensamblado de interoperabilidad. Por ejemplo, también puede modificar un ensamblado de interoperabilidad para mejorar su facilidad de uso. La única forma de determinar cuáles son las personalizaciones necesarias es escribir realmente código mediante el ensamblado de interoperabilidad. Para obtener instrucciones sobre cómo modificar los ensamblados de interoperabilidad, vea Cómo: Editar ensamblados de interoperabilidad.

El cálculo de referencias se ve afectado cuando el cliente y el servidor están en apartamentos incompatibles. En los siguientes ejemplos, la mayoría de los parámetros para los que se calculan referencias no son compatibles con Automatización y requieren que se realice una de las acciones siguientes:

  • Confirmar que tanto el cliente como el servidor están en apartamentos compatibles (y por tanto, que no se realiza el cálculo de referencias COM).

  • Registrar el proxy y el código auxiliar generados a partir de un lenguaje de definición de interfaz (IDL). El registro de la biblioteca de tipos no es útil en estos casos, ya que gran parte de la información necesaria para el cálculo de referencias no se propaga desde IDL hasta la biblioteca de tipos.

Matrices de estilo C compatibles

En la siguiente declaración IDL se muestra una matriz de estilo C.

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

Como este tipo no es compatible con Automatización, la información acerca del tamaño de la matriz (como el vínculo entre el primer y el segundo parámetros) no se puede expresar en la biblioteca de tipos. El importador de la biblioteca de tipos (Tlbimp.exe) importa el segundo parámetro como una referencia al entero y no como una matriz administrada. Puede ajustar el parámetro si modifica el código MSIL.

Buscar en MSIL

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

Reemplazar con

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

Para llamar desde código administrado

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

Matrices de estilo C de entrada y salida

En la siguiente declaración IDL se muestra una matriz de estilo C de entrada y salida.

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

En este caso, es posible cambiar el tamaño de la matriz y volver a pasar el nuevo tamaño. Como este tipo no es compatible con Automatización, la información acerca del tamaño de la matriz (como el vínculo entre el primer y el segundo parámetros) no se puede expresar en la biblioteca de tipos. Tlbimp.exe importa el segundo parámetro como un IntPtr. Si bien puede seguir llamando a este método desde código administrado, para cambiar el tamaño de la matriz debe modificar el código MSIL y utilizar métodos de la clase Marshal para controlar manualmente la asignación y la desasignación de la memoria.

Buscar en MSIL

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

Reemplazar con

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

Para llamar desde código administrado

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

Matrices de estilo C multidimensionales

En la siguiente declaración IDL se muestra una matriz bidimensional de estilo C.

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

Como este tipo no es compatible con Automatización, la información acerca del tamaño y el número de dimensiones de la matriz (como el vínculo entre el primer y el segundo parámetros) no se puede expresar en la biblioteca de tipos. Tlbimp.exe importa el segundo parámetro como un tipo IntPtr y no como una matriz multidimensional administrada. Puede ajustar el parámetro si modifica el código MSIL.

Buscar en MSIL

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

Reemplazar con

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

Para llamar desde código administrado

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

SAFEARRAY con límite distinto de cero

En la siguiente declaración IDL se muestra un parámetro SAFEARRAY.

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

Suponga que este SAFEARRAY tiene un límite distinto de cero. En el código administrado, estas matrices se representan mediante el tipo System.Array. Sin embargo, de manera predeterminada el importador convierte todos los parámetros SAFEARRAY en referencias a matrices administradas. Tiene dos opciones para cambiar el comportamiento predeterminado:

  • Importar todas las matrices en una biblioteca de tipos como tipos System.Array utilizando Tlbimp.exe con el modificador /sysarray.

  • Importar algunos parámetros como tipos System.Array modificando manualmente el código MSIL, como se muestra en el ejemplo siguiente.

    Buscar en MSIL

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

    Reemplazar con

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

    Llamar desde código administrado

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

Conservar la firma

En la siguiente declaración IDL se muestra una firma de un método COM.

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

Tlbimp.exe cambia las firmas de los métodos COM. Los parámetros marcados con [out, retval] en IDL se convierten en valores devueltos de los métodos administrados. Todos los valores HRESULT que indican un error se transforman en excepciones administradas. Algunas veces es necesario conservar la firma original del método COM, como cuando el método devuelve algo distinto de valores HRESULT de operación correcta. En la siguiente representación administrada se muestra un ejemplo de una firma que puede modificar.

Representación administrada en MSIL

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

Reemplazar con

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

Para ver qué valor HRESULT se devuelve

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

Pasar null en lugar de una referencia a un tipo de valor

En la siguiente declaración IDL se muestra un puntero IDL a una estructura.

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

Tlbimp.exe importa el parámetro como una referencia al tipo de valor Point. En C# y en Visual Basic 2005, no se puede pasar una referencia null (Nothing en Visual Basic) como un parámetro cuando se espera recibir una referencia a un tipo de valor. Si la función COM requiere un parámetro null (Nothing), puede cambiar la firma modificando el código MSIL.

Buscar en MSIL

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

Reemplazar con

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

La firma modificada le permite pasar un valor null. Sin embargo, si necesita pasar algunos valores reales debe utilizar los métodos de la clase Marshal, como se muestra en el siguiente ejemplo.

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

Vea también

Tareas

Cómo: Editar ensamblados de interoperabilidad

Cómo: Crear contenedores manualmente

Referencia

TlbImp.exe (Importador de la biblioteca de tipos)

Conceptos

Personalizar contenedores RCW

Tipos de datos COM

Personalizar contenedores CCW