XPや7などのNT系Windowsでシャットダウン・再起動・ログオフ・サスペンド・休止を行う
|
(2012/04/09更新)
sysexit命令やExitWindowsEx APIだけでNT系Windowsをシャットダウンできない理由
HSPからWindowsの終了や再起動を行う方法としてはhspext.dll命令のsysexitやWin32 APIのExitWindowsExがありますが、動作環境がXPや2000などのNT系OSの場合、これらの命令/APIを実行しただけではWindowsは言うことを聞いてくれません。
実はNT系OSで上記のことをさせるには、命令/APIの実行前にOSのシャットダウン権限を得ている状態でなければいけません。これはプログラムを実行しているユーザがWindowsの管理者権限を持っていたとしても必要になります。
プログラムでOSのシャットダウン権限を得るには、「プロセスにSE_SHUTDOWN_NAME特権を割り当てる」必要があります。具体的な手順としては、「現在のプロセスのアクセストークンを取得」→「アクセストークンのSE_SHUTDOWN_NAME特権を有効にする」という形になります。
現在のプロセスのアクセストークンを取得
トークンを取得するには、まずGetCurrentProcess APIで現在のプロセスの擬似ハンドルを取得してから、OpenProcessToken APIを実行します。GetCurrentProcessで得られるハンドルはクローズの必要はありませんが、トークンの方は不要になった時点でクローズする必要があります。
アクセストークンのSE_SHUTDOWN_NAME特権を有効にする
この部分の処理では3つの構造体が必要なため、まずそれ用の変数を用意します。TOKEN_PREVILEGES構造体については、今回設定しなければならない特権情報が1つなのでサイズが16バイトになっていますが、使用される状況によっては変わる可能性があります。
次にLookupPrivilegeValue APIによって適切なLUID構造体を取得し、それを元にLUID_AND_ATTRIBUTES構造体、TOKEN_PREVILEGES構造体を作成。最後にアクセストークンとTOKEN_PREVILEGES構造体を引数にしてAdjustTokenPrivileges APIを実行します。
トークンの変更がうまくいけば、あとはExitWindowsEx APIを実行するだけでWindowsの終了/再起動が可能です(ExitWindowsExの呼び出しはモジュールに含まれています)。ExitWindowsExの代わりにhspext.dllのsysexit命令を使ってもかまいません。
モジュールの使い方
利用したいスクリプトでインクルードしてから、命令一覧にある命令から一つ選んで呼び出して下さい。また呼び出した後には必ずend命令を入れておくようにして下さい。マシンによってはwin_shutdownでもwin_poweroffでも同じ動作になるようですが、確実に電源を切りたい場合はwin_poweroffを使っておけばいいでしょう。
参考ページ
http://www31.ocn.ne.jp/~yoshio2/vcmemo18-1.html
http://www6.plala.or.jp/MilkHouse/practical/contents310/contents31002.html
http://itpro.nikkeibp.co.jp/article/Windows/20060208/228778/
関連リンク
Windows用フリーウェア - NT系Windowsを終了・再起動・ログオフ・スリープさせるためのユーティリティ、shutdown / reboot / logoff/ sleep
>> ダウンロード (ブラウザで見ると文字化けしますが、データは正常です)
/***********************************************************
NT系Windowsシャットダウン機能モジュール
【2012/04/09更新】
(使い方)
以下の命令のうちいずれか一つを実行する。
サスペンドまたは休止させる場合は、命令を呼び出し
た後にend命令を実行してプログラムを終了させて下さい。
9x系Windowsではこのモジュールを使う必要はない。
作者の環境では、win_shutdownとwin_poweroffは「Windows終了」+
「電源オフ」という同じ動作になりました。
(命令一覧)
●ログオフ
#deffunc win_logoff
●シャットダウン
#deffunc win_shutdown
●再起動
#deffunc win_reboot
●電源オフ
#deffunc win_poweroff
●サスペンド(スリープ)
#deffunc win_suspend
#deffunc win_sleep
●休止(ハイバネート)
#deffunc win_hibernate
***********************************************************/
#ifndef __GM_EXIT_WINDOWS__
#define global __GM_EXIT_WINDOWS__
#include "kernel32.as"
#include "advapi32.as"
#include "user32.as"
#uselib "PowrProf.dll"
#func global SetSuspendState "SetSuspendState" int, int, int
#module
#const TRUE 1
#const FALSE 0
#const NULL 0
#const TOKEN_ADJUST_PRIVILEGES 0x20
#const SIZE_LUID 8 // 構造体サイズ
#const SIZE_LUID_AND_ATTRIBUTES 12
#const SIZE_TOKEN_PRIVILEGES 16 // 特権情報を1つだけ設定する場合(PRIVILEGE_COUNT=1)
#define SE_SHUTDOWN_NAME "SeShutdownPrivilege"
#const SE_PRIVILEGE_ENABLED 0x02
#const PRIVILEGE_COUNT 1
#const EWX_LOGOFF 0
#const EWX_SHUTDOWN 1
#const EWX_REBOOT 2
#const EWX_POWEROFF 8
/*
* アクセストークンのSE_SHUTDOWN_NAME 特権を有効に
*/
#deffunc _adjust_privilege
/* 現在のプロセスのアクセストークンを取得 */
GetCurrentProcess
hproc = stat // 現在のプロセスの擬似ハンドル。クローズ不要。
htoken = 0 // SE_SHUTDOWN_NAME 特権を設定するためのアクセストークン用。要クローズ。
OpenProcessToken hproc, TOKEN_ADJUST_PRIVILEGES, varptr(htoken)
/* アクセストークンのSE_SHUTDOWN_NAME 特権を有効に */
dim luid, SIZE_LUID / 4 // LUID 構造体
dim luid_and_attributes, SIZE_LUID_AND_ATTRIBUTES / 4 // LUID_AND_ATTRIBUTES 構造体
dim token_privileges, SIZE_TOKEN_PRIVILEGES / 4 // TOKEN_PREVILEGES 構造体
LookupPrivilegeValue NULL, SE_SHUTDOWN_NAME, varptr(luid)
luid_and_attributes = luid(0), luid(1), SE_PRIVILEGE_ENABLED
token_privileges = PRIVILEGE_COUNT, luid_and_attributes(0), luid_and_attributes(1), luid_and_attributes(2)
AdjustTokenPrivileges htoken, FALSE, varptr(token_privileges), 0, NULL, NULL
CloseHandle htoken
return
/*
* 指定の方法でWindowsを終了
*/
#deffunc _exit_win int ewx_type_
_adjust_privilege
ExitWindowsEx ewx_type_, NULL
return
/*
* Windowsをサスペンド(スリープ)または休止(ハイバネート)
*/
#deffunc _suspend_win int flag_hiberbate_
_adjust_privilege
SetSuspendState flag_hiberbate_, FALSE, FALSE
return
/*
* ログオフ
*/
#deffunc win_logoff
_exit_win EWX_LOGOFF
return
/*
* シャットダウン
*/
#deffunc win_shutdown
_exit_win EWX_SHUTDOWN
return
/*
* 再起動
*/
#deffunc win_reboot
_exit_win EWX_REBOOT
return
/*
* 電源オフ
*/
#deffunc win_poweroff
_exit_win EWX_POWEROFF
return
/*
* スリープ(=サスペンド)
*/
#deffunc win_sleep
_suspend_win FALSE
return
/*
* サスペンド(=スリープ)
*/
#deffunc win_suspend
_suspend_win FALSE
return
/*
* 休止(ハイバネート)
*/
#deffunc win_hibernate
_suspend_win TRUE
return
#global
#endif
/*
%dll
gm_exit_windows.hsp
%date
2012/04/09
%author
chrono
%port
Win
%note
利用しているDLL : kernel32.dll, advapi32.dll, user32.dll, powrprof.dll
9x系Windowsではこのモジュールを使う必要はありません。
;----------
%index
win_logoff
NT系Windowsからログオフ
%prm
%inst
%type
ユーザ定義命令
%sample
%href
win_shutdown
win_reboot
win_poweroff
win_sleep
win_suspend
win_hibernate
;----------
%index
win_shutdown
NT系Windowsをシャットダウン
%prm
%inst
%type
ユーザ定義命令
%sample
%href
win_logoff
win_reboot
win_poweroff
win_sleep
win_suspend
win_hibernate
;----------
%index
win_reboot
NT系Windowsを再起動
%prm
%inst
%type
ユーザ定義命令
%sample
%href
win_logoff
win_shutdown
win_poweroff
win_sleep
win_suspend
win_hibernate
;----------
%index
win_poweroff
NT系Windowsマシンを電源オフ
%prm
%inst
%type
ユーザ定義命令
%sample
%href
win_logoff
win_shutdown
win_reboot
win_sleep
win_suspend
win_hibernate
;----------
%index
win_sleep
NT系Windowsマシンをスリープ(=サスペンド)
%prm
%inst
同じモジュールのwin_suspend命令でも同じことができます。
%type
ユーザ定義命令
%sample
%href
win_logoff
win_shutdown
win_reboot
win_suspend
win_hibernate
;----------
%index
win_suspend
NT系Windowsマシンをサスペンド(=スリープ)
%prm
%inst
同じモジュールのwin_sleep命令でも同じことができます。
%type
ユーザ定義命令
%sample
%href
win_logoff
win_shutdown
win_reboot
win_sleep
win_hibernate
;----------
%index
win_hibernate
NT系Windowsマシンを休止(ハイバネート)
%prm
%inst
%type
ユーザ定義命令
%sample
%href
win_logoff
win_shutdown
win_reboot
win_sleep
win_suspend
%*/
|