〜 システム 〜
パソコンをログオフ・再起動・終了 (要USER32.DLL, KERNEL32.DLL, ADVAPI32.DLL)

ウィンドウズを再起動または終了したり、現在のユーザーをログオフするやり方を説明します。
使用するのはAPI関数ExitWindowsExで、予約された第2パラメータは0として、
メインである第1パラメータに次のいずれかを指定します。
EWX_LOGOFF0x0000現在のユーザーをログオフ
EWX_SHUTDOWN0x0001システムをシャットダウンして、電源を切っても安全な状態にする
EWX_REBOOT0x0002システムをシャットダウンした後、システムを再起動する
EWX_POWEROFF0x0008システムをシャットダウンした後、電源を切る
また、オプションとして次の値をパラメータ値に加えることが出来ます。
EWX_FORCE0x0004全てのプロセスを強制的に終了する
EWX_FORCEIFHUNG0x0010ハングアップしたプロセスを強制的に終了する(Windows2000〜)
9X系のウィンドウズでは上記全てのパラメータを使用出来ますが、 NT系または2000以降だと、HSPの実行プロセスにシャットダウン権限がないために、 セキュリティ機能によりログオフ以外は正常に動作させることができません。 NT系または2000以降でも動作させるには、プロセスにSE_SHUTDOWN_NAME特権の追加が必要です。 流れとしてはまず、API関数GetCurrentProcessでプロセスハンドルを取得、 プロセスハンドルを使ってAPI関数OpenProcessTokenでプロセストークンを開きます。 オープン時に使うのは、アクセストークン内容を問い合わせるTOKEN_QUERY(=0x0008)と、 トークンに変更を加えるTOKEN_ADJUST_PRIVILEGES(=0x0020)を合わせた0x0028を指定しましょう。 次に「SE_SHUTDOWN_NAME特権を有効化して、AdjustTokenPrivileges関数で設定」としたいのですが、 設定にはTOKEN_PRIVILEGES構造体を使う必要があり、ローカル一意識別子(LUID)で要求されるので、 先にAPI関数LookupPrivilegeValueを使って特権名から適切なLUIDを取得します。 LUIDを取得したら、SE_SHUTDOWN_NAME特権を有効(=SE_PRIVILEGE_ENABLED)にして、 API関数AdjustTokenPrivilegesを行えば設定が完了で、下記のいずれかが返ります。
ERROR_SUCCESS0x0000全ての特権を調整した
ERROR_NOT_ALL_ASSIGNED0x0514特権の調整に失敗した、または調整しなかった
9X系ではそのまま、NT系または2000以降では権限を設定してから…。 1つのスクリプトでどちらでも実行可能にするにはOSのバージョンをチェックして分岐させましょう。 バージョンの取得についてはコチラを参考にしてください。

getosver タイプ
タイプ refstrに返すバージョン情報の取得タイプを指定する。
0「」(バージョン情報テキストは取得しない)
1「メジャーバージョン」
2「メジャーバージョン」.「マイナーバージョン」
3「メジャーバージョン」.「マイナーバージョン」.「ビルドナンバー」
4「メジャーバージョン」.「マイナーバージョン」.「ビルドナンバー」 「追加情報」
尚、statにはプラットフォーム種別コードが返る。

exitwin タイプ, 強制
タイプ動作タイプ(0:ログオフ 1:シャットダウン 2:再起動 3:パワーオフ)を指定する
強制強制オプション(0:強制なし 1:強制終了 2:ハングアップのみ強制終了)を指定する

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
	ll_libload kernel, "kernel32.dll"
	ll_getproc GetCurrentProcess, "GetCurrentProcess", kernel
	ll_getproc GetVersionEx, "GetVersionExA", kernel
	ll_libload user, "user32.dll"
	ll_getproc ExitWindowsEx, "ExitWindowsEx", user
	ll_libload advapi, "advapi32.dll"
	ll_getproc AdjustTokenPrivileges, "AdjustTokenPrivileges", advapi
	ll_getproc LookupPrivilegeValue, "LookupPrivilegeValueA", advapi
	ll_getproc OpenProcessToken, "OpenProcessToken", advapi

#module
#deffunc getosver int
	mref type, 0
	mref stt, 64
	mref rstr, 65
	dim i, 37
	i = 148
	ll_getptr i : ll_ret prm
	ll_callfunc prm, 1, GetVersionEx@
	stt = i.4
	if type = 0 : return
	if i.4 = 2 : rstr = "NT " : else : rstr = ""
	rstr += "" + i.1
	if type > 1 : rstr += "." + i.2
	if type > 2 : rstr += "." + i.3
	if type > 3 {
		rstr += " "
		repeat 32, 5
			strlen i.1, rstr
			wpoke rstr, i.1 + 0, i.cnt & 0xFFFF
			wpoke rstr, i.1 + 2, i.cnt >> 16
		loop
	}
	return

#deffunc exitwin int, int
	mref type, 0 : mref option, 1
	types = 0x0000, 0x0001, 0x0002, 0x0008
	options = 0x0000, 0x0004, 0x0010
	flags = types.type + options.option
	// NT系OSなら特権を有効化
	getosver
	if stat = 2 {
		ll_callfnv GetCurrentProcess@ : ll_ret i
		prm = i, 0x0028 // TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
		ll_getptr token : ll_ret prm.2
		ll_callfunc prm, 3, OpenProcessToken@
		prm = 0
		ll_getptr s : s = "SeShutdownPrivilege" : ll_ret prm.1 // SE_SHUTDOWN_NAME
		ll_getptr luid : ll_ret prm.2
		ll_callfunc prm, 3, LookupPrivilegeValue@
		prm = token, 0, 0, 0, 0, 0
		tp = 1, luid, 0, 2 // Count, LUID_AND_ATTRIBUTES(LUID, Attribute), SE_PRIVILEGE_ENABLED
		ll_getptr tp : ll_ret prm.2
		ll_callfunc prm, 6, AdjustTokenPrivileges@
	}
	prm = flags, 0
	return
#global

	items = "ログオフ\n終了\n再起動"
	objsize 100, 20
	pos 10, 10 : combox menu, , items
	pos 10, 40 : chkbox "強制実行", force
	pos 10, 70 : button "実行する", *running
	stop

*running
	notesel items
	noteget item, menu
	dialog item + "してよろしいですか?", 2
	if stat = 6 : exitwin menu, force
	stop

バージョン情報 = getosver(タイプ)
バージョン情報バージョン情報テキストの受取先を指定する。
タイプ バージョン情報の取得タイプを指定する。
0「」(バージョン情報テキストは取得しない)
1「メジャーバージョン」
2「メジャーバージョン」.「マイナーバージョン」
3「メジャーバージョン」.「マイナーバージョン」.「ビルドナンバー」
4「メジャーバージョン」.「マイナーバージョン」.「ビルドナンバー」 「追加情報」
尚、statにはプラットフォーム種別コードが返る。

exitwin タイプ, 強制
タイプ動作タイプ(0:ログオフ 1:シャットダウン 2:再起動 3:パワーオフ)を指定する
強制強制オプション(0:強制なし 1:強制終了 2:ハングアップのみ強制終了)を指定する

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#uselib "kernel32.dll"
#cfunc global GetCurrentProcess "GetCurrentProcess"
#func  global GetVersionEx "GetVersionExA" var
#uselib "user32.dll"
#func  global ExitWindowsEx "ExitWindowsEx" int, int
#uselib "advapi32.dll"
#func  global AdjustTokenPrivileges "AdjustTokenPrivileges" int, int, var, int, int, int
#func  global LookupPrivilegeValue "LookupPrivilegeValueA" int, sptr, var
#func  global OpenProcessToken "OpenProcessToken" int, int, var

#module
#defcfunc getosver int type, local i, local s
	dim i, 37
	i = 148
	GetVersionEx i
	if type = 0 : return i.4
	if i.4 = 2 : s = "NT " : else : s = ""
	s += str(i.1)
	if type > 1 : s += "." + i.2
	if type > 2 : s += "." + i.3
	if type > 3 {
		s += " "
		repeat 32 : lpoke s, strlen(s), i(5 + cnt) : loop
	}
	return s

#deffunc exitwin int type, int option
	types = 0x0000, 0x0001, 0x0002, 0x0008
	options = 0x0000, 0x0004, 0x0010
	// NT系OSなら特権を有効化
	if getosver() = 2 {
		OpenProcessToken GetCurrentProcess(), 0x0028, token // TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
		LookupPrivilegeValue 0, "SeShutdownPrivilege", luid // SE_SHUTDOWN_NAME
		tp = 1, luid, 0, 2 // Count, LUID_AND_ATTRIBUTES(LUID, Attribute), SE_PRIVILEGE_ENABLED
		AdjustTokenPrivileges token, , tp
	}
	ExitWindowsEx types.type + options.option
	return
#global

	items = "ログオフ\n終了\n再起動"
	objsize 100, 20
	pos 10, 10 : combox menu, , items
	pos 10, 40 : chkbox "強制実行", force
	pos 10, 70 : button gosub "実行する", *running
	stop

*running
	notesel items
	noteget item, menu
	dialog item + "してよろしいですか?", 2
	if stat = 6 : exitwin menu, force
	return