using System.Runtime.InteropServices;
// The ExitWindowsEx application programming interface (API)
// function allows a message to be sent to all executing processes for the current user,
// requesting that they terminate to allow the computer to be shut down,
// restarted or in preparation for the current user to be logged off.
// The function is available in Windows 2000 and later operating systems.
[DllImport("user32.dll", SetLastError = true)]
static extern int ExitWindowsEx(uint uFlags, uint dwReason);
enum ExitFlags
{
Logoff = 0,
Shutdown = 1,
Reboot = 2,
Force = 4,
PowerOff = 8,
ForceIfHung = 16
}
enum Reason : uint
{
ApplicationIssue = 0x00040000,
HardwareIssue = 0x00010000,
SoftwareIssue = 0x00030000,
PlannedShutdown = 0x80000000
}
// Elevating Privileges
// All programs execute with a set of privileges that enable and disable Windows functionality.
// For security purposes, the privileges provided to a program should be the minimum necessary to ensure correct execution.
const int PrivilegeEnabled = 0x00000002;
const int TokenQuery = 0x00000008;
const int AdjustPrivileges = 0x00000020;
const string ShutdownPrivilege = "SeShutdownPrivilege";
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokenPrivileges
{
public int PrivilegeCount;
public long Luid;
public int Attributes;
}
// This function gets a handle that represents the current process.
// The handle is used to identify the process when elevating the privileges.
[DllImport("kernel32.dll")]
internal static extern IntPtr GetCurrentProcess();
// This function retrieves the access token for a process.
// When used with the current process handle,
// the access token holds the privilege information for the executing program.
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern int OpenProcessToken(
IntPtr processHandle,
int desiredAccess,
ref IntPtr tokenHandle);
// This function is used to perform a lookup of the locally unique identifier (LUID) for a named privilege.
// This allows the LUID for the shutdown privilege to be found in readiness for elevating the privileges of the process.
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern int LookupPrivilegeValue(
string systemName, string name, ref long luid);
// Once the process handle, access token and privilege LUID are identified,
// this function is used to change the program's privileges and assign the shut down rights.
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern int AdjustTokenPrivileges(
IntPtr tokenHandle, bool disableAllPrivileges,
ref TokenPrivileges newState,
int bufferLength,
IntPtr previousState,
IntPtr length);
// This method uses the four API functions in turn to identify the current process,
// retrieve the current privileges, identify the shutdown privilege and grant it to the user.
private void ElevatePrivileges()
{
IntPtr currentProcess = GetCurrentProcess();
IntPtr tokenHandle = IntPtr.Zero;
int result = OpenProcessToken(
currentProcess,
AdjustPrivileges | TokenQuery,
ref tokenHandle);
if (result == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
TokenPrivileges tokenPrivileges;
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Luid = 0;
tokenPrivileges.Attributes = PrivilegeEnabled;
result = LookupPrivilegeValue(
null,
ShutdownPrivilege,
ref tokenPrivileges.Luid);
if (result == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
result = AdjustTokenPrivileges(
tokenHandle,
false,
ref tokenPrivileges,
0, IntPtr.Zero,
IntPtr.Zero);
if (result == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
private void Shutdown(bool Force)
{
ElevatePrivileges();
int result = 0;
if (Force)
{
// Forcing a Shutdown
result = ExitWindowsEx(
(uint)(ExitFlags.Shutdown | ExitFlags.PowerOff | ExitFlags.Force),
(uint)(Reason.HardwareIssue | Reason.PlannedShutdown));
}
else
{
result = ExitWindowsEx(
(uint)(ExitFlags.Shutdown | ExitFlags.PowerOff),
(uint)(Reason.HardwareIssue | Reason.PlannedShutdown));
}
if (result == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
private void Restart()
{
ElevatePrivileges();
int result = ExitWindowsEx(
(uint)(ExitFlags.Reboot),
(uint)(Reason.SoftwareIssue | Reason.PlannedShutdown));
if (result == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
private void Logoff()
{
ElevatePrivileges();
int result = ExitWindowsEx(
(uint)(ExitFlags.Logoff),
(uint)(Reason.ApplicationIssue | Reason.PlannedShutdown));
if (result == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
}