Reiniciar Windows desde .NET

En anteriores entradas comenté que explicaría cómo reiniciar Windows desde un programa hecho en .NET. Hasta donde yo sé el .NET Framework no tiene un API para cerrar la sesión actual o para reiniciar el sistema, así que tenemos que hacer las llamadas oportunas al código nativo.


En Win32 hay dos funciones para realizar la tarea, la original, ExitWindows y otra más moderna y que permite más cosas, ExitWindowsEx.


Pero si probamos a llamarlas directamente nos damos cuenta de que Windows nos ignora por completo y no hace nada. Eso se debe a que un programa no tiene los privilegios necesarios para realizar tal tarea, por lo que es necesario que primero se los asigne antes de llamar al método de reinicio.


El privilegio que necesitamos es SE_SHUTDOWN_NAME para poder reiniciar el propio ordenador o para cerrar la sesión activa. Y ya que vamos a necesitar acceso al código nativo, lo vamos a hacer desde un método que hemos llamado MySystemShutdown y que recibe un valor UINT (equivalente a un UInt32 del .NET) con la acción que queramos realizar.


Los valores posibles para el parámetro son:
























Nombre Macro


Valor numérico


Descripción


EWX_LOGOFF


0


Cierra la sesión actual


EWX_POWEROFF


0x00000008


Apaga el ordenador.


EWX_REBOOT


0x00000002


Reinicia el ordenador.


EWX_RESTARTAPPS


0x00000040


Reinicia el ordenador abriendo todas las aplicaciones que hubiera registradas para hacerlo.


 


Aquellos que estén utilizando C++/CLI deben tener dichas macros habilitadas si han incluido Windows.h. Los programadores de C# pueden utilizar los valores numéricos (aparte de tener que traducir la rutina o meterla en una clase y crearse un ensamblado).


Y, finalmente, el código (que está sacado de la MSDN con ligeras modificaciones):


BOOL MySystemShutdown(UINT action)


{


   HANDLE hToken;


   TOKEN_PRIVILEGES tkp;


 


   // Get a token for this process.


   if (!OpenProcessToken(GetCurrentProcess(),


        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))


      return( FALSE );


 


   // Get the LUID for the shutdown privilege.  


   LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,


        &tkp.Privileges[0].Luid);


 


   tkp.PrivilegeCount = 1;  // one privilege to set   


   tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;


 


   // Get the shutdown privilege for this process.  


   AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,


        (PTOKEN_PRIVILEGES)NULL, 0);


 


   if (GetLastError() != ERROR_SUCCESS)


      return FALSE;


 


   // Shut down the system and force all applications to close.  


   if (!ExitWindowsEx(action | EWX_FORCE,


               SHTDN_REASON_MAJOR_OPERATINGSYSTEM |


               SHTDN_REASON_MINOR_UPGRADE |


               SHTDN_REASON_FLAG_PLANNED))


      return FALSE;


 


   return TRUE;


}


 

Ejecutar un programa antes de que se inicie Windows (y II)

En la entrada anterior hablaba sobre cómo lanzar un programa para que se ejecute antes del inicio de Windows basado en mis propias investigaciones. Tras un comentario de Peni, decidí probar un programa cualquiera… para descubrir que no funciona.

Un sesudo destripe de los dos programas que sé lo hacen, a saber, PDBoot.exe y autochk.exe comenzó a darme una ligera idea de qué es necesario. Para ello el que suscribe abrió una consola de comandos del Visual Studio, se fue a C:WindowsSystem32 y ejecutó el conocido dumpbin sobre dichos programas, a saber:

dumpbin /exports <fichero>

El autochk.exe no exporta nada, pero el otro sí, en general funciones relacionadas con la desfragmentación. Luego hizo lo mismo con las importaciones, y ahí sí que obtuvo algo interesante. Lo siguiente es la importación de funciones de autochk.exe:

ntdll.dll
77F497AB 716 _wcsicmp
77F20011 76A wcsstr
77F3F354 CD NtClose
77F40014 1A1 NtQueryValueKey
77F3FC24 150 NtOpenKey
77F22F50 3B3 RtlInitUnicodeString
77F3FFA4 19A NtQuerySymbolicLinkObject
77F3FCD4 15D NtOpenSymbolicLinkObject
77F1764A 42E RtlPrefixUnicodeString
77F42EF7 33F RtlEqualUnicodeString
77F3FE04 179 NtQueryDirectoryObject
77F3FBC4 149 NtOpenDirectoryObject
77F78664 85 LdrSetMUICacheType
77F40574 20A NtTerminateProcess
77F89B82 4BC RtlUnhandledExceptionFilter
77F02B68 4D0 RtlUnwind

Y sigue así hasta algo más de cien exportaciones. Está claro que el programa está utilizando el API nativo de Windows, no el subsistema Win32 como hacen todos los programas comunes. Además, si lanzamos el programa citado nos dice que no se puede ejecutar bajo Win32.

Así que una en la frente: no se trata de un ejecutable normal y corriente, sino de algo especial. La primera pregunta es: ¿quizás sea el formato ejecutable de un driver, o sólo la obligatoriedad de no realizar llamadas a Win32?

Y aquí es donde el autor de esto decide hacer lo que debió haber hecho desde un primer momento: consultar en Google.

¿Y qué encontró? Pues esto: http://www.microsoft.com/technet/sysinternals/information/NativeApplications.mspx. Entre otras cosas, le dice que necesita el DDK de Windows, y que debe usar funciones como NtDisplayString y no printf. En fin, que como el autor ya tiene suficiente con su trabajo diario como para meterse en camisa de once varas, pues decide detenerse aquí en cuanto al tema de ejecutar programas propios antes del inicio de Windows, de modo que lo publicado hasta ahora solo sirve para lanzar un chequeo de disco, que no es poco.

También ha añadido una nueva función que ha llamado RemoveBootExecuteEntry, y a la de la entrada anterior le ha cambiado el nombre por AddBootExecuteEntry. Un ejemplo completo se puede bajar de aquí. Y eso es todo.

Addenda
Como no quiero que este comentario de Ramón Sola se pierda, lo añado aquí:

Eso se puede observar en la cabecera PE. El valor de subsistema no es 3 (interfaz de consola) ni 2 (interfaz gráfica), sino 1 (nativo, no requiere subsistema). Csrss.exe es el programa nativo responsable del subsistema Windows en modo usuario, siendo Win32k.sys la parte kernel.

Las API nativas de Windows apenas están documentadas. El propósito de esta ocultación de información, según veo yo, es el de evitar el desarrollo de programas que dependan excesivamente de la implementación interna del sistema operativo, ya que puede variar mucho de una versión del sistema operativo a otra (o incluso de un service pack a otro). Esto ha generado acusaciones más o menos fundadas contra Microsoft de no proporcionar igualdad de oportunidades; de aprovecharse del conocimiento del subsistema nativo para provecho de sus propios productos en detrimento de la competencia, que tiene que acogerse forzosamente al subsistema Win32. Si algunas empresas como Raxco o Diskeeper son capaces de desarrollar productos que se apoyan directamente en los servicios nativos, debe de ser porque Microsoft comparte la información con ellas de algún modo, mediante algún acuerdo.

Los módulos nativos en modo usuario enlazan directa o indirectamente a Ntdll.dll y no pueden o no deberían depender de bibliotecas Win32. Los módulos nativos en modo kernel son los drivers, que enlazan a Ntoskrnl.exe, Hal.dll u otros drivers (controladores de minipuerto, por ejemplo).

Por el contrario, el subsistema Win32 depende considerablemente de los servicios nativos y otras rutinas de apoyo que ofrece Ntdll.dll. No tienes más que fijarte en las tablas de importación de Kernel32, User32, Gdi32, Advapi32 y otras DLLs de Windows. Además, en las tablas de exportación de Kernel32 podrás observar incluso «forwards» (no sé cómo traducirlo), entradas que remiten a otras DLLs. Por ejemplo, la llamada a HeapAlloc desde un programa Win32 se resuelve en tiempo de carga a la rutina RtlAllocateHeap en Ntdll.dll.

Versiones de Windows NT anteriores a Windows XP incluyeron otros subsistemas aparte de Win32. Por ejemplo, Windows 2000 incluía un subsistema POSIX, y Windows NT 4 también un subsistema OS/2 que emulaba OS/2 1.x (aplicaciones en modo texto). Parece que no llegaron a ser muy populares.

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.

Atributos y reflexión (Cosas curiosas de C#, último post)

Atributos
Con esta largamente proyectada y nunca escrita (hasta ahora) entrada pretendo finalizar la serie de temas curiosos o novedosos (o más bien el hecho de que me hayan resultado curiosos a mí personalmente) sobre el lenguaje C#, para pasar a otras cosas. En algún lugar –hace ya bastante tiempo- dije que no me gustaban los atributos, al menos para realizar Interop con código nativo, pensando que la única finalidad de ellos era la citada, pero no es así, una parte de los atributos es el Interop, pero tiene muchas otras más, todas ellas interesantes, y como rectificar es de sabios –y no es que yo lo sea-, los atributos es una de las cosas que más me están gustando del .NET, ahora que empiezo a conocerlos en todo su esplendor.

Pero, ¿qué son los atributos? Son la forma de indicar dentro del código fuente que ciertos métodos o clases tienen un comportamiento especial definido mediante dichos atributos, amén de poder incluir toda una serie de metadatos dentro del código ejecutable para que sirva a nuestros propósitos o a los del entorno de ejecución. En pocas palabras, es mediante el uso de atributos como el .NET (y el Visual Studio) sabe la mayoría de cosas sobre el código que está ejecutando, así como su comportamiento.

Dicho esto, y tomando un ejemplo un tanto trivial, la construcción

[Serializable]
class Dato
{
    int d1,d2;
}

está indicando al compilador y al entorno de ejecución que la clase asociada es serializable, es decir, que puede ser guardada automáticamente en un flujo de datos, por lo que su implementación final dentro del código será algo diferente si no hubiera indicado dicho atributo.

Existen infinidad de atributos predefinidos que nos permiten desde hacer lo de arriba hasta indicar de qué forma se van a distribuir los datos en una estructura, pasando por indicar que una enumeración está compuesta de flags, potenciar la compilación condicional de forma que ciertos métodos se ejecuten como si estuvieran vacíos, marcar algo como obsoleto y que podría ser eliminado en siguientes versiones, utilizar código nativo y hacer llamadas a bibliotecas de terceros realizadas en otros lenguajes, y un larguísimo etcétera. La MSDN contiene una referencia completa sobre los atributos existentes si se busca la clase System.Attribute y se miran todas las clases que heredan de ella, lo que nos mete de lleno en el siguiente párrafo.

Y es que aparte de utilizar los existentes, también podemos crear nuestros propios atributos de forma sencilla, o más bien de la misma forma en que creamos nuestras propias clases: heredando de Attribute o de alguna de sus hijas. La utilidad de todo esto no es evidente a simple vista, pero lo cierto es que podría ser de mucha utilidad en la metaprogramación y en la creación de herramientas y extensiones al lenguaje. Imaginemos que estamos haciendo una herramienta para medir el código que cada programador realiza mediante la obligación de que cada programador marque su código con una propiedad que signifique su nombre y la fecha en que empezó el código. Es solo un ejemplo que no voy a detallar (más que nada porque ando algo falto de tiempo y porque es el ejemplo típico de la MSDN y de algún libro), pero su implementación mediante atributos es muy sencilla.

Claro está, si tenemos atributos personalizados debemos ser capaces de obtenerlos en tiempo de ejecución, si no de poco nos iban a servir. Y ello es completamente posible mediante el uso de typeof aplicado al elemento del que queremos obtenerlos. De nuevo en la MSDN tenemos varios ejemplos, que se entenderán mejor si antes seguimos el punto sobre la reflexión de esta entrada, ya que los citados se obtienen gracias a la misma.

Lo importante de todo esto está en que podemos cualificar y calificar nuestro propio código asociando metainformación que en determinadas situaciones podrían hacer que el código funcione de diferente forma a la deseada, o simplemente a incluir información extendida sobre lo que estamos haciendo, como tener un sistema de ayuda no sólo integrado en el código fuente, sino también disponible en tiempo de ejecución, que es la forma en la que está documentado en mayor parte el .NET y que las herramientas de desarrollo son capaces de obtener.

Reflexión
Una de las cosas que permiten los atributos, o más bien una de las cosas en las que los atributos forman parte directa e importante es la reflexión. No, no es cuestión de pensar, si no de, sin saber qué código vamos a cargar, poder ejecutarlo sin más o incluso lanzar métodos y acceder a elementos que teóricamente no están a nuestro alcance, como puede ser entrar y conocer el nivel de acceso privado de un objeto. Con la reflexión también podemos acceder a los atributos arriba citados.

Para entendernos diremos que es un paso más allá del OLE, ActiveX y COM, mucho más potente y seguro. Para un programador de C++, tanto los atributos como la reflexión son un RTTI a lo grande (realmente demasiado grande y con demasiado código oculto para que nos guste, pero eso no evita que esté ahí y que se pueda utilizar).

El primer paso consiste en obtener una referencia a un objeto de la clase Type mediante el método miembro GetType() que toda clase .NET y C# posee, incluso los tipos por valor (aquí es donde podemos ver una aplicación práctica a la dualidad clase-tipo de la que en su momento hablé y que, siendo sincero, sigue sin gustarme). También podemos utilizar la expresión typeof().

Luego podemos hacer muchas cosas con ello, desde la obtención de los atributos de un objeto como ya hemos dicho, o la ejecución de métodos que en principio no están accesibles, como el ejemplo de esta entrada mía, en la que explico cómo activar el doble buffer en un panel.

Lo cierto es que estas dos características dan al .NET Framework y a sus familiares cercanos una potencia nada desdeñable y a la que los programadores de sistemas no estamos acostumbrados.