2011-12-21 10 views
11

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:

  1. ¿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?
  2. ¿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?
  3. ¿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?

+2

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. –

+1

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. –

+2

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#. –

Respuesta

14

No, no es estrictamente necesario aplicar ninguno de estos atributos en su propio código. Todos son opcionales y se aplican automáticamente a tu código según el tipo de parámetro.

En esencia, tienen las siguientes palabras clave equivalentes de C#:

  • Usted recibe [In] por defecto.
  • La palabra clave ref le consigue [In, Out].
  • La palabra clave out te consigue [Out].

Todo documentado en una bonita tabla here.

Solo necesita usarlos cuando desee alterar esa semántica implícita o cambiar el comportamiento predeterminado del contador de referencias. Por ejemplo, puede marcar un parámetro declarado ref con el atributo [In] solo para suprimir la parte "salir" de la clasificación.

Dicho esto, me encuentro utilizándolos porque son una forma muy fácil de hacer que el código se auto-documente.

+0

¡Me gusta la idea de autodiagnóstico! Y solo agrego: el uso de MarshalAs para Bool and Strings es mucho más relevante, revisa esto también ... – eFloh

+0

Sí, estoy más familiarizado con el atributo de MarshalAs, aunque hay algunos detalles de los que aún no estoy claro (principalmente con matrices). Estaba comenzando simple :) –

+0

¡Ah, eso realmente explica algo que veo en pinvoke.net mucho! Por ejemplo, si un método toma un parámetro REFIID, normalmente eso sería un "Guid de ref". Pero si el parámetro está designado como [en] en el IDL, puedo designarlo como "[In] ref Guid refiid" y no me molestará ordenar la estructura Guid ya que no la necesito, corrija ? –

Cuestiones relacionadas