Автор вопроса: Vit | Web-сайт:www.home-soft.jino-net.ru
Почему не работает функция ExitWindowsEx?
Код программы:
Public Function IsWinNT() As Boolean
Dim myOS As OSVERSIONINFO
myOS.dwOSVersionInfoSize = Len(myOS)
GetVersionEx myOS
IsWinNT = (myOS.dwPlatformId = VER_PLATFORM_WIN32_NT)
End Function
'set the shut down privilege for the current application
Private Sub EnableShutDown()
Dim hProc As Long
Dim hToken As Long
Dim mLUID As LUID
Dim mPriv As TOKEN_PRIVILEGES
Dim mNewPriv As TOKEN_PRIVILEGES
hProc = GetCurrentProcess()
OpenProcessToken hProc, TOKEN_ADJUST_PRIVILEGES + TOKEN_QUERY, hToken
LookupPrivilegeValue "", "SeShutdownPrivilege", mLUID
mPriv.PrivilegeCount = 1
mPriv.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED
mPriv.Privileges(0).pLuid = mLUID
' enable shutdown privilege for the current application
AdjustTokenPrivileges hToken, False, mPriv, 4 + (12 * mPriv.PrivilegeCount), mNewPriv, 4 + (12 * mNewPriv.PrivilegeCount)
End Sub
' Shut Down NT
Public Sub ShutDownNT(Force As Boolean)
Dim Flags As Long
Flags = EWX_SHUTDOWN
If Force Then Flags = Flags + EWX_FORCE
If IsWinNT Then EnableShutDown
ExitWindowsEx Flags, 0
End Sub
Для NT платформ необходимо получить привилегии для управления питанием (Shutdown, Reboot, Logoff) - EnableShutDown.
Когда срабатывает событие в программе, то комп действует одним из следующих методов:
- никак не реагирует
- завершает работу Windows, но показывает сообщение "Теперь питание компьютера можно отключить".
Раньше такого не замечал. Машина работает по Win2000. Тестировал под Win98 и WinXP - работает нормально. Что за глюки?
Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As Long
Private Declare Function ExitWindowsEx Lib "user32" (ByVal uFlags As Long, ByVal dwReserved As Long) As Long
Private Declare Function GetCurrentProcess Lib "kernel32" () 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 TOKEN_PRIVILEGES, ReturnLength As Long) As Long
Private Declare Function SetSystemPowerState Lib "kernel32" (ByVal fSuspend As Long, ByVal fForce As Long) As Long
Private Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
Private Const EWX_LOGOFF = &H0& ' завершение сеанса пользователя
Private Const EWX_SHUTDOWN = &H1& ' шатдаун компьютера
Private Const EWX_REBOOT = &H2& ' перезагрузка компьютера
Private Const EWX_POWEROFF = &H8& ' выключение компьютера (ATX)
Private Const EWX_FORCE = &H4& ' флаг принудительного выполнения операции
Private Const EWX_FORCEIFHUNG = &H10& ' флаг принудительного выполнения при зависании
Private Type LUID
UsedPart As Long: IgnoredForNowHigh32BitPart As Long
End Type
Private Type LUID_AND_ATTRIBUTES
TheLuid As LUID: Attributes As Long
End Type
Private Type TOKEN_PRIVILEGES
PrivilegeCount As Long: TheLuid As LUID: Attributes As Long
End Type
Private Type OSVERSIONINFO
dwOSVersionInfoSize As Long: dwMajorVersion As Long: dwMinorVersion As Long
dwBuildNumber As Long: dwPlatformId As Long: szCSDVersion As String * 128
End Type
Public Function OsVersion(Back As Integer) As String
Dim info As OSVERSIONINFO
info.dwOSVersionInfoSize = Len(info)
GetVersionEx info
If Back = 0 Then OsVersion = CInt(info.dwPlatformId)
If Back = 1 Then
Select Case info.dwPlatformId
Case 0
OsVersion = ""
Case 1
OsVersion = "Windows 9x" & " v" & info.dwMajorVersion & "."
OsVersion = OsVersion & info.dwMinorVersion & " Build "
OsVersion = OsVersion & info.dwBuildNumber
Case 2
OsVersion = "Windows NT" & " v" & info.dwMajorVersion & "."
OsVersion = OsVersion & info.dwMinorVersion & " Build "
OsVersion = OsVersion & info.dwBuildNumber
End Select
End If
If Back = 3 Then OsVersion = info.dwMajorVersion
Back = 0
End Function
Public Function Shutdown() As Boolean
Select Case OsVersion(False)
Case Is = VER_PLATFORM_WIN32s
Shutdown = False
Case Is = VER_PLATFORM_WIN32_WINDOWS
ExitWindowsEx EWX_SHUTDOWN, 0&
Shutdown = True
Case Is = VER_PLATFORM_WIN32_NT
AdjustToken
ExitWindowsEx EWX_SHUTDOWN Or EWX_POWEROFF, 0
Shutdown = True
End Select
End Function
Public Function Restart() As Boolean
Select Case OsVersion(False)
Case Is = VER_PLATFORM_WIN32s
Restart = False
Case Is = VER_PLATFORM_WIN32_WINDOWS
ExitWindowsEx EWX_REBOOT, 0&
Restart = True
Case Is = VER_PLATFORM_WIN32_NT
AdjustToken
ExitWindowsEx EWX_REBOOT, 0
Restart = True
End Select
End Function
Public Sub LogOff()
ExitWindowsEx EWX_LOGOFF, 0&
End Sub
Public Sub Suspend()
If OsVersion(False) = VER_PLATFORM_WIN32_NT Then AdjustToken
SetSystemPowerState True, False
End Sub
Public Sub Hibernate()
If OsVersion(False) = VER_PLATFORM_WIN32_NT Then AdjustToken
SetSystemPowerState False, False
End Sub
Private Function AdjustToken() As Long
Const TOKEN_ADJUST_PRIVILEGES = &H20: Const TOKEN_QUERY = &H8
Dim hdlProcessHandle As Long, hdlTokenHandle As Long, lBufferNeeded As Long
Dim tmpLuid As LUID: Dim tkp As TOKEN_PRIVILEGES
Dim tkpNewButIgnored As TOKEN_PRIVILEGES
ExitWindowsEx под NT, XP не работает.
Код который написал sne подходит, но всеже:
Dim strComputer As String
strComputer = "."
Set objWMIService = GetObject("winmgmts:" & _
"{impersonationLevel=impersonate,(Shutdown)}!\\" & strComputer & "\root\cimv2"
Set colOperatingSystems = objWMIService.ExecQuery( _
"Select * from Win32_OperatingSystem"
For Each ObjOperatingSystem In colOperatingSystems
ObjOperatingSystem.ShutDown 'Для выключения
Next
Я конечно попробую все варианты, но меня удивляет тот факт, что раньше надругих машинах, работающих по Win2000 программа работала. Та тачка, на которой я пытался сделать - специально cконфигурирована для некоторой задачи (в ней даже CD-ROM'а нет), т.е. вмешательство в работу компа ограничена.
Код описанный в вопросе рабочий (пример из API-Guide). Насколько я понял проблема состоит лишь в небольшой доработке под корпус ATX. Добавьте
Private Const EWX_POWEROFF = &H8&
, как писал sne и процедурка ShutDownNT примет следующий вид:
Public Sub ShutDownNT(Force As Boolean)
Dim Flags As Long
Flags = EWX_SHUTDOWN Or EWX_POWEROFF
If Force Then Flags = Flags + EWX_FORCE
If IsWinNT Then EnableShutDown
ExitWindowsEx Flags, 0
End Sub
Ну, быть может проблема кроется несколько глубже - в доработке самого корпуса под стандарт ATX. Это объясняет почему код на 98 не работает ))
Тестировал под Win98 и WinXP - работает нормально.
- цитата из вопроса для LamerOnLine, или Вы имели ввиду код VBLamer? Но sne уже объяснил, почему его не стоит рассматривать.
Мой ответ лишь результат сравнения кода, приведенного в вопросе и кода sne(как и предлагалось).