Ejecutar un programa antes de que se inicie Windows
Seguro que cualquier usuario de Windows ha visto cómo justo en medio del arranque de su PC, se modifica la pantalla de inicio de forma un tanto extraña y se inicia un chequeo del disco duro. O si utiliza herramientas como el Acronis Disk Director, tras el pertinente reinicio se lanzan en dicho lugar las herramientas, o también con los desfragmentadores comerciales como el Perfect Disk o el Diskeeper.
¿Cómo puede hacer uno eso mediante código para, por ejemplo, forzar un chequeo del disco de sistema sin intervención del usuario? Es decir, si uno intenta lanzar un chkdsk con la opción /f desde una ventana sobre el disco de sistema (aunque sea por programa), chkdsk le dirá que no puede verificar ahora, que si quiere hacerlo en el siguiente reinicio, requiriendo la intervención del usuario.
O quizás estemos haciendo una aplicación de sistemas que requiera acceso a disco antes de que el propio Windows lo bloquee…
La teoría
Justo es que si Windows puede hacerlo, nosotros también. Todo el meollo del asunto está en una clave del registro, situada en
"HKLM\SYSTEM\CurrentControlSet\Control\Session Manager"
llamada
"BootExecute"
y que suele contener un array de cadenas con el texto (en mi caso, que tengo instalado el Perfect Disk)
"PDBoot.exe","autocheck autochk *"
Una inspección a dicha clave tras haber lanzado un chequeo de disco y haber aceptado la opción de reinicio devuelve
"autocheck autochk /p \\??\\C:","PDBoot.exe","autocheck autochk *"
Podemos observar que a lo existente se le ha añadido una nueva línea, justo al principio de todo. Con esto ya tenemos claro cómo funciona todo el asunto: una línea por comando, con la observación de que los programas de aplicación pueden, también, trastear con la clave sin peligro, ya que el software del Perfect Disk así lo hace.
El algoritmo
Para evitar eliminar entradas existentes, se hace necesario en primer lugar leer el contenido de dicha clave, añadir al principio nuestra nueva línea, y después volver a escribir la clave. Opcionalmente nos queda reiniciar, cosa que explicaré cómo hacer en una próxima entrada.
El ejemplo (en C++/CLI)
Esta vez he optado por un ejemplo completo de consola de comandos. Quien quiera probarlo sólo tiene que crearse un proyecto nuevo y sustituir el texto de su fichero principal por el que pongo aquí.
// BootExecute.cpp : main project file.
#include "stdafx.h"
using namespace System;
using namespace Microsoft::Win32;
void
BootExecute(String ^nuevoValor)
{
//Abrimos la clave con permisos de escritura
RegistryKey ^key=Registry::LocalMachine->OpenSubKey("SYSTEM\\CurrentControlSet\\Control\\Session Manager",true);
//Leemos el valor
array<String ^> ^values=(array<String ^> ^)key->GetValue("BootExecute",gcnew array<String ^> {"ERROR"});
array<String ^> ^newValues;
//Aquí no deberíamos entrar, pero por si acaso...
if(values->Length==1 && values[0]=="ERROR")
newValues=gcnew array<String ^>(1) {nuevoValor};
else
{
//Creamos un nuevo array y copiamos los valores antiguos más el nuevo
newValues=gcnew array<String ^>(values->Length+1);
newValues[0]=nuevoValor;
Array::Copy(values,0,newValues,1,values->Length);
}
//Escribimos y nos vamos
key->SetValue("BootExecute",newValues);
key->Close();
}
int
main(array<System::String ^> ^args)
{
//Lo que vamos a añadir
String ^nuevoValor="autocheck autochk /p \\??\\C:";
BootExecute(nuevoValor);
return 0;
}
El funcionamiento es evidente por sí mismo, aparte de los profusos comentarios que ayudan a entender el programa. Básicamente abrimos la clave del registro, leemos los valores actuales, creamos un nuevo array con el nuevo valor y copiamos el de los valores actuales. Luego escribimos y ya está hecho.
El paso siguiente es explicar cómo reiniciar el sistema operativo, forzando incluso el mismo cierre, lo que requiere hacerlo con código nativo. Todo eso lo explicaré en una próxima entrada.
Comparte este post: