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;


}


 

2 comentarios sobre “Reiniciar Windows desde .NET”

Deja un comentario

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