2009-04-18 18 views
9

Por MSDN que he encontrado la siguiente descripción de los dos atributos:DllImport - PreserverSig y SetLastError atributos

PreserveSig Configure el campo PreserveSig true para traducir directamente firmas no administrados con HRESULT o valores RETVAL; establézcalo en falso para convertir automáticamente los valores HRESULT o retval a excepciones. Por defecto, el campo PreserveSig es verdadero.

SetLastError Permite que el llamante use la función Marshal.GetLastWin32Error API para determinar si se produjo un error al ejecutar el método. En Visual Basic, el valor predeterminado es verdadero (lo que agrega cierta sobrecarga); en C# y C++, el valor predeterminado es falso.

Mi pregunta es: ¿cómo se relacionan estas dos entre sí? Supongamos que tengo PreserveSig establecido en 'falso' - significa que debería haber convertido HRESULT a excepción - si la función no administrada devuelve un entero que indica que se produjo un error o no se produjo ningún error, ¿cómo podría traducirse esto a excepción?

¿Por qué también necesito llamar al método GetLastWin32Error si de alguna manera logré extraer la excepción con PreserveSig?

Saludos cordiales PK

Respuesta

14

funciones de Win32 casi nunca devolver un HRESULT. En su lugar, devuelven un BOOL o usan valores especiales para indicar un error (por ejemplo, CreateFile devuelve INVALID_HANDLE_VALUE). Almacenan el código de error en una variable por subproceso, que puede leer con GetLastError(). SetLastError=true instruye al marcador para que lea esta variable después de que la función nativa regrese, y esconde el código de error donde más tarde lo puede leer con Marshal.GetLastWin32Error(). La idea es que el tiempo de ejecución de .NET pueda invocar a otras funciones de Win32 detrás de escena que arruinen el código de error de su llamada p/invoke antes de que tenga la oportunidad de inspeccionarlo.

Las funciones que devuelven HRESULT (o equivalente, por ejemplo, NTSTATUS) pertenecen a un nivel diferente de abstracción que las funciones de Win32. En general, estas funciones están relacionadas con COM (por encima de Win32) o desde ntdll (debajo de Win32), por lo que no usan el último código de error de Win32 (aunque pueden llamar internamente a las funciones de Win32).

PreserveSig=false instruye el contador de referencias para comprobar el retorno HRESULT y si no es un código de éxito, para crear y lanzar una excepción que contiene el HRESULT. La declaración administrada de su función ed DllImport tiene void como su tipo de devolución.

Recuerde, el compilador C# o VB no puede verificar la firma no administrada de la función ed DllImport, por lo que tiene que confiar en lo que le indique. Si coloca PreserveSig=false en una función que devuelve algo que no sea HRESULT, obtendrá resultados extraños (por ejemplo, excepciones aleatorias). Si coloca SetLastError=true en una función que no establece el último código de error Win32, obtendrá basura en lugar de un código de error útil.

+0

No tengo experiencia con objetos COM, así que permítanme hacer una pregunta más sobre la creación de la firma del método. La pregunta es: cuando veo que la función COM devuelve HRESULT, puedo marcar mi método como return void y establecer PreserveSig = false (como dijo), o establecer PreserveSig = true y marcar mi método como regresar IntPtr para examinar manualmente el código devuelto? – pkolodziej

+0

Sí, eso es correcto, excepto que HRESULT es UInt32s, no IntPtrs. –

+0

Gracias, ha sido muy útil. – pkolodziej