Compartir a través de


Traducciones de signatura de método implícitas en la interoperabilidad de .NET

Para mantener su independencia del lenguaje de programación, el sistema COM de Windows y muchas API de Windows devuelven un tipo entero de 4 bytes denominado HRESULT para indicar si una API se ha aplicado correctamente o no, junto con cierta información sobre el error. Otros valores que deben pasarse al autor de la llamada se devuelven a través de parámetros de puntero que actúan como parámetros "out" y suelen ser el último parámetro de la signatura. Tradicionalmente, lenguajes como C# y Visual Basic traducen un código de error como excepción para coincidir con la forma en que los errores se suelen propagar en el lenguaje y esperan que las signaturas del método de interoperabilidad no incluyan HRESULT. Para traducir la signatura de método a una signatura nativa, el entorno de ejecución mueve el valor devuelto del método a un parámetro "out" adicional con un nivel más de direccionamiento indirecto (es decir, lo convierte en un puntero al tipo de valor devuelto de la signatura administrada) y asume un valor devuelto de HRESULT. Si el método administrado devuelve void, no se agrega ningún parámetro adicional y el valor devuelto se convierte en HRESULT. Por ejemplo, vea los dos métodos COM de C# siguientes que se traducen a la misma signatura nativa:

int Add(int a, int b);

void Add(int a, int b, out int sum);
HRESULT Add(int a, int b, /* out */ int* sum);

PreserveSig en COM

Se espera que todos los métodos COM de C# usen la signatura traducida de forma predeterminada. Para usar y exportar métodos sin la traducción de signaturas y el control de valores HRESULT, agregue PreserveSigAttribute a un método de interfaz COM. Cuando el atributo se aplica a un método, no se realiza ninguna traducción a la signatura y no se inician excepciones para los valores HRESULT con errores. Esto es aplicable tanto a COM integrado como a COM generado por código fuente. Por ejemplo, consulte la siguiente signatura de método de C# con un atributo PreserveSig y su signatura nativa correspondiente.

[PreserveSig]
int Add(int a, int b, out int sum);
HRESULT Add(int a, int b, int* sum);

Esto puede ser útil si el método puede devolver valores HRESULT diferentes que no sean errores, pero debe abordarse de forma distinta. Por ejemplo, algunos métodos pueden devolver el valor S_FALSE cuando un método no genera error pero solo devuelve resultados parciales y S_OK cuando devuelve todos los resultados.

PreserveSig con invocaciones de plataforma (P/Invokes)

El atributo DllImportAttribute también tiene el campo bool PreserveSig, que funciona de forma similar a PreserveSigAttribute, pero su valor predeterminado es true. Para indicar que el entorno de ejecución debe traducir la signatura administrada y administrar el valor HRESULT que se devuelve, establezca el campo PreserveSig en false para DllImportAttribute. Por ejemplo, vea las siguientes signaturas de dos invocaciones de plataforma (P/Invokes) en el mismo método nativo, una con PreserveSig establecido en false y la otra con el valor true predeterminado.

[DllImport("shlwapi.dll", EntryPoint = "SHAutoComplete", ExactSpelling = true, PreserveSig = false)]
public static extern void SHAutoComplete(IntPtr hwndEdit, SHAutoCompleteFlags dwFlags);

[DllImport("shlwapi.dll", EntryPoint = "SHAutoComplete", ExactSpelling = true)]
public static extern int SHAutoCompleteHRESULT(IntPtr hwndEdit, SHAutoCompleteFlags dwFlags);

Nota:

Las invocaciones de plataforma (P/Invokes) generadas por código fuente, que usan LibraryImportAttribute, no tienen ningún campo PreserveSig. El código generado siempre asume que la signatura nativa y la administrada son idénticas. Para obtener más información, consulte Invocaciones de plataforma (P/Invokes) generadas por código fuente.

Control manual de los valores HRESULT

Al llamar a un método PreserveSig que devuelve un elemento HRESULT, puede usar el método ThrowExceptionForHR para iniciar la excepción correspondiente si HRESULT indica un error. De forma similar, al implementar un método PreserveSig, puede usar el método GetHRForException para devolver el elemento HRESULT que indica un valor correspondiente para la excepción.

Serialización de elementos HRESULT como estructuras

Al usar un método PreserveSig, se espera que int sea el tipo administrado para HRESULT. Sin embargo, el uso de una estructura personalizada de 4 bytes como tipo de valor devuelto le permite definir propiedades y métodos auxiliares que pueden simplificar el trabajo con HRESULT. En la serialización integrada, esto funciona automáticamente. Para usar una estructura en lugar de int como representación administrada de HRESULT en la serialización generada por código fuente, agregue el atributo MarshalAsAttribute con Error como argumento. La presencia de este atributo reinterpreta los bits de HRESULT como estructura.

Consulte también