Exiting Windows and Logging Off Programmatically
If you develop software that updates key Windows configuration settings, you may require that the system be restarted or that the users logs out and performs a new login process. Using Windows API functions, this can be controlled programmatically in C#.
ExitWindowsEx API Function
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.
The API call is used to terminate all of the current user's processes. When the user executing the function is the interactive user, this can also cause the system to automatically shut down or restart. When the command is called from a service that is running under a different user's credentials or within a Terminal Services session, the function can successfully stop all of the current processes without initiating a shutdown of the physical server. NB: In this situation if a shutdown is required the InitiateSystemShutdownEx API can be used instead.
Creating the Sample Program
In this article a sample program will be created that demonstrates how to programmatically power off or restart the system. This program will then be modified to show the other uses of the API function. To begin, create a new Windows application named "ShutdownSample". Add three buttons to the initial form and set the properties for the buttons as follows:
You may also want to change the Id of the form and the text that appears in its caption. The end result should look similar to the form shown below.
Referencing the ExitWindowsEx API Function
The .NET framework does not natively provide any means of shutting down the system. Instead, you must use a Windows API function for this task. The first thing that we need to do is to reference the InteropServices namespace so that we can access the Windows API functions. To do this, add a new using directive at the start of the code for the form.
Once the reference to the InteropServices namespace has been added, we can declare the API function as a static function. Ensure that the following declaration appears within the form's class code block but not within any method or property declaration.
[DllImport("user32.dll", SetLastError = true)]
static extern int ExitWindowsEx(uint uFlags, uint dwReason);
The ExitWindowsEx function requires two parameters to be specified. The first parameter, uFlags, determines the action that should be taken when the function is called. The integer value to use is determined by combining one or more flag values. To make the code easier to read, we will define a new enumeration containing the key values for our purposes.
Add the following enumeration code within the form's code block.
Logoff = 0,
Shutdown = 1,
Reboot = 2,
Force = 4,
PowerOff = 8,
ForceIfHung = 16
Shutdown Reason Codes
The second parameter of the ExitWindowsEx function is used to define the reason that the system was shut down. There are eight standard major reasons for Windows to be exited or restarted. These can each be modified using minor reason values. There are several tens of reason codes available that are described in Microsoft's System Shutdown Reason Codes MSDN article. For the simple demonstration of the codes, we will define just a few of the major reasons in a second enumeration.
enum Reason : uint
ApplicationIssue = 0x00040000,
HardwareIssue = 0x00010000,
SoftwareIssue = 0x00030000,
PlannedShutdown = 0x80000000
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. For this reason, the ability to shut down Windows is not provided as standard to .NET software. The privilege must be requested before the shut down command is available.
Elevating the program's privileges to include the required shut down rights uses a series of API calls. The following four functions are used:
- GetCurrentProcess. This function gets a handle that represents the current process. The handle is used to identify the process when elevating the privileges.
- OpenProcessToken. 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.
- LookupPrivilegeValue. 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.
- AdjustTokenPrivileges. 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.
17 December 2007