C++: Capturar excepciones del sistema operativo

Juguemos un rato con el siguiente código fuente:

 

   1: #include "stdafx.h"
   2: #include <Windows.h> 
   3:  
   4: int _tmain(int argc, _TCHAR* argv[])
   5: {
   6:     HANDLE hHeap=HeapCreate(HEAP_GENERATE_EXCEPTIONS,0,4096); 
   7:  
   8:     try
   9:     {
  10:         for(;;)
  11:             HeapAlloc(hHeap,HEAP_GENERATE_EXCEPTIONS,1024);
  12:     }
  13:     catch(...)
  14:     {
  15:         ;
  16:     } 
  17:  
  18:     HeapDestroy(hHeap);
  19:     return 0;
  20: } 

El programa es muy sencillo: crea un montículo local de 4Kb (una página de RAM) y luego se vuelve loco asignando bloques de 1KB. Como buenos programadores de C++ que somos, encerramos la asignación de memoria dentro de un bloque try y capturamos cualquier excepción que se pueda producir. Luego liberamos de un plumazo el montículo asignado, sin preocuparnos de los bloques que hemos asignado (que es una de las ventajas de trabajar con montículos locales).

Evidentemente, cuando intentemos asignar un bloque que no quepa, la función lanzará una excepción, que será capturada por nuestro bloque catch, ¿no? (Dejaremos como ejercicio para el lector el hecho de que la excepción ocurra en la tercera iteración y no en la quinta).

Pues si no hemos tocado nada de las opciones del proyecto, no. Nos saltará el IDE con una excepción no controlada en lugar de nuestro bloque de captura… mmmmm… curioso.

¿Qué está ocurriendo? Básicamente que el modelo de excepciones de Windows no es el mismo que el de C++; es decir, las excepciones producidas o lanzadas dentro de las funciones Win32 no son directamente compatibles con C++, quizás porque cuando Windows se hizo… el C++ era un animal mitológico que solamente unos pocos gurús utilizaban y que en general consistía en un metacompilador que generaba código C, sin estandarización alguna. También pudo haberse debido a que como Win32 se programa directamente en C, no se esperaba que el C++ tuviera la importancia que ahora tiene.

Pero entonces, ¿cómo capturo una excepción Win32? En el C de Microsoft (y por extensión también en su C++, ignoro si otros compiladores también lo soportan), existen los bloques __try/__except/__finally, que realizan una especie de pseudocontrol de excepciones un tanto barroco, ya que los parámetros para el bloque __exceptse definen de una forma un tanto estrambótica.

Como este tipo de control de excepciones no se debe puede mezclar con el de C++, no vamos a entrar en detalles sobre su funcionamiento, sino que vamos a poner un enlace con un ejemplo: http://msdn2.microsoft.com/en-us/library/ms681409(VS.85).aspx. Y este otro con el punto de entrad en la MSDN sobre el tema: http://msdn2.microsoft.com/en-us/library/ms680657(VS.85).aspx.

Entonces, ¿qué? ¿Se puede o no se puede? Pues claro que se puede, tan sólo hay que cambiar una opción del proyecto.

image

Nos vamos a la pantalla de que estamos viendo en la captura de arriba, y cambiamos en Enable C++ Exceptions» la opción por defecto de «Yes (EHsc)» por la mostrada en la imagen.

¿Qué hemos hecho? Pues le hemos dicho al compilador que habilite la compatibilidad con las excepciones de Win32, de forma que, una vez compilado el ejemplo de arriba con esta opción activada, se nos disparará correctamente la excepción.

Según la documentación, se pierde algo de optimización agresiva en las excepciones, pero pienso que las ventajas superan a los inconvenientes, ya que hemos normalizado el control de las excepciones.

3 comentarios sobre “C++: Capturar excepciones del sistema operativo”

  1. Hola Rafael,

    Actualmente tengo un aplicativo desarrollado en Visual C++ (VS2008) el cual, después de alrededor de un año en producción, me está dando el siguiente error:

    Excepción win32 no controlada en xxx.EXE [738], tendrás alguna idea de cual puede ser la causa?

    Gracias de antemano por tu ayuda.

    Att
    Jhon

  2. Pues no tengo ni idea, pero podrías activar la opción que comento en el post, poner un bloque try/catch y capturarla, o incluso intentar reproducirla desde el debugger…

    Por experiencia, cuando pasa alguna cosa de estas en un soft en producción suele deberse a cosas tan tontas como que no hay espacio suficiente en disco, o han cambiado el nombre de algún recurso…

  3. Temgo un programita en c++ y necesito capturar la ram de la maquina, es decir las propiedades de esta, mira a ver si puedes ayudarme que estoy enredeado con eso.

    Gracias

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *