Su un newsgroup ho letto di una persona che chiedeva come eseguire lo shutdown di Windows da programma. Con documentazione MSDN alla mano, ho scritto un paio di funzioni che fanno shutdown e reboot (bel modo di sfruttare la pausa pranzo, eh? :-)).

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
private struct LUID
{
    public uint LowPart;
    public uint HighPart;
};

[StructLayout(LayoutKind.Sequential)]
private struct TOKEN_PRIVILEGES
{
    public int PrivilegeCount;
    public LUID Privileges;
    public int Attributes;
};

[DllImport("kernel32.dll")]
private extern IntPtr GetCurrentProcess();

[DllImport("advapi32.dll", SetLastError=true)]
private extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);

[DllImport("advapi32.dll", SetLastError=true)]
private extern bool LookupPrivilegeValue(string lpSystemName, string lpName, ref LUID lpLuid);

[DllImport("advapi32.dll", SetLastError=true) ]
private extern bool AdjustTokenPrivileges(IntPtr TokenHandle, int DisableAllprivileges, [MarshalAs(UnmanagedType.Struct)]ref TOKEN_PRIVILEGES NewState, int BufferLength, IntPtr PreviousState, IntPtr ReturnLength);

[DllImport("user32.dll", SetLastError=true)]
private extern bool ExitWindowsEx(int uFlags, int dwReason);

// Costanti per AdjustTokenProvilege
private const int SE_PRIVILEGE_ENABLED = 0x00000002;
private const int TOKEN_QUERY = 0x00000008;
private const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;

// Costanti per ExitWindowsEx
private const int EWX_LOGOFF = 0x00000000;
private const int EWX_SHUTDOWN = 0x00000001;
private const int EWX_REBOOT = 0x00000002;
private const int EWX_FORCE = 0x00000004;
private const int EWX_POWEROFF = 0x00000008;
private const int EWX_FORCEIFHUNG = 0x00000010;

private void SetTokenPrivileges()
{
    TOKEN_PRIVILEGES newState = new TOKEN_PRIVILEGES();
    LUID luid = new LUID();

    LookupPrivilegeValue(null, "SeShutdownPrivilege", ref luid);
    IntPtr processHandle = GetCurrentProcess();
    IntPtr tokenHandle = IntPtr.Zero;
    OpenProcessToken(processHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref tokenHandle);
    newState.PrivilegeCount = 1;
    newState.Privileges = luid;
    newState.Attributes = SE_PRIVILEGE_ENABLED;
    AdjustTokenPrivileges(tokenHandle, 0, ref newState, Marshal.SizeOf(newState), IntPtr.Zero, IntPtr.Zero);
}

public void Reboot()
{
    SetTokenPrivileges();
    ExitWindowsEx(EWX_REBOOT, 0);
}

public void Shutdown()
{
    SetTokenPrivileges();
    ExitWindowsEx(EWX_SHUTDOWN, 0);
}

Come da documentazione, su sistemi NT/2000/XP/2003 è necessario dare al token che esegue lo shutdown/reboot l’attributo “SeShutdownPrivilege”. Questo compito è assegnato alla funzione SetTokenPrivileges().

“Wrappare” il tutto in una classe è un giochetto.

Lo posto qui, così, se serve a qualcuno…