Estoy tratando de atravesar el desorden de las definiciones de interoperabilidad COM que hemos esparcido a través de varios proyectos y recopilarlos en una sola ubicación conocida, buena de la cual el conjunto el equipo de desarrollo puede beneficiarse. Parte de este esfuerzo implica limpiar las definiciones que se han acumulado a lo largo de los años.Cuándo es necesario/apropiado usar InAttribute y OutAttribute para COM Interop
Algunos de estos son prestados de otro código fuente, algunos se copiaron textualmente de pinvoke.net, y algunos parecen traducirse directamente de los encabezados del SDK. Una cosa que noto es que no hay consistencia sobre cuándo usar los diversos atributos de clasificación, (incluso entre los ejemplos de pinvoke.net, esto es acertado o extraño). Parte del problema es que no creo que nadie aquí (incluido yo) entienda completamente cuándo se necesitan o no los diversos atributos, o qué es lo que realmente hacen. Hasta este punto, hacerlo bien parece ser una combinación de conjeturas y cambios aleatorios hasta que las COMExcepciones dejen de suceder, pero prefiero que las traducciones sean correctas porque alguien las miró y las declaró.
Por lo tanto, estoy comenzando con [In]
y [Out]
. Sé lo que hacen esos dos atributos conceptualmente: informan al marshaller en qué dirección deben ir los datos. I asume el Marshaller, por ejemplo, no se molestará en copiar datos de [In]
a la persona que llama, o sabe que los datos de [Out]
podrían necesitar ser liberados en el lado del destinatario, etc. Las cosas que no sé son:
- ¿Cuándo es necesario para utilizar estos atributos? Es decir, ¿cuándo se equivocó el comportamiento de clasificación predeterminado de modo que los atributos lo hagan correcto?
- ¿Cuándo es seguro para utilizar estos atributos? Es decir, ¿va a especificar qué debe ser el comportamiento predeterminado para cambiar la forma en que funciona el marcador?
- ¿Cuándo es peligroso para utilizar estos atributos? Supongo que marcar explícitamente un parámetro de salida
[In]
es malo, pero está marcando un parámetro de entrada[In, Out]
que realmente va a romper algo?
Así, dado un método de interfaz COM hipotética cuya IDL se ve así:
HRESULT Foo(
[in] ULONG a,
[out] ULONG * b
[in, out] ULONG * c);
que podrían ver esto traduce como cualquiera de los siguientes:
void Foo(
uint cb,
out uint b,
ref uint c);
void Foo(
uint cb,
[Out] out uint b,
[In, Out] ref uint c);
void Foo(
[In] uint cb,
[Out] out uint b,
[In, Out] ref uint c);
¿Hay alguna diferencia funcional entre esos tres? ¿Alguno de ellos se considera "mejor" que los otros por razones además de la corrección técnica?
Tenga cuidado aquí, está comparando manzanas y naranjas. Los atributos [in] y [out] en un archivo IDL solo son utilizados por midl.exe cuando genera el código proxy/stub. Que solo se utilizan cuando una llamada COM necesita ser ordenada entre apartamentos o procesos. Los atributos .NET [In] y [Out] solo son utilizados por el marshaller pinvoke. Que se ejecuta en un entorno de tiempo de ejecución muy diferente, siempre en proceso y sin tener en cuenta los apartamentos. Su intención es sin duda la misma, optimizar la llamada. –
Sí, yo (creo que) entiendo esta parte. Para mis propósitos, cuando traduzco IDL a C#, solo uso los atributos IDL como una pista de cómo se supone que "se comportan" los métodos. IOW, el atributo [out] en IDL significa que el escritor de la interfaz pretende que este parámetro regrese de la persona que llama con un valor almacenado en él, así que necesito asegurarme de que el código C# actúa de la misma manera. Donde me estoy quedando corto es comprender el comportamiento predeterminado del contador de referencias .NET y cuándo debo decir qué hacer frente a cuando hace lo correcto por sí mismo. –
Son necesarios en IDL porque no está completamente claro cuál es la dirección del flujo de datos cuando utiliza punteros. No es un problema en C# con las palabras clave * ref * y * out *. El buen caso del 99% simplemente está omitiendo los atributos en C#. 100% si realmente está reemplazando el código COM con C#. –