CSharp Windows

ExitWindowsEx in C#

Blog post featured image

Here’s a straightforward class I’ve created for shutting down, rebooting, and logging off Windows using the ExitWindowsEx function. Each method in this class is overloaded with a variant that forces the action. This means it doesn’t allow Windows to send the WM_QUERYENDSESSION message, preventing the user from canceling the action.

Here’s the complete code for the class:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

static class ExitWindows {

  private struct LUID {
    public int LowPart;
    public int HighPart;
  }
  private struct LUID_AND_ATTRIBUTES {
    public LUID pLuid;
    public int Attributes;
  }
  private struct TOKEN_PRIVILEGES {
    public int PrivilegeCount;
    public LUID_AND_ATTRIBUTES Privileges;
  }

  [DllImport("advapi32.dll")]
  static extern int OpenProcessToken(IntPtr ProcessHandle,
    int DesiredAccess, out IntPtr TokenHandle);

  [DllImport("advapi32.dll", SetLastError = true)]
  [return: MarshalAs(UnmanagedType.Bool)]
  static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
    [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
    ref TOKEN_PRIVILEGES NewState,
    UInt32 BufferLength,
    IntPtr PreviousState,
    IntPtr ReturnLength);

  [DllImport("advapi32.dll")]
  static extern int LookupPrivilegeValue(string lpSystemName,
    string lpName, out LUID lpLuid);

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

  const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
  const short SE_PRIVILEGE_ENABLED = 2;
  const short TOKEN_ADJUST_PRIVILEGES = 32;
  const short TOKEN_QUERY = 8;

  const ushort EWX_LOGOFF = 0;
  const ushort EWX_POWEROFF = 0x00000008;
  const ushort EWX_REBOOT = 0x00000002;
  const ushort EWX_RESTARTAPPS = 0x00000040;
  const ushort EWX_SHUTDOWN = 0x00000001;
  const ushort EWX_FORCE = 0x00000004;

  private static void getPrivileges() {
    IntPtr hToken;
    TOKEN_PRIVILEGES tkp;

    OpenProcessToken(Process.GetCurrentProcess().Handle,
      TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken);
    tkp.PrivilegeCount = 1;
    tkp.Privileges.Attributes = SE_PRIVILEGE_ENABLED;
    LookupPrivilegeValue("", SE_SHUTDOWN_NAME,
      out tkp.Privileges.pLuid);
    AdjustTokenPrivileges(hToken, false, ref tkp,
      0U, IntPtr.Zero, IntPtr.Zero);
  }

  public static void Shutdown() { Shutdown(false); }
  public static void Shutdown(bool force) {
    getPrivileges();
    ExitWindowsEx(EWX_SHUTDOWN |
      (uint)(force? EWX_FORCE : 0) | EWX_POWEROFF, 0);
  }

  public static void Reboot() { Reboot(false); }
  public static void Reboot(bool force) {
    getPrivileges();
    ExitWindowsEx(EWX_REBOOT |
      (uint)(force ? EWX_FORCE : 0), 0);
  }

  public static void LogOff() { LogOff(false); }
  public static void LogOff(bool force) {
    getPrivileges();
    ExitWindowsEx(EWX_LOGOFF |
      (uint)(force ? EWX_FORCE : 0), 0);
  }
}

I hope you find this class helpful for managing system power states in your C# applications!