Option Strict Off
Option Explicit On
Imports System.Runtime.InteropServices
Friend Class Form1
Inherits System.Windows.Forms.Form
' システムをログオフまたはシャットダウン
Public Enum ExitWindows
EWX_LOGOFF = &H0 'ログオフ
EWX_SHUTDOWN = &H1 'シャットダウン 98:電源オフ
EWX_REBOOT = &H2 '再起動
EWX_POWEROFF = &H8 '電源オフ NT:電源オフ 98:無し
EWX_RESTARTAPPS = &H40
EWX_FORCE = &H4 '強制(無条件に実行)
EWX_FORCEIFHUNG = &H10
End Enum
<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function ExitWindowsEx( _
ByVal uFlags As ExitWindows, _
ByVal dwReason As Integer) As Boolean
End Function
' 自分自身の擬似プロセスハンドルを取得
<DllImport("kernel32.dll")> _
Private Shared Function GetCurrentProcess() As IntPtr
End Function
' アクセストークンのタイプ
Private Const TOKEN_QUERY As Short = &H8s
Private Const TOKEN_ADJUST_PRIVILEGES As Short = &H20s
' プロセスと結び付けられたアクセストークンを開く
<DllImport("advapi32.dll", SetLastError:=True)> _
Private Shared Function OpenProcessToken( _
ByVal ProcessHandle As IntPtr, _
ByVal DesiredAccess As Integer, _
ByRef TokenHandle As IntPtr _
) As Boolean
End Function
' ユニークな認証標識を定義する構造体
<StructLayout(LayoutKind.Sequential)> _
Private Structure tagLUID
Dim LowPart As Integer
Dim HighPart As Integer
End Structure
' SE_SHUTDOWN_NAME特権を示す定数
Private Const SE_SHUTDOWN_NAME As String = "SeShutdownPrivilege"
' 指定した特権名のLUIDを検索
<DllImport("advapi32.dll", SetLastError:=True, _
CharSet:=System.Runtime.InteropServices.CharSet.Auto)> _
Private Shared Function LookupPrivilegeValue( _
ByVal lpSystemName As String, _
ByVal lpName As String, _
ByRef lpLuid As Long) As Boolean
End Function
' 指定したアクセストークンを設定
<DllImport("advapi32.dll", SetLastError:=True)> _
Private Shared Function AdjustTokenPrivileges( _
ByVal TokenHandle As IntPtr, _
ByVal DisableAllPrivileges As Boolean, _
ByRef NewState As TOKEN_PRIVILEGES, _
ByVal BufferLength As Integer, _
ByVal PreviousState As IntPtr, _
ByVal ReturnLength As IntPtr) As Boolean
End Function
' ユニークな認証標識と属性を定義
Private Structure LUID_AND_ATTRIBUTES
Dim Luid As tagLUID
Dim Attributes As Integer
End Structure
' アクセストークンの特権セット情報を定義
<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Private Structure TOKEN_PRIVILEGES
Public PrivilegeCount As Integer
Public Luid As Long
Public Attributes As Integer
End Structure
' 特権の属性を示す定数
Private Const SE_PRIVILEGE_ENABLED As Integer = &H2
Private 予定時刻 As Date
Private Op As Long '処理種別
Private Sub Form1_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load
'------------------
' 書式設定
'------------------
Me.Text = "指定時間後にシャットダウン/再起動/ログオフ"
Button1.Text = "電源オフ"
Button2.Text = "再起動"
Button3.Text = "ログオフ"
Button4.Text = "中止"
Button4.Enabled = False
With Combo1
.Font = VB6.FontChangeSize(.Font, 11) 'フォントサイズ
.ImeMode = System.Windows.Forms.ImeMode.Off 'IMEモード:オフ
.Items.Add(0) '時間リスト 0分
.Items.Add(1) '1分
.Items.Add(10) '10分
.Items.Add(30) '30分
.SelectedIndex = 0 '初期選択位置:0分
End With
With Label1
.Font = VB6.FontChangeSize(.Font, 16)
.TextAlign = System.Drawing.ContentAlignment.TopCenter
.Text = ""
End With
With Timer1
.Enabled = False '初期状態は無効
.Interval = 1000 '周期:1秒
End With
End Sub
'----------------------------
' 指定時間の入力チェック
'----------------------------
Private Sub Combo1_KeyPress(ByVal eventSender As System.Object, ByVal eventArgs As System.Windows.Forms.KeyPressEventArgs) Handles Combo1.KeyPress
Dim KeyAscii As Short = Asc(eventArgs.KeyChar)
If (KeyAscii <> Asc(vbBack)) And (Not (Chr(KeyAscii) Like "[0-9]")) Then KeyAscii = 0 '0〜9以外は不許可
eventArgs.KeyChar = Chr(KeyAscii)
If KeyAscii = 0 Then
eventArgs.Handled = True
End If
End Sub
Private Sub Combo1_Validating(ByVal eventSender As System.Object, ByVal eventArgs As System.ComponentModel.CancelEventArgs) Handles Combo1.Validating
Dim Cancel As Boolean = eventArgs.Cancel
If Combo1.Text = "" Then
MsgBox("指定時間:空白は無効")
Cancel = True '空白は不許可
End If
eventArgs.Cancel = Cancel
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Call Go(ExitWindows.EWX_SHUTDOWN)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Call Go(ExitWindows.EWX_REBOOT)
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Call Go(ExitWindows.EWX_LOGOFF)
End Sub
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
Timer1.Enabled = False 'タイマー停止
Label1.Text = ""
Button1.Enabled = True
Button2.Enabled = True
Button3.Enabled = True
Button4.Enabled = False
End Sub
Private Sub Go(ByVal Param As Integer)
Op = Param '処理種別
Label1.ForeColor = System.Drawing.Color.Black '表示色=黒
Timer1.Enabled = True
If Val(Combo1.Text) = 0 Then '指定時間が0なら
予定時刻 = System.DateTime.FromOADate(Now.ToOADate + TimeSerial(0, 0, 5).ToOADate) '5秒前から
Else
予定時刻 = System.DateTime.FromOADate(Now.ToOADate + TimeSerial(0, Val(Combo1.Text), 0).ToOADate) 'そのまま
End If
Button1.Enabled = False
Button2.Enabled = False
Button3.Enabled = False
Button4.Enabled = True
End Sub
Private Sub Timer1_Tick(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Timer1.Tick
Dim t As TimeSpan '残り時間
t = New TimeSpan(0, 0, (予定時刻 - Now()).TotalSeconds) '秒単位(ミリ秒は表示しない)
Label1.Text = t.ToString
Select Case t.TotalSeconds
Case Is <= 0 '時間=0
'-------------------
' 電源オフ実行
'-------------------
Call PowerOff() '電源オフ実行
End
Case Is <= 10 '10秒以内
Label1.ForeColor = System.Drawing.Color.Red '表示色=赤
Beep() 'カウントダウン音
Case Else
End Select
End Sub
Private Sub PowerOff()
'
' 電源オフ用サブルーチン
'
Dim lngHandleProcess As IntPtr
Dim lngHandleToken As IntPtr
Dim udtLuid As New tagLUID
Dim udtNewState As New TOKEN_PRIVILEGES
Dim udtPreviousState As New TOKEN_PRIVILEGES
Dim lngRc As Integer
Dim OSPlatform As String = My.Computer.Info.OSPlatform 'OSバージョン取得
Select Case OSPlatform
Case "Win32NT" 'NT系OS?
' カレントプロセスの疑似ハンドルを取得
lngHandleProcess = GetCurrentProcess()
' カレントプロセスのアクセストークンを開く
lngRc = OpenProcessToken(lngHandleProcess, TOKEN_QUERY Or TOKEN_ADJUST_PRIVILEGES, lngHandleToken)
' アクセストークンのパラメータに特権を付与
With udtNewState
.PrivilegeCount = 1
.Attributes = SE_PRIVILEGE_ENABLED
' SE_SHUTDOWN_NAME特権のLUIDを検索
lngRc = LookupPrivilegeValue(Nothing, SE_SHUTDOWN_NAME, udtNewState.Luid)
End With
' 新しいアクセストークンを設定 ★★★★★★例外発生★★★★★★★★
lngRc = AdjustTokenPrivileges(lngHandleToken, False, udtNewState, 0, IntPtr.Zero, IntPtr.Zero)
' 終了処理(NTの場合、SHUTDOWNでは電源は切れない)
Call ExitWindowsEx(Op, CInt(0))
Case "Win32Windows"
If Op = ExitWindows.EWX_POWEROFF Then Op = ExitWindows.EWX_SHUTDOWN
Call ExitWindowsEx(Op, CLng(0))
Case Else
End Select
End Sub
End Class