Attribute VB_Name = "ShtDwnAndChgResolution"
Option Explicit
Private bWindowsNT As Boolean
Private Declare Function LockWorkStation Lib "user32.dll" () As Long

'
' Operating System Constants, Types and Declares
'
Const VER_PLATFORM_WIN32s = 0
Const VER_PLATFORM_WIN32_WINDOWS = 1
Const VER_PLATFORM_WIN32_NT = 2

Public Declare Function Beep Lib "kernel32" (ByVal dwFreq As Long, ByVal dwDuration As Long) As Long

Type OSVERSIONINFO
    dwOSVersionInfoSize As Long
    dwMajorVersion      As Long
    dwMinorVersion      As Long
    dwBuildNumber       As Long
    dwPlatformId        As Long
    szCSDVersion        As String * 128
End Type

Public Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As Long
'
' Shutdown/change resolution Constants, Types and Declares
'
'Public Const EWX_LOGOFF = 0
'Public Const EWX_SHUTDOWN = 1
'Public Const EWX_REBOOT = 2
Public Const EWX_LOGOFF As Long = &H0
Public Const EWX_SHUTDOWN As Long = &H1
Public Const EWX_REBOOT As Long = &H2
Public Const EWX_FORCE As Long = &H4
Public Const EWX_POWEROFF As Long = &H8
Public Const EWX_FORCEIFHUNG As Long = &H10 '2000/XP only
'
' Using this option to shutdown windows does not send
' the WM_QUERYENDSESSION and WM_ENDSESSION messages to
' the open applications. Thus, those apps may loose
' any unsaved data.
'
'Const EWX_FORCE = 4
Const CCDEVICENAME = 32
Const CCFORMNAME = 32
Const DM_BITSPERPEL = &H40000
Const DM_PELSWIDTH = &H80000
Const DM_PELSHEIGHT = &H100000
Const CDS_UPDATEREGISTRY = &H1
Const CDS_TEST = &H2
Const CDS_FULLSCREEN = &H4
Const DISP_CHANGE_SUCCESSFUL = 0
Const DISP_CHANGE_RESTART = 1
 
Const HWND_BROADCAST = &HFFFF&
Const WM_DISPLAYCHANGE = &H7E&
Const SPI_SETNONCLIENTMETRICS = 42

Type DEVMODE
    dmDeviceName       As String * CCDEVICENAME
    dmSpecVersion      As Integer
    dmDriverVersion    As Integer
    dmSize             As Integer
    dmDriverExtra      As Integer
    dmFields           As Long
    dmOrientation      As Integer
    dmPaperSize        As Integer
    dmPaperLength      As Integer
    dmPaperWidth       As Integer
    dmScale            As Integer
    dmCopies           As Integer
    dmDefaultSource    As Integer
    dmPrintQuality     As Integer
    dmColor            As Integer
    dmDuplex           As Integer
    dmYResolution      As Integer
    dmTTOption         As Integer
    dmCollate          As Integer
    dmFormName         As String * CCFORMNAME
    dmUnusedPadding    As Integer
    dmBitsPerPel       As Integer
    dmPelsWidth        As Long
    dmPelsHeight       As Long
    dmDisplayFlags     As Long
    dmDisplayFrequency As Long
End Type

Public Declare Function EnumDisplaySettings Lib "user32" Alias "EnumDisplaySettingsA" (ByVal lpszDeviceName As Long, ByVal iModeNum As Long, lpDevMode As Any) As Boolean
Public Declare Function ChangeDisplaySettings Lib "user32" Alias "ChangeDisplaySettingsA" (lpDevMode As Any, ByVal dwFlags As Long) As Long
Public Declare Function ExitWindowsEx Lib "user32" (ByVal uFlags As Long, ByVal dwReserved As Long) As Long
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
'
' The following are required to shutdown NT.
'
Const ERROR_NOT_ALL_ASSIGNED = 1300
Const SE_PRIVILEGE_ENABLED = 2
Const TOKEN_QUERY = &H8
Const TOKEN_ADJUST_PRIVILEGES = &H20

Type LUID
    lowpart As Long
    highpart As Long
End Type

Type LUID_AND_ATTRIBUTES
    pLuid As LUID
    Attributes As Long
