[Source] 電腦關機、登出、重新開機,不用再調用 Shutdown.exe 了!

一般要關機就直接開始選單選關機就行了,有時候要定時關機可能就會用到 Shutdown.exe,可是 Shutdown.exe 用起來有幾個小問題,像是無法關閉 Windows Server,或者如果使用者要阻止關機只要一個 -a 指令就可以了,甚至到系統資料夾把檔案直接殺掉...
其實 M$ 自己就有提供一個 API 可以讓我們調用關機、登出、重啟的動作!

Windows 2000 之後必須先把程式提權才能成功調用 ExitWindowsEx

C++
HANDLE   hdl;
OpenProcessToken(GetCurrentProcess(),   TOKEN_ADJUST_PRIVILEGES,   &hdl);
PTOKEN_PRIVILEGES   ptoken   =   (PTOKEN_PRIVILEGES)   new   BYTE[sizeof(DWORD)   +
sizeof(LUID_AND_ATTRIBUTES)];
ptoken-> PrivilegeCount   =   1;
LUID   uid;
LookupPrivilegeValue(NULL,   SE_SHUTDOWN_NAME,   &uid);
ptoken-> Privileges[0].Luid   =   uid;
ptoken-> Privileges[0].Attributes   =   SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hdl,   FALSE,   ptoken,   0,   NULL,   NULL);
CloseHandle(hdl);
delete   [](BYTE   *)ptoken;
ExitWindowsEx(EWX_FORCE|EWX_SHUTDOWN,0);

VB6 因為要手動宣告所以比較麻煩點...
Option Explicit

Private Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Declare Function LookupPrivilegeValueA Lib "advapi32.dll" (ByVal lpSystemName As String, ByVal lpName As String, lpLuid As LUID) As Long
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 Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function ExitWindowsEx Lib "user32" (ByVal uFlags As Long, ByVal dwReserved As Long) As Long

Private Const TOKEN_ADJUST_PRIVILEGES = &H20
Private Const TOKEN_QUERY = &H8
Private Const SE_PRIVILEGE_ENABLED = &H2
Private Const ANYSIZE_ARRAY = 1

Private Type LUID
    lowpart As Long
    highpart As Long
End Type

Private Type LUID_AND_ATTRIBUTES
    pLuid As LUID
    Attributes As Long
End Type

Private Type TOKEN_PRIVILEGES
    PrivilegeCount As Long
    Privileges(ANYSIZE_ARRAY) As LUID_AND_ATTRIBUTES
End Type

Private Const EWX_FORCE = 4
Private Const EWX_SHUTDOWN = 1
Private Const EWX_REBOOT = 2
Private Const EWX_LOGOFF = 0

Private Sub Command1_Click()
    Dim hdl As Long
    Dim uid As LUID
    Dim ptoken As TOKEN_PRIVILEGES
    Dim PreviousState As TOKEN_PRIVILEGES
    Dim ReturnLength As Long
    
    OpenProcessToken GetCurrentProcess, (TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY), hdl
    LookupPrivilegeValueA "", "SeShutdownPrivilege", uid
    ptoken.PrivilegeCount = 1
    ptoken.Privileges(0).pLuid = uid
    ptoken.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED
    AdjustTokenPrivileges hdl, False, ptoken, Len(PreviousState), PreviousState, ReturnLength
    CloseHandle hdl
    ExitWindowsEx EWX_SHUTDOWN Or EWX_FORCE, 0
End Sub

以上源碼皆已在 Win7 x86 測試完成。

留言

本月最夯

偷用電腦,怎知?事件檢視器全記錄!(開機時間、啟動項時間...)