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.