¿Por qué aparece el fatídico mensaje “No hay disco en la unidad”?

Es posible que en alguna ocasión le aparezca un mensaje de error bastante curioso que, sin motivo aparente, le advierte de que no hay disco en la unidad. Suele aparecer al trabajar con alguna aplicación, o bien al iniciar el sistema, y tiene un aspecto similar a la siguiente imagen:

Inserte_disco_unidad

¿Por qué ocurre este mensaje de error?

La representación de un proceso en Windows es una estructura de datos que internamente se denomina EPROCESS (que viene de executive process) y que reside en espacio de memoria de núcleo. Este bloque contiene numerosos campos y apuntadores a estructuras de datos auxiliares (entre otras, el PEB o bloque de entorno de proceso). Es uno de estos campos el que le dice a Windows si el proceso es quien va a manejar los errores graves de sistema, tales como errores de E/S, fallos de alineamiento, etc. y cómo va a hacerlo. Vemos esto de forma práctica usando Windbg como depurador, habiendo iniciado una sesión de depuración de núcleo y escribiendo este comando:

lkd> dt _eprocess

[…]

+0x284 ImagePathHash : Uint4B
+0x288 DefaultHardErrorProcessing : Uint4B
+0x28c LastThreadExitStatus : Int4B
+0x290 Peb : Ptr64 _PEB
+0x298 PrefetchTrace : _EX_FAST_REF
+0x2a0 ReadOperationCount : _LARGE_INTEGER
+0x2a8 WriteOperationCount : _LARGE_INTEGER
+0x2b0 OtherOperationCount : _LARGE_INTEGER
+0x2b8 ReadTransferCount : _LARGE_INTEGER

[…]

El campo “DefaultHardErrorProcessing” está marcado en negrita porque es el que nos interesa para este artículo. Cuando Windows crea un proceso, como podrá intuir, una de las fases de inicialización implica rellenar la estructura EPROCESS. Una vez que se rellena la estructura EPROCESS esta se inserta en la lista de procesos activos y en el espacio de nombres del administrador de objetos de Windows (Object Manager), el cual devuelve un handle único que permite que el proceso sea accesible tanto para el sistema como para el resto de aplicaciones. El valor inicial del campo “DefaultHardErrorProcessing” generalmente se hereda del proceso padre, y por defecto hace que el sistema muestre todos los errores graves de sistema que ocurran. La ventana de error aparece cuando ocurre un error grave y el proceso o hilo en cuestión no lo ha gestionado.

¿Cómo cambiar el contenido del atributo de proceso DefaultHardErrorProcessing para que en vez de mostrar una ventana de error se le envíe el error al proceso para que lo trate?

Se puede usar la API pública SetErrorMode, que admite diferentes parámetros según el tipo de error grave que queramos delegar al proceso en cuestión. De esta manera evitaremos que aparezcan crípticas ventanas de error (como la que aparece al comienzo del artículo), y que nuestra aplicación quede a la espera de que interactuemos con dicha ventana para proseguir con su funcionamiento. En Windows Vista se añadió al bloque de entorno de hilo (TEB) un nuevo campo de control de errores graves, como puede comprobar si ejecuta el comando !teb en una sesión de depuración de núcleo en Windbg (en Windows Vista o Windows 7):

kd> !teb

[…]

HardErrorMode:        0`

[…]

Si bien este campo está presente desde Windows Vista, no fue hasta la llegada de Windows 7 cuando se creó una API pública para que los desarrolladores pudieran modificarlo en sus programas: SetThreadErrorMode. Esta API surgió de la necesidad por parte de las aplicaciones multi-hilo de cambiar este valor sin afectar al valor por proceso (que automáticamente es heredado por cada nuevo hilo).

Así pues, es recomendable que las aplicaciones hagan uso de la siguiente llamada a función para evitar que la experiencia de usuario sea poco agradable en caso de que ocurran errores graves:

SetErrorMode(SEM_FAILCRITICALERRORS);

o bien, en Windows 7:

SetThreadErrorMode(SEM_FAILCRITICALERRORS);

Esta es la causa por la cual aparecen mensajes del tipo “No hay disco en la unidad” en los momentos más inoportunos. Por suerte Windows ofrece a los desarrolladores la posibilidad de manejar apropiadamente estas circunstancias excepcionales para así proporcionar una experiencia de usuario más agradable. Espero que este artículo haga más visibles estas posibilidades y todos disfrutemos de un mejor ecosistema.

One thought on “¿Por qué aparece el fatídico mensaje “No hay disco en la unidad”?

  1. Desde el punto de vista de un desarrollador, si no quiero “pasar verguenza” y que al producirse este error, supongo yo, al tratar de acceder un archivo en F:\ siendo F:\ un disco extrahíble que no siempre está presente o una unidad que cambió de letra, debo usar SetThreadErrorMode(SEM_FAILCRITICALERRORS); para que mi aplicación maneje el error y así evitar que se muestre el diálogo por defecto del sistema. Por ejemplo, en C++ la manera estándar de ver si existe un archivo es tratar de abrirlo para escritura usando fopen por ejemplo o intentar crear un file stream (esto si se quiere evitar usar una llamada específica del api de Windows), esto debería mostrar el diálogo de error si la unidad a la que la aplicación intenta acceder no está presente, también es por cosas como esta que no se debería verificar la existencia de un fichero de esa forma.

    El artículo tiene la medida justa de información, igual que todo lo que he leído en este blog.

    Muchas gracias.

Leave a Reply to JH Cancel reply

Your email address will not be published. Required fields are marked *