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



“HKLMSYSTEMCurrentControlSetControlSession 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.

11 comentarios en “Ejecutar un programa antes de que se inicie Windows”

  1. He hecho pruebas con 3 equipos diferentes aparte del de desarrollo, y no parece romper nada, tanto en XP como el Vista.

    En este momento hay 200 máquinas en la calle ejecutando ese código sin problemas bajo XP Embedded (aunque en realidad es una sola, ya que son imágenes replicadas).

    Lo que no he probado es con otros comandos, como un cmd.exe o similar, y parece ser que la clave tampoco la borra Windows, así que si añades algo no olvides quitarlo… Mañana pongo otra entrada sobre cómo quitarlo y si tengo tiempo probaré otros comandos.

  2. A) Claro que se puede hacer en C# sin problema ninguno. Sólo tienes que traducir directamente, ten en cuenta que no es C++, si no C++/CLI.

    B) Sí que se puede, y de hecho tienes un montón de clases para ello en el espacio de nombres System.Diagonstic. Con la clase EventLog, por ejemplo. En http://msdn2.microsoft.com/en-us/library/e6t4tk09(vs.80).aspx tienes más info.

    C) En este caso no es necesario, en otros sí. El problema del C# frente al C++/CLI es que con este último tenemos destrucción determinista, algo más de rendimiento y un interop mucho más fácil. Respecto al C++ nativo, está claro que el C# no tiene nada que hacer.

  3. El programa que instala el programa que se ejecutará antes es trivial hacerlo, como puedes ver. Apenas son unas líneas.

    Ni borracho de cocacola en lo que respecta al programa que se ejecutará antes de que Windows termine de arrancar.

    Sólo en C/C++ y sin aprovechar todo lo que ofrece Win32.

    Ramón Sola tiene un comentario en este blog que explica por qué.

Deja un comentario

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