End Type

Type TOKEN_PRIVILEGES
    PrivilegeCount As Long
    Privileges As LUID_AND_ATTRIBUTES
End Type

Public Declare Function AdjustTokenPrivileges Lib "advapi32.dll" (ByVal TokenHandle As Long, ByVal DisableAllPriv As Long, NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Long, PreviousState As TOKEN_PRIVILEGES, ReturnLength As Long) As Long
Public Declare Function LookupPrivilegeValue Lib "advapi32.dll" Alias "LookupPrivilegeValueA" (ByVal lpSystemName As Any, ByVal lpName As String, lpUid As LUID) As Long
Public Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
Public Declare Function GetCurrentProcess Lib "kernel32" () As Long
Public Declare Function SetSystemPowerState Lib "kernel32" (ByVal fSuspend As Long, ByVal fForce As Long) As Long

Public Enum MONIERACTION
    MA_KILLPROCESS = 0
    MA_SHUTDOWNCOMPUTER = 1
    MA_RESTARTCOMPUTER = 2
    MA_LOGOFF = 3
    MA_STANDBY = 4
    MA_LOGONSCREEN = 5
    MA_SUSPENDPROCESS = 6
End Enum

Public Function IsWindowsNTPlus() As Boolean
    Dim OSInfo As OSVERSIONINFO
    ' See if we are running Windows 9x or NT.
    OSInfo.dwOSVersionInfoSize = Len(OSInfo)
    Call GetVersionEx(OSInfo)
    IsWindowsNTPlus = (OSInfo.dwPlatformId = VER_PLATFORM_WIN32_NT)
End Function


Public Sub GetOsVersion()
    Dim OSInfo As OSVERSIONINFO
    OSInfo.dwOSVersionInfoSize = Len(OSInfo)
    Call GetVersionEx(OSInfo)
    bWindowsNT = (OSInfo.dwPlatformId = VER_PLATFORM_WIN32_NT)
End Sub

Public Sub ShutDownPc(ByVal NOption As MONIERACTION)
    Dim tLuid          As LUID
    Dim tTokenPriv     As TOKEN_PRIVILEGES
    Dim tPrevTokenPriv As TOKEN_PRIVILEGES
    Dim lResult        As Long
    Dim lToken         As Long
    Dim lLenBuffer     As Long
    Dim lMode As Long
    '
    ' Determine the shutdown mode.
    '
    ' EWX_LOGOFF
    '   Shuts down all processes running and
    '   logs off the user.
    '
    ' EWX_REBOOT
    '   Shuts down and restarts the system.
    '
    ' EWX_SHUTDOWN
    '   Shuts down the system to a point where
    '   it is safe to turn off the system.
    '
    ' EWX_POWEROFF
    '   Shuts down the system and turns off power.
    '   The system must support this feature.
    '
    ' EWX_FORCE
    '   Forcibly shuts down the system. Files are not closed,...
    '   data may be lost.
    '
    Select Case NOption
        Case MA_LOGOFF
            lMode = EWX_LOGOFF
        Case MA_RESTARTCOMPUTER
            lMode = EWX_REBOOT
        Case MA_SHUTDOWNCOMPUTER
            lMode = EWX_POWEROFF
    End Select
    
    If NOption = MA_STANDBY Then
        SetSystemPowerState False, True
        Exit Sub
    ElseIf NOption = MA_LOGONSCREEN Then
        ChangeUserSystem
        Exit Sub
    End If
    
    bWindowsNT = IsWindowsNTPlus
    If Not bWindowsNT Then
        Call ExitWindowsEx(EWX_FORCE + lMode, 0&)
    ElseIf NOption = MA_LOGOFF Or MA_RESTARTCOMPUTER Or MA_SHUTDOWNCOMPUTER Then
        '
        ' Get the access token of the current process.  Get it
        ' with the privileges of querying the access token and
        ' adjusting its privileges.
        '
        lResult = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, lToken)
        If lResult = 0 Then
            Exit Sub 'Failed
        End If
        '
        ' Get the locally unique identifier (LUID) which
        ' represents the shutdown privilege.
        '
        lResult = LookupPrivilegeValue(0&, "SeShutdownPrivilege", tLuid)
        If lResult = 0 Then Exit Sub 'Failed
        '
        ' Populate the new TOKEN_PRIVILEGES values with the LUID
        ' and allow your current process to shutdown the computer.
        '
        With tTokenPriv
            .PrivilegeCount = 1
            .Privileges.Attributes = SE_PRIVILEGE_ENABLED
            .Privileges.pLuid = tLuid
        lResult = AdjustTokenPrivileges(lToken, False, tTokenPriv, Len(tPrevTokenPriv), tPrevTokenPriv, lLenBuffer)
        End With
        
        If lResult = 0 Then
            Exit Sub 'Failed
        Else
            If Err.LastDllError = ERROR_NOT_ALL_ASSIGNED Then Exit Sub 'Failed
        End If
        '
        '  Shutdown Windows.
        '
        Call ExitWindowsEx(EWX_FORCE + lMode, 0&)
        Exit Sub
    End If
    
End Sub

Public Function ChangeResolutionPc(ByVal nWidth As Single, ByVal nHeight As Single, Optional ByVal NBits As Byte)
    Dim DevM    As DEVMODE
    Dim lResult As Long
    Dim iAns    As Integer
    '
    ' Retrieve info about the current graphics mode
    ' on the current display device.
    '
    lResult = EnumDisplaySettings(0, 0, DevM)
    '
    ' Set the new resolution. Don't change the color
    ' depth so a restart is not necessary.
    '
    With DevM
        .dmFields = DM_PELSWIDTH Or DM_PELSHEIGHT 'Or DM_BITSPERPEL
        .dmPelsWidth = nWidth 'ScreenWidth
        .dmPelsHeight = nHeight  'ScreenHeight
        If IsMissing(NBits) = True Then
        Else
            .dmBitsPerPel = NBits '(could be 8, 16, 32 or even 4)
        End If
    End With
    '
    ' Change the display settings to the specified graphics mode.
    '
    lResult = ChangeDisplaySettings(DevM, CDS_FULLSCREEN)
    Select Case lResult
        Case DISP_CHANGE_RESTART
            iAns = MsgBox("You must restart your computer to apply these changes." & _
                vbCrLf & vbCrLf & "Do you want to restart now?", _
                vbYesNo + vbSystemModal, "Screen Resolution")
            If iAns = vbYes Then Call ExitWindowsEx(EWX_REBOOT, 0)
        Case DISP_CHANGE_SUCCESSFUL
            Call ChangeDisplaySettings(DevM, CDS_UPDATEREGISTRY)
            Call SendMessage(HWND_BROADCAST, WM_DISPLAYCHANGE, SPI_SETNONCLIENTMETRICS, ByVal 0&)
        Case Else
            GiveMessage "Mode non supporté", M_Ok, 0
    End Select
    
    '
    ' NOTE:
    ' By changing CDS_FULLSCREEN to CDS_TEST, you no longer need:
    ' Call SendMessage(HWND_BROADCAST, WM_DISPLAYCHANGE, SPI_SETNONCLIENTMETRICS, ByVal 0&)
    '
    'lResult = ChangeDisplaySettings(DevM, CDS_TEST)
    'Select Case lResult
    '    Case DISP_CHANGE_RESTART
    '        iAns = MsgBox("You must restart your computer to apply these changes." & _
    '            vbCrLf & vbCrLf & "Do you want to restart now?", _
    '            vbYesNo + vbSystemModal, "Screen Resolution")
    '        If iAns = vbYes Then Call ExitWindowsEx(EWX_REBOOT, 0)
    '    Case DISP_CHANGE_SUCCESSFUL
    '        Call ChangeDisplaySettings(DevM, CDS_UPDATEREGISTRY)
    '        MsgBox "Screen resolution changed", vbInformation, "Resolution Changed"
    '    Case Else
    '        MsgBox "Mode not supported", vbSystemModal, "Error"
    'End Select

End Function

Public Sub BeepNow(Optional ByVal Parameter_X As Long)
    If Parameter_X <= 10 And Parameter_X >= 2 Then
        Beep 2000, 200
    ElseIf Parameter_X <= 2 Then
        Beep 2000, 600
    End If
End Sub

Public Sub ChangeUserSystem()
    Call LockWorkStation
End Sub
