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.
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!