Cambios en el cálculo de referencias
Actualización: noviembre 2007
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
Conceptos
Personalizar contenedores a los que se puede llamar en tiempo de ejecución
Personalizar contenedores COM a los que se puede llamar