¿Puedes atrapar una excepción nativa en el código C #?

En el código C #, ¿puede capturar una excepción nativa lanzada desde las profundidades de una biblioteca no administrada? Si es así, ¿tiene que hacer algo diferente para atraparlo o lo intenta de manera estándar … atraparlo?

Puede usar Win32Exception y usar su propiedad NativeErrorCode para manejarlo adecuadamente.

// http://support.microsoft.com/kb/186550 const int ERROR_FILE_NOT_FOUND = 2; const int ERROR_ACCESS_DENIED = 5; const int ERROR_NO_APP_ASSOCIATED = 1155; void OpenFile(string filePath) { Process process = new Process(); try { // Calls native application registered for the file type // This may throw native exception process.StartInfo.FileName = filePath; process.StartInfo.Verb = "Open"; process.StartInfo.CreateNoWindow = true; process.Start(); } catch (Win32Exception e) { if (e.NativeErrorCode == ERROR_FILE_NOT_FOUND || e.NativeErrorCode == ERROR_ACCESS_DENIED || e.NativeErrorCode == ERROR_NO_APP_ASSOCIATED) { MessageBox.Show(this, e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } } 

Catch without () detectará excepciones que no cumplen con CLS, incluidas las excepciones nativas.

 try { } catch { } 

Consulte la siguiente regla de FxCop para obtener más información http://msdn.microsoft.com/en-gb/bb264489.aspx

La capa de interoperabilidad entre C # y el código nativo convertirá la excepción en una forma administrada, permitiendo que sea capturada por su código C #. A partir de .NET 2.0, catch (Exception) debería capturar cualquier cosa que no sea un error irrecuperable.

En algún lugar con un reflector .NET he visto el siguiente código:

 try { ... } catch(Exception e) { ... } catch { ... } 

Hmm, C # no permite arrojar una excepción que no se derive de la clase System.Exception. Y, por lo que sé, cualquier cautch de excepción por parte del marshaller de interoperabilidad está envuelto por la clase de excepción que hereda la excepción System.Exception.

Entonces mi pregunta es si es posible detectar una excepción que no sea una System.Exception.

Esto depende del tipo de excepción nativa de la que está hablando. Si se refiere a una excepción SEH, entonces el CLR hará una de dos cosas.

  1. En el caso de un código de error SEH conocido, lo correlacionará con la excepción .Net apropiada (es decir, OutOfMemoryException)
  2. En el caso de un código no mapeable (E_FAIL) o desconocido, lanzará una instancia de SEHException .

Ambos serán capturados con un simple bloque de “captura (Excepción)”.

El otro tipo de excepción nativa que puede cruzar el límite nativo / administrado son las excepciones de C ++. No estoy seguro de cómo se asignan / manejan. Supongo que, dado que Windows implementa las excepciones de C ++ sobre SEH, solo se asignan de la misma manera.

Casi, pero no del todo. Atrapará la excepción con

 try { ... } catch (Exception e) { ... } 

pero aún tendrás problemas potenciales. De acuerdo con MSDN , para asegurar que se invocan destructores de excepción, tendrías que atrapar como:

 try { ... } catch { ... } 

Esta es la única manera de asegurar que se llame a una excepción destructor (aunque no estoy seguro de por qué). Pero eso te deja con la compensación de la fuerza bruta frente a una posible fuga de memoria.

Por cierto, si usa el enfoque (Excepción e), debe conocer los diferentes tipos de excepciones que puede encontrar. RuntimeWrappedException es lo que se asignará a cualquier tipo gestionado que no sea de excepción (para los lenguajes que pueden lanzar una cadena), y otros se asignarán, como OutOfMemoryException y AccessViolationException. COM Interop HRESULTS o excepciones que no sean E___FAIL se correlacionarán con COMException, y finalmente al final tendrá SEHException para E_FAIL o cualquier otra excepción no asignada.

Entonces, ¿qué debería hacer? La mejor opción es no arrojar excepciones de su código no administrado. Hah. Realmente, si tiene una opción, ponga barreras y fallas que hagan que la elección sea peor, una posibilidad de pérdida de memoria durante el manejo de excepciones o no saber de qué tipo es su excepción.

Si usas un

 try { } catch(Exception ex) { } 

captará TODAS las excepciones, dependiendo de cómo llame a las bibliotecas externas, es posible que obtenga una excepción relacionada con las comunicaciones que encapsula el error, pero detectará el error.

Una captura de prueba estándar debería hacer el truco, creo.

Me encontré con un problema similar con una excepción System.data lanzando una excepción sqlClient que no fue detectada, agregando una try..catch en mi código, el truco en la instancia