Why Simply Calling ExitWindowsEx won’t Shutdown or Restart Windows XP, Vista, 7, and Newer

Click Star to Rate Post
1 Star2 Stars3 Stars4 Stars5 Stars (2 votes, average: 5.00 out of 5)
 

Simply executing the ExitWindowsEx API function works fine using older versions of Windows like Windows 98 or ME. You only needed to call the ExitWindowsEx with the desired parameters and it was good to go. But with the regular consumer family of Windows starting with Windows XP, Microsoft based the OS on NT/2000 which is a very different Kernel and Architecture. That includes Windows Vista, Windows 7, 8/8.1, and 10 as well. Your programs are now required to have ‘special privileges’ before it will grant your application’s request to shutdown/restart/logoff the device. Visual C++ has these Privileges by default, but not any of the VBs unfortunately. So the first step you must do is request your application be granted the required privileges. The source code below was originally in VB 6.0 code from Microsoft that I converted to Visual Basic .NET. The code here will work with all versions of .NET including 2005, 2008, plus Visual Basic 2010, and newer. There are only minor changes needed to make it work with Visual Basic 6.0, mainly the variable/parameter types like changing the Integers to Long types. I went ahead and put the VB.NET source code in this post.

Note: If you are wanting to get the original VB 6.0 privilege codes then click on this link and/or click this link as well.

Need to first get some structures for the APIs.

    Private Structure LUID

        Dim UsedPart As Integer

        Dim IgnoredForNowHigh32BitPart As Integer

    End Structure

    Private Structure TOKEN_PRIVILEGES

        Dim PrivilegeCount As Integer

        Dim TheLuid As LUID

        Dim Attributes As Integer

    End Structure

Next you can go ahead and add the needed API methods to execute the privilege requests.

    '
    'The API functions below are all used to give the application the proper privilege so the OS will allow the app to Shutdown Windows.
    '
    Private Declare Function OpenProcessToken Lib "advapi32" (ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef TokenHandle As Integer) As Integer

    Private Declare Function LookupPrivilegeValue Lib "advapi32" Alias "LookupPrivilegeValueA" (ByVal lpSystemName As String, ByVal lpName As String, ByRef lpLuid As LUID) As Integer

    Private Declare Function AdjustTokenPrivileges Lib "advapi32" (ByVal TokenHandle As Integer, ByVal DisableAllPrivileges As Boolean, ByRef NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Integer, ByRef PreviousState As TOKEN_PRIVILEGES, ByRef ReturnLength As Integer) As Integer

Now to setup and create a Sub that will do all the work to set your privileges.

    '
    'This sub will do all of the work of setting up your apps process using the APIs posted above to get the
    'proper privileges to shutdown the OS.
    'I originally got this function from msdn and converted it from VB 6.0 to VB.Net and did a tweak here and there.
    '
    Private Sub AdjustToken()

        Const TOKEN_ADJUST_PRIVILEGES As Int32 = &H20

        Const TOKEN_QUERY As Int32 = &H8

        Const SE_PRIVILEGE_ENABLED As Int32 = &H2

        Dim hdlProcessHandle As IntPtr

        Dim hdlTokenHandle As Int32

        Dim tmpLuid As LUID

        Dim tkp As TOKEN_PRIVILEGES

        Dim tkpNewButIgnored As TOKEN_PRIVILEGES

        Dim lBufferNeeded As Int32

        hdlProcessHandle = Process.GetCurrentProcess.Handle

        OpenProcessToken(hdlProcessHandle, (TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY), hdlTokenHandle)

        'Get the LUID for shutdown privilege.
        LookupPrivilegeValue("", "SeShutdownPrivilege", tmpLuid)

        tkp.PrivilegeCount = 1 'One privilege to set

        tkp.TheLuid = tmpLuid

        tkp.Attributes = SE_PRIVILEGE_ENABLED

        'Enable the shutdown privilege in the access token of this process.
        AdjustTokenPrivileges(hdlTokenHandle, False, tkp, Len(tkpNewButIgnored), tkpNewButIgnored, lBufferNeeded)

    End Sub

Now that the main Privilege codes are done, you just need one more API Function.

Below is the API call you execute to perform the actual shutdown/restart/logoff command on the computer.

    'The function used to actually send the request to shutdown windows. Set the ‘shutdownTypes’ parameter to whether you want windows to “shutdown, reboot, logOff, ect…” You can get those at MSDN or download one of my examples from my VBCodesource.com website.
    Private Declare Function ExitWindowsEx Lib "user32" (ByVal shutdownType As Integer, ByVal dwReserved As Integer) As Integer

Edit: As per Garry’s comment below, I included some relevant flags you can use with the ExitWindowsEx function.

        Private Const EWX_LOGOFF As Integer = &H0
        Private Const EWX_SHUTDOWN As Integer = &H1
        Private Const EWX_REBOOT As Integer = &H2
        Private Const EWX_FORCE As Integer = &H4
        Private Const EWX_POWEROFF As Integer = &H8
        Private Const EWX_FORCEIFHUNG As Integer = &H10 '2000/XP only

OK, now you first need to call the AdjustToken()  Sub and then the ExitWindowsEx Function. This example code will Log Off the user.

        AdjustToken()

        'Calls the function to begin executing.
        ExitWindowsEx(EWX_LOGOFF, Nothing)

That’s all there is to it! OK, it Is a lot of code to get the ExitWindowsEx API to work with Windows 2000/XP/Vista/7/8/8.1/10.0. To bad Microsoft doesn’t give Visual Basic these Privileges by default like they do with C++. Oh well, don’t have much of a choice.

Remember, its possible to get these codes to work with Visual Basic 6.0 as well. You need to change the types (Especially Integers to Longs, and Structures to Types) plus process info then it should be ok. Or click on this link to the original code

I have pre-made Class Libraries and Examples for Visual Basic.NET, VB 2005/2008/2010/2012, and Visual Basic 2013. I also have an Example of doing this in Visual Basic 6.0 at my Visual Basic Code Source website.

Well that’s all for now. Have Fun!

Jason

Revisited: 2015

4 thoughts on “Why Simply Calling ExitWindowsEx won’t Shutdown or Restart Windows XP, Vista, 7, and Newer

  1. garry b

    thanks the codes needed are
    Private Const EWX_LOGOFF As Integer = &H0
    Private Const EWX_SHUTDOWN As Integer = &H1
    Private Const EWX_REBOOT As Integer = &H2
    Private Const EWX_FORCE As Integer = &H4
    Private Const EWX_POWEROFF As Integer = &H8
    Private Const EWX_FORCEIFHUNG As Integer = &H10 ‘2000/XP only

    Reply

Leave a Reply

Your email address will not be published.