xcom x360ce win32 válida una solucion sistema puede especificado error encontrar denegado archivo aplicación acceso 0x80004005 c# winapi exception win32exception

c# - x360ce - system.componentmodel.win32exception xcom 2



Lanzar un Win32Exception (3)

Recientemente he estado escribiendo un montón de código que involucra interoperabilidad con la API de Win32 y me he estado preguntando cuál es la mejor manera de lidiar con los errores nativos (no administrados) causados ​​por llamadas a las funciones de la API de Windows.

Actualmente, las llamadas a funciones nativas se ven algo así:

// NativeFunction returns true when successful and false when an error // occurred. When an error occurs, the MSDN docs usually tell you that the // error code can be discovered by calling GetLastError (as long as the // SetLastError flag has been set in the DllImport attribute). // Marshal.GetLastWin32Error is the equivalent managed function, it seems. if (!WinApi.NativeFunction(param1, param2, param3)) throw new Win32Exception();

La línea que plantea la excepción se puede reescribir de manera equivalente como tal, creo:

throw new Win32Exception(Marshal.GetLastWin32Error());

Ahora, todo esto está bien, ya que arroja una excepción que contiene adecuadamente el código de error de Win32 que se estableció, así como una descripción (generalmente) legible por humanos del error como la propiedad de Message del objeto de Excepción. Sin embargo, he estado pensando que sería aconsejable modificar / envolver al menos algunas, si no todas, de estas excepciones para que den un mensaje de error ligeramente más orientado al contexto, es decir, uno más significativo en cualquier situación en que esté el código nativo. siendo utilizado. He considerado varias alternativas para esto:

  1. Especificando un mensaje de error personalizado en el constructor para Win32Exception .

    throw new Win32Exception(Marshal.GetLastWin32Error(), "My custom error message.");

  2. Envolver la Win32Exception en otro objeto de excepción para que se conserven tanto el código de error original como el mensaje (la Win32Exception es ahora la InnerException de la excepción principal).

    throw new Exception("My custom error message.", Win32Exception(Marshal.GetLastWin32Error()));

  3. Lo mismo que 2, excepto que se usa otra excepción Win32Exception como la excepción de contenedor.

  4. Lo mismo que 2, excepto que se usa una clase personalizada derivada de Exception como la excepción de envoltura.

  5. Lo mismo que 2, excepto que se usa una excepción BCL (Biblioteca de clases base) como principal cuando sea apropiado. No estoy seguro de si es apropiado establecer la InnerException en Win32Exception en este caso (tal vez para un envoltorio de bajo nivel pero no para una interfaz abstracta / de alto nivel que no haga evidente que la interoperabilidad de Win32 está sucediendo detrás de escena).

Esencialmente, lo que quiero saber es: ¿cuál es la práctica recomendada para tratar los errores de Win32 en .NET? Lo veo hecho en código de código abierto de diferentes maneras, pero tenía curiosidad por si había alguna guía de diseño. Si no, estaría interesado en sus preferencias personales aquí. (¿Quizás incluso no utilices ninguno de los métodos anteriores?)


Esto no es realmente específico a las excepciones de Win32; la pregunta es, ¿cuándo deberían identificarse dos casos de error diferentes por dos tipos diferentes derivados de Excepciones, y cuándo deberían arrojarse el mismo tipo con diferentes valores almacenados en su interior?

Desafortunadamente, esto es imposible de responder sin conocer de antemano todas las situaciones en las que se llamará su código. :) Este es el problema con el hecho de que solo se puedan filtrar las excepciones por tipo. En términos generales, si tiene la fuerte sensación de que sería útil tratar dos casos de error de manera diferente, lance diferentes tipos.

De lo contrario, es frecuente que la cadena devuelta por Exception.Message solo deba registrarse o mostrarse al usuario.

Si hay información adicional, envuelva la excepción Win32Exception con algo más de su propio nivel. Por ejemplo, estás tratando de hacer algo con un archivo, y el usuario con el que te estás ejecutando no tiene permiso para hacerlo. Capture la excepción Win32Exception, envuélvala en una clase de excepción propia, cuyo mensaje proporciona el nombre de archivo y la operación que se intenta realizar, seguido del mensaje de la excepción interna.


Mi punto de vista siempre ha sido que la forma adecuada de manejar esto depende de la audiencia objetivo y cómo se usará su clase.

Si la persona que llama a su clase / método se dará cuenta de que está llamando a Win32 de una forma u otra, usaría la opción 1) que ha especificado. Esto me parece lo más "claro". (Sin embargo, si este es el caso, nombraré a su clase de manera que quede claro que la API de Win32 se usará directamente). Dicho esto, hay excepciones en el BCL que, en realidad, subclase Win32Exception para ser más claro, en lugar de simplemente envolverlo. Por ejemplo, SocketException deriva de Win32Exception. Personalmente nunca he usado ese enfoque, pero parece una forma potencialmente limpia de manejar esto.

Si la persona que llama de su clase no tiene idea de que está llamando directamente a la API de Win32, yo manejaría la excepción y usaría una excepción personalizada, más descriptiva, que usted define. Por ejemplo, si estoy usando tu clase y no hay ninguna indicación de que estés usando la API de Win32 (ya que la estás utilizando internamente por alguna razón específica y no obvia), no tendría ninguna razón para sospechar que puede necesitar manejar una excepción Win32Exception. Siempre puede documentar esto, pero me parece más razonable atraparlo y dar una excepción que tenga más significado en su contexto empresarial específico. En este caso, podría ajustar la excepción Win32Exception inicial como una excepción interna (es decir, su caso 4), pero dependiendo de lo que causó la excepción interna, podría no hacerlo.

Además, hay muchas veces en que se emitirá una Win32Exception desde una llamada nativa, pero hay otras excepciones en el BCL que son más relevantes. Este es el caso cuando llama a una API nativa que no está envuelta, pero hay funciones similares que están envueltas en el BCL. En ese caso, es probable que atrape la excepción, me asegure de que sea lo que estoy esperando, pero luego coloque la excepción BCL estándar en su lugar. Un buen ejemplo de esto sería usar SecurityException en lugar de lanzar una Win32Exception.

En general, sin embargo, evitaría las opciones 2 y 3 que mencionaste.

La opción dos arroja un tipo de Excepción general. Recomendaría evitarlo por completo. Parece irrazonable envolver una excepción específica en una más generalizada.

La opción tres parece redundante: realmente no hay ventaja sobre la opción 1.


Personalmente haría # 2 o # 4 ... Preferiblemente # 4. Envuelva Win32Exception dentro de su excepción que es sensible al contexto. Me gusta esto:

void ReadFile() { if (!WinApi.NativeFunction(param1, param2, param3)) throw MyReadFileException("Couldn''t read file", new Win32Exception()); }

De esta manera, si alguien descubre la excepción, tendrán una idea bastante clara de dónde ocurrió el problema. No haría el # 1 porque requiere la captura para interpretar el mensaje de error de texto. Y # 3 realmente no da ninguna información adicional.