ExitWindowsEx API doesn't work from inside a DLL

Hi experts,

My task was to create an ASP file that can restart Windows (on the server side ofcourse).
I wrote the code, but it doesn't restart. nothing happens.
To do that I wrote this piece of ASP code:

Set o = Server.CreateObject("ServerServices.Restart")
set o = nothing

and here is my DLL (ServerServices.Restart which is registered well and has the proper permissions on the server)

Option Explicit

Private Const TOKEN_ADJUST_PRIVILEGES As Long = &H20
Private Const TOKEN_QUERY As Long = &H8
Private Const SE_PRIVILEGE_ENABLED As Long = &H2

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

Private Const VER_PLATFORM_WIN32_NT As Long = 2

  OSVSize         As Long
  dwVerMajor      As Long
  dwVerMinor      As Long
  dwBuildNumber   As Long
  PlatformID      As Long
  szCSDVersion    As String * 128
End Type

Private Type LUID
   dwLowPart As Long
   dwHighPart As Long
End Type

   udtLUID As LUID
   dwAttributes As Long
End Type

   PrivilegeCount As Long
End Type
Private Declare Function ExitWindowsEx Lib "user32" (ByVal dwOptions As Long, ByVal dwReserved As Long) As Long
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Declare Function OpenProcessToken Lib "advapi32" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
Private Declare Function LookupPrivilegeValue Lib "advapi32" Alias "LookupPrivilegeValueA" (ByVal lpSystemName As String, ByVal lpName As String, lpLuid As LUID) As Long
Private Declare Function AdjustTokenPrivileges Lib "advapi32" (ByVal TokenHandle As Long, ByVal DisableAllPrivileges As Long, NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Long, PreviousState As Any, ReturnLength As Long) As Long
Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As Long
Public Sub RestartWindows()
   Dim success As Long
   If IsWinNTPlus() Then
      success = EnableShutdownPrivledges()
      If success Then ExitWindowsEx(EWX_REBOOT, 0&)
      RestartWindows = ExitWindowsEx(EWX_REBOOT, 0&)
   End If
End Sub

Private Function IsWinNTPlus() As Boolean
   #If Win32 Then
      OSV.OSVSize = Len(OSV)
      If GetVersionEx(OSV) = 1 Then
         IsWinNTPlus = (OSV.PlatformID = VER_PLATFORM_WIN32_NT) And (OSV.dwVerMajor >= 4)
      End If
   #End If
End Function

Private Function EnableShutdownPrivledges() As Boolean

   Dim hProcessHandle As Long
   Dim hTokenHandle As Long
   Dim lpv_la As LUID
   hProcessHandle = GetCurrentProcess()
   If hProcessHandle <> 0 Then  
      If OpenProcessToken(hProcessHandle, (TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY), hTokenHandle) <> 0 Then
         If LookupPrivilegeValue(vbNullString, "SeShutdownPrivilege", lpv_la) <> 0 Then
            With token
               .PrivilegeCount = 1
               .laa.udtLUID = lpv_la
               .laa.dwAttributes = SE_PRIVILEGE_ENABLED
            End With
            If AdjustTokenPrivileges(hTokenHandle, False, token, ByVal 0&, ByVal 0&, ByVal 0&) <> 0 Then
               EnableShutdownPrivledges = True
            End If
         End If
      End If
   End If

End Function


I know for sure that the DLL works fine. however, when called by ASP from within a DLL - the ExitWindowsEX API returns '1' (Can't quit)....


Who is Participating?
grayeConnect With a Mentor Commented:
I assume you've adjusted the impersonation of that section of the web page to take on the rights of the logged on user (who would have to be an administrator)?

Just a note... The security associated with the IIS accounts are specifically desgined to reduce the risk of an intrusion and therefore have the "least privileges" required to function.  That means they probably don't have the appropriate authority/permissions to perform a shutdown.

Ugi_FletzetAuthor Commented:
As an intra-net application, I've adjusted the impersonation of that section of the web page to take on the rights of the server administrator which has full rights and not IUSR_xxx (IIS default user, xxx is the computer name) which has very few rights...

Does anyone ever try to do it / heard of someone who did it / know that there is a way to do it / know of an example / what ever...

It looks like a simple & essential task - the aility to restart your server with ASP code called a DLL (ActiveX control)

I don't have an answer, but I've got a suggestion!

You could try using Windows Management Instrumentation (WMI) instead of the APIs to reboot the server.  Here is a sample:

' Add Reference to System.Management
Imports System.Management

' Use WMI's Win32Shutdown class to remotely logoff the user, reboot the PC, or
' shutdown the PC.
Public Class Actions

    Public Enum ActionTypes As Integer
        Logoff = 0
        Reboot = 4
        Shutdown = 8
    End Enum

    Public Sub DoAction(ByVal PC_Name As String, ByVal Flag As Integer, ByVal forced As Boolean)
        Dim wmi As ManagementClass
        Dim inParams, outParams As ManagementBaseObject
        Dim obj As ManagementObject
        Dim ans As Boolean
        Dim Result As Integer

        ' force the action regardless of any activity on the remote PC
        If forced = True Then
            Flag += 4
        End If
        ans = True

        wmi = New ManagementClass("\\" & PC_Name & "\root\cimv2:Win32_OperatingSystem")
        For Each obj In wmi.GetInstances()

            ' Get an input parameters object for this method
            inParams = obj.GetMethodParameters("Win32Shutdown")

            ' fill 'em in
            inParams("Flags") = Flag
            inParams("Reserved") = 0

            ' do it!
            outParams = obj.InvokeMethod("Win32Shutdown", inParams, Nothing)
            Result = Convert.ToInt32(outParams("returnValue"))
            If Result <> 0 Then
                Throw New System.ComponentModel.Win32Exception(Result)
            End If
    End Sub
End Class
Ugi_FletzetAuthor Commented:
Thank you Graye, I'll try that and return to you later (It might taks some time...)
Ugi_FletzetAuthor Commented:
Sorry for the delay, as I said - it might taks some time.

I tried the WMI way, but it still doesn't work. My guess - it's a special Windows protection, and the answer to my question should be: You're unable to accomplish the task under ASP....
Anyway - I'm giving graye the points, as he was the only one to help...

If someone will ever heard of a way to restart Windows with ASP, or if someone will come across a sample or just even a rumor of someone that did it - I'll appriciate any help.,,

Venabili - You can remove your comment.
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.