2012-09-25 34 views
6

Si un tipo de tiempo de ejecución de Windows provoca un error COM .NET parece envolver este error a menudo (¿o siempre?) Solo en una instancia Exception. El mensaje de error incluye el código de error COM HRESULT. Al utilizar la nueva API criptográfica con AES-CBC, por ejemplo, una longitud de búfer incorrecta da como resultado un Exception con el mensaje "El búfer de usuario proporcionado no es válido para la operación solicitada. (Exception from HRESULT: 0x800706F8)".¿Cómo manejar las excepciones de WinRT que resultan en Excepción?

Bueno, ¿cómo se supone que debemos manejar esas excepciones? ¿Deberíamos leer el código HRESULT de la excepción para tener una idea del tipo de excepción que fue? En .NET clásico obtendría un CryptographicException que podría utilizar para distinguir los errores criptográficos de otros errores.

Otra cosa que no entiendo es que las reglas de calidad del código de Microsoft indican que uno nunca debe arrojar Excepción, sino siempre los tipos derivados. La razón es que nadie debería verse obligado a detectar el Exception general que también captura más excepciones fatales como OutOfMemoryException. Otra regla dice que nunca se debe capturar Exceptio n en las bibliotecas. ¿Cómo podríamos seguir estas políticas si nos vemos obligados a atrapar Exception en las aplicaciones de la Tienda Windows o en las bibliotecas WinRT?

Por cierto: Clemens Vasters shows in his blog how we can catch Exception while avoiding to catch fatal exception. Supongo que capturar Exception ya no es un código malo.

+0

Con respecto a la entrada del blog vinculado, muchas de las excepciones "fatales" enumeradas no pueden ser detectadas por el código administrado. Notablemente, 'StackOverflowException', aunque estoy bastante seguro de que los AV no pueden ser capturados tampoco (ambos pueden ser capturados en código nativo, por supuesto, pero hacerlo es peligroso). Tenga en cuenta también que algunas excepciones que _parecen_ fatales pueden no serlo de hecho. Por ejemplo, muchos componentes COM devuelven 'E_OUTOFMEMORY' cuando se agota el espacio en un búfer en particular. Este HRESULT se traducirá como OutOfMemoryException, pero no significa que el proceso haya agotado todo su espacio de direcciones. –

Respuesta

4

Es posible detectar Exception, manejar determinados errores al encender HRESULT, y volver a lanzar el Exception si el error fue "inesperado". Por ejemplo,

try 
{ 
    // ... 
} 
catch (Exception ex) 
{ 
    switch (ex->HResult) 
    { 
    case E_INVALID_USER_BUFFER: // 0x800706f8 
     // handle invalid buffer case... 
     break; 
    default: 
     // Unexpected exception; re-throw: 
     throw; 
    } 
} 

(I desean señalar que proporciona una amortiguación inválida suena más como un error lógico que un error de ejecución, por lo que me pregunto si esta excepción en particular realmente debe ser capturado.)

Alternativamente, una una solución más general sería escribir una función o un conjunto de funciones que manejen Exception para HRESULT conocidos y vuelvan a lanzar una excepción más específica. Por ejemplo,

static void HandleKnownExceptions(Action f) 
{ 
    try 
    { 
     f(); 
    } 
    catch (Exception ex) 
    { 
     // Detect expected HRESULTs and throw the more-specific exception 
     // type for each. 
    } 
} 

Ambos enfoques funcionan igual de bien tanto en C++ como en C#.

Tenga en cuenta que no es necesariamente el caso de que Exception sea lanzado directamente por la plataforma u otros componentes. En la capa ABI de Windows Runtime, no hay excepciones: todos los errores se informan a través del límite ABI por HRESULT. El CLR traduce un puñado de HRESULT conocidos a tipos de excepción más específicos, pero no puede realizar una traducción general.

+0

Gracias James. Ese fue mi enfoque al atrapar el buffer inválido HRESULT. Me parece un poco extraño que los programadores de .NET ahora tengan que lidiar con HRESULTS. Obtienes fácilmente un búfer no válido cuando intentas descifrar datos inválidos que pueden haber sido moderados o simplemente recortados. Creo que es casi imposible verificar los datos cifrados para la longitud correcta porque esto depende del algoritmo y la clave utilizados. Ya es suficientemente difícil averiguar el tamaño de bloque usado.Capturar el error de memoria intermedia no válida es vital para garantizar que los datos no válidos se traten de manera fácil de usar. –

+0

Ah, mi error entonces. No entendí qué buffer era inválido. Tienes razón, manejar ese tipo de error es una buena idea :-) –

Cuestiones relacionadas