Link to home
Start Free TrialLog in
Avatar of Ugi_Fletzet
Ugi_FletzetFlag for Israel

asked on

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")
o.RestartWindows
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

Private Type OSVERSIONINFO
  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

Private Type LUID_AND_ATTRIBUTES
   udtLUID As LUID
   dwAttributes As Long
End Type

Private Type TOKEN_PRIVILEGES
   PrivilegeCount As Long
   laa As LUID_AND_ATTRIBUTES
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&)
   Else
      RestartWindows = ExitWindowsEx(EWX_REBOOT, 0&)
   End If
End Sub
 

Private Function IsWinNTPlus() As Boolean
   #If Win32 Then
      Dim OSV As OSVERSIONINFO
      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
   Dim token As TOKEN_PRIVILEGES
   
   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)....




---------------------------------------------------------------------------------------------


ASKER CERTIFIED SOLUTION
Avatar of graye
graye
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Ugi_Fletzet

ASKER

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)
Hummm...

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
        Next
    End Sub
End Class
Thank you Graye, I'll try that and return to you later (It might taks some time...)
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.