Question:
How do I reboot (with an option to force) inside of Win NT? I know about the ExitWindowsEx API call, which works fine in Windows 95, but unfortunately this does not work correctly in NT.
From my testing, the ExitWindowsEx API call will only do a log off (or forced log off) but not a full system shutdown and reboot.
Answer:
Actually, under NT, this is not such an easy question. You must first give yourself shutdown privileges, even though you have those same privileges as an interactive user?and that is what makes it more interesting.
The code below works just fine:
Option ExplicitDeclare Function ExitWindowsEx _ Lib "user32" _ (ByVal uFlags As Long, _ ByVal dwReserved As Long) As LongPrivate Const EWX_FORCE As Long = 4&Private Const EWX_LOGOFF As Long = 0&Private Const EWX_REBOOT As Long = 2&Private Const EWX_SHUTDOWN As Long = 1&Private Const ERROR_SUCCESS As Long = 0&Private Const ERROR_NOT_ALL_ASSIGNED As Long = 1300&Private Declare Function AdjustTokenPrivileges _ Lib "advapi32.dll" _ (ByVal TokenHandle As Long, _ ByVal DisableAllPrivileges As Long, _ NewState As TOKEN_PRIVILEGES, _ ByVal BufferLength As Long, _ PreviousState As TOKEN_PRIVILEGES, _ ReturnLength As Long) As LongPrivate Declare Function LookupPrivilegeValue _ Lib "advapi32.dll" Alias "LookupPrivilegeValueA" _ (ByVal lpSystemName As Any, _ ByVal lpName As String, _ lpLuid As LUID) As LongPrivate Declare Function OpenProcessToken _ Lib "advapi32.dll" _ (ByVal ProcessHandle As Long, _ ByVal DesiredAccess As Long, _ TokenHandle As Long) As LongPrivate Declare Function GetCurrentProcess _ Lib "kernel32" () As LongPrivate Const TOKEN_QUERY As Long = &H8&Private Const TOKEN_ADJUST_PRIVILEGES As Long = &H20&Private Const SE_PRIVILEGE_ENABLED As Long = &H2Private Type LUID lowpart As Long highpart As LongEnd TypePrivate Type LUID_AND_ATTRIBUTES pLuid As LUID Attributes As LongEnd TypePrivate Type TOKEN_PRIVILEGES PrivilegeCount As Long Privileges As LUID_AND_ATTRIBUTESEnd TypePublic Sub ShutDown(ByVal xi_blnForce As Boolean) Dim p_lngRtn As Long Dim p_lngFlags As Long Dim p_lngToken As Long Dim p_lngBufLen As Long Dim p_lngLastErr As Long Dim p_typLUID As LUID Dim p_typTokenPriv As TOKEN_PRIVILEGES Dim p_typPrevTokenPriv As TOKEN_PRIVILEGES p_lngRtn = OpenProcessToken(GetCurrentProcess(), _ TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, _ p_lngToken) If p_lngRtn = 0 Then ' Failed Debug.Print ReturnApiErrString(Err.LastDllError) Exit Sub End If p_lngRtn = LookupPrivilegeValue(0&, "SeShutdownPrivilege", p_typLUID) If p_lngRtn = 0 Then ' Failed Debug.Print ReturnApiErrString(Err.LastDllError) Exit Sub End If p_typTokenPriv.PrivilegeCount = 1 p_typTokenPriv.Privileges.Attributes = SE_PRIVILEGE_ENABLED p_typTokenPriv.Privileges.pLuid = p_typLUID p_lngRtn = AdjustTokenPrivileges(p_lngToken, False, _ p_typTokenPriv, Len(p_typPrevTokenPriv), _ p_typPrevTokenPriv, p_lngBufLen) If p_lngRtn = 0 Then ' Failed Debug.Print Err.LastDllError, ReturnApiErrString(Err.LastDllError) Exit Sub Else p_lngLastErr = Err.LastDllError If p_lngLastErr = ERROR_SUCCESS Then ' Everything is OK ElseIf p_lngLastErr = ERROR_NOT_ALL_ASSIGNED Then Debug.Print "Not all privileges assigned." Else Debug.Print p_lngLastErr, ReturnApiErrString(p_lngLastErr) End If End If If xi_blnForce = False Then p_lngFlags = EWX_REBOOT Else p_lngFlags = EWX_REBOOT And EWX_FORCE End If p_lngRtn = ExitWindowsEx(p_lngFlags, 0&) End Sub