・Excel 2000 - VBA編
<1.Windows APIを使用する>
Excelを起動してAlt + F11を押してVBエディタを開き、
挿入メニューから標準モジュールを追加してください。
新規のモジュールができたら以下を記述してください。
Option Explicit '現在のプロセスハンドル取得 Private Declare Function GetCurrentProcess Lib "kernel32" () As Long 'アクセストークン オープン Private Declare Function OpenProcessToken Lib "advapi32.dll" _ (ByVal ProcessHandle As Long, _ ByVal DesiredAccess As Long, _ TokenHandle As Long) As Long '特権名よりローカル一意識別子取得 Private Declare Function LookupPrivilegeValue Lib "advapi32.dll" _ Alias "LookupPrivilegeValueA" _ (ByVal lpSystemName As String, _ ByVal lpName As String, _ dlpLuid 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 Long, _ ReturnLength As Long) As Long '第五引数データ型変更 'ハンドルClose 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 Declare Function SetSystemPowerState Lib "kernel32.dll" _ (ByVal fSuspend As Long, _ ByVal fForce As Long) As Long 'Hibernationサポート確認 Private Declare Function IsPwrHibernateAllowed Lib "Powrprof.dll" () As Byte 'Hibernation有効/無効化 Private Declare Function CallNtPowerInformation Lib "Powrprof.dll" _ (ByVal InformationLevel As POWER_INFORMATION_LEVEL, _ lpInputBuffer As Byte, _ ByVal nInputBufferSize As Long, _ lpOutputBuffer As Long, _ ByVal nOutputBufferSize As Long) As Long '(定数) Private Const TOKEN_QUERY As Long = &H8 Private Const TOKEN_ADJUST_PRIVILEGES As Long = &H20 Private Const EWX_LOGOFF As Long = &H0 Private Const EWX_REBOOT As Long = &H2 Private Const EWX_POWEROFF As Long = &H8 Private Const EWX_FORCEIFHUNG As Long = &H10 Private Const SE_SHUTDOWN_NAME As String = "SeShutdownPrivilege" Private Const SE_PRIVILEGE_ENABLED As Long = &H2 '(構造体) 'ローカル一意識別子 Private Type LUID lowpart As Long highpart As Long End Type Private Type LUID_AND_ATTRIBUTES pLuid As LUID Attributes As Long '特権を有効にするにはSE_PRIVILEGE_ENABLEDを指定 End Type 'AdjustTokenPrivilegesで使用する変更する特権情報を保持する構造体 Private Type TOKEN_PRIVILEGES PrivilegeCount As Long '変更する特権数 Privileges(0) As LUID_AND_ATTRIBUTES End Type '(列挙体) Private Enum POWER_INFORMATION_LEVEL SystemReserveHiberFile = 10 End Enum Public Enum POWER_STATUS POWEROFF = 1 LOGOFF = 2 REBOOT = 3 STANDBY = 4 HIBER = 5 End Enum '---------------------------------------------------------------------------------- 'Win32APIによる電源管理(引数に指定した状態に移行) '引数 argeStatus : 列挙体 POWEROFF, LOGOFF, REBOOT, STANDBY, HIBERのいずれか '戻値 成功 0以外, 失敗 0 Public Function GFnControlPowerByAPI(argeStatus As POWER_STATUS) As Long Dim vlRet As Long '戻値フラグ Dim vlFlag(3) As Long 'Poweroff, Logoff, Reboot用配列 Dim vcIn As Byte 'Hibernation有効フラグ 'SE_SHUTDOWN_NAME特権の有効化 If FnControlPrivilege(SE_SHUTDOWN_NAME, True) = 0 Then Exit Function vlFlag(0) = &H10000: _ vlFlag(1) = EWX_POWEROFF: _ vlFlag(2) = EWX_LOGOFF: _ vlFlag(3) = EWX_REBOOT Do If argeStatus <= REBOOT Then 'シャットダウン/ログオフ/再起動 vlRet = ExitWindowsEx(vlFlag(argeStatus) Or EWX_FORCEIFHUNG, 0) Else 'Hibernationの場合 If argeStatus = HIBER Then If IsPwrHibernateAllowed() = 0 Then 'Hibernation無効の時 'Hibernation有効化 vcIn = 1 If CallNtPowerInformation(SystemReserveHiberFile, _ vcIn, LenB(vcIn), ByVal 0, 0) <> 0 Then vlRet = 0: Exit Do End If End If End If 'サスペンド/休止 vlRet = SetSystemPowerState((argeStatus = STANDBY), 1) End If Exit Do Loop '特権無効化 FnControlPrivilege SE_SHUTDOWN_NAME, False GFnControlPowerByAPI = vlRet End Function '---------------------------------------------------------------------------------- '特権の有効化/無効化 '引数 argsPrivilege '戻値 成功 0以外 失敗 0 Private Function FnControlPrivilege(argsPrivilege As String, _ argyEnable As Boolean) As Long Dim vlRet As Long Dim vlHToken As Long Dim vtLuid As LUID Dim vtTp As TOKEN_PRIVILEGES 'アクセストークン オープン vlRet = OpenProcessToken(GetCurrentProcess(), _ TOKEN_QUERY Or TOKEN_ADJUST_PRIVILEGES, _ vlHToken) If vlRet = 0 Then Exit Function Do '特権名(argsPrivilege)からローカル一意識別子(vtLuid)の取得 vlRet = LookupPrivilegeValue(vbNullString, argsPrivilege, vtLuid) If vlRet = 0 Then Exit Do 'TOKEN_PRIVILEGES構造体の作成 vtTp.PrivilegeCount = 1 vtTp.Privileges(0).pLuid = vtLuid vtTp.Privileges(0).Attributes = IIf(argyEnable, SE_PRIVILEGE_ENABLED, 0) '特権の有効化/無効化 vlRet = AdjustTokenPrivileges(vlHToken, 0, vtTp, 0, ByVal 0, ByVal 0) If vlRet = 0 Then Exit Do Exit Do Loop 'ハンドルClose CloseHandle vlHToken FnControlPrivilege = vlRet End Function |
記述できたらブックを保存して、イミディエイトウィンドウやワークシートから GFnControlPowerByAPIを任意の引数を渡して実行してください。
APIの宣言に関しては Win32Api.txt にありますが、LookupPrivilegeValueの第三引数はLARGE_INTEGERとして定義されていますが、 C言語ではLUIDへのポインタで宣言されているので 型名を変更しています。または、 この関数の定義を変えないで、LUID構造体名をLARGE_INTEGERとしてもいいかもしれません。
また、AdjustTokenPrivilegesの第五引数についても Win32Api.txt はTOKEN_PRIVILEGE構造体を参照渡しするようになっていますが、今回はこの引数は使用せずNULL(0)を 指定するためにLong型に変更しています。
IsPwrHibernateAllowed、CallNtPowerInformationの両関数については Win32Api.txt にないので、C言語での宣言を参考に作成しています。
構造体は Win32Api.txt にあるのでそのまま使えますが、POWER_INFORMATION_LEVEL列挙体はないので CallNtPowerInformationのドキュメントで確認してください。
ロジックはVC++の場合と同じなので 各APIのドキュメントとともに確認してください。
<2.WMIを使用する・・・対象OS Windows2000, WindowsXP>
VBAの場合は
VC++の時と大違いで楽にできます。
ただやはりスタンバイと休止は自分で実装しないといけないです。ということで
あんまり使えないですが長くないので書いておきます。
前項で使用したブックに新しく標準モジュールを挿入して以下のように記述してください。
Option Explicit 'Public Enum POWER_STATUS ' POWEROFF = 1 ' LOGOFF = 2 ' REBOOT = 3 ' STANDBY = 4 ' HIBER = 5 'End Enum 'WMIによる電源管理(シャットダウン, ログオフ, 再起動のみ) '(スタンバイと休止は不可) '引数 status: POWER_STATUS列挙体の POWEROFF, LOGOFF, REBOOTのいずれか '戻値 成功時 1, 失敗時 0 '参照設定 Microsoft WMI Scripting V1.x Library Public Function GFnControlPowerByWMI(status As POWER_STATUS) As Long Dim vlRet As Long Dim voLocator As WbemScripting.SWbemLocator Dim voServices As WbemScripting.SWbemServices '名前空間 Dim voObjSet As WbemScripting.SWbemObjectSet 'インスタンス群 Dim voObj As WbemScripting.SWbemObject 'インスタンス Dim voInst As WbemScripting.SWbemObject '同上 Dim voInParam As WbemScripting.SWbemObject 'メソッド入力パラメータ Dim voOutParam As WbemScripting.SWbemObject 'メソッド出力パラメータ On Error GoTo ErRoutine Set voLocator = CreateObject("WbemScripting.SWbemLocator") '名前空間に接続 Set voServices = voLocator.ConnectServer(strServer:=".", _ strNamespace:="root\CIMV2") 'シャットダウン特権の追加 voServices.Security_.Privileges.Add wbemPrivilegeShutdown, True 'WIN32_OperatingSystemクラスのインスタンス群を取得 Set voObjSet = voServices.ExecQuery("SELECT * FROM Win32_OperatingSystem") If voObjSet.Count < 1 Then Set voLocator = Nothing: Exit Function End If 'インスタンス取得 For Each voObj In voObjSet Set voInst = voObj: Exit For Next voObj 'Win32Shutdownメソッド用入力パラメータ作成 Set voInParam = voInst.Methods_("Win32Shutdown").InParameters.SpawnInstance_() voInParam.Properties_.Item("Flags").Value = Choose(status, 8, 0, 2) '(A) 'Win32Shutdownメソッド実行 Set voOutParam = voInst.ExecMethod_("Win32Shutdown", voInParam) '出力パラメータvoOutParamの評価 GFnControlPowerByWMI = _ IIf(voOutParam.Properties_("ReturnValue").Value = 0, 1, 0) Set voLocator = Nothing Exit Function ErRoutine: GFnControlPowerByWMI = 0 Set voLocator = Nothing End Function |
保存してGFnControlPowerByWMIを実行してください。
ロジックについてはこちら
と同じなので省略します。
※注(A)
<3.WSH(Windows Script Host)を使用する・・・対象OS Windows XP>
多分、VBAの場合はこれが一番楽そうですが、電源OFF等につかうコマンド shutdown.exeや休止(ハイバーネーション)時使うかもしれないpowercfg.exe はWindows XP以降でしか有効ではないです。
上記二項と同じブックに新しい標準モジュールを追加して以下を記述してください。
Option Explicit 'Public Enum POWER_STATUS ' POWEROFF = 1 ' LOGOFF = 2 ' REBOOT = 3 ' STANDBY = 4 ' HIBER = 5 'End Enum '電源管理(引数に指定した状態に移行) - <WindowsXP以降のみ有効> '引数 argeStatus : 列挙体 POWEROFF, LOGOFF, REBOOT, STANDBY, HIBERのいずれか '戻値 成功 1, 失敗 0 '参照設定 Windows Script Host Object Model(C:\Windows\system32\wshom.ocx) Public Function GFnControlPowerByWSH(argeStatus As POWER_STATUS) As Long Dim voWshShell As IWshRuntimeLibrary.wshshell 'WSH Shellオブジェクト Dim voFso As IWshRuntimeLibrary.FileSystemObject 'FileSystemObjectオブジェクト Dim vsSysFolder As String 'システムフォルダーパス Dim vsCmd As String 'コマンド文字列 On Error GoTo ErRoutine 'OSのバージョン確認 If Val(Mid(Application.OperatingSystem, _ InStrRev(Application.OperatingSystem, " ", -1) + 1)) < 5.01 Then Exit Function End If Set voWshShell = CreateObject("WScript.Shell") Set voFso = CreateObject("Scripting.FileSystemObject") 'システムフォルダパス取得 vsSysFolder = voFso.GetSpecialFolder(SystemFolder).Path If argeStatus <= REBOOT Then 'Poweroff, Logoff, Reboot 'コマンド文字列作成 vsCmd = vsSysFolder & "\shutdown.exe -t 0 " & Choose(argeStatus, "-s", "-l", "-r") Else 'Suspend, Hibernation 'ハイバーネーション有効/無効 vsCmd = "powercfg.exe /H " & IIf((argeStatus = STANDBY), "OFF", "ON") voWshShell.Run vsCmd, 0 'コマンド文字列作成 vsCmd = vsSysFolder & "\Rundll32.exe Powrprof.dll, SetSuspendState" End If 'コマンド実行 voWshShell.Run vsCmd, 0 Set voWshShell = Nothing Set voFso = Nothing GFnControlPowerByWSH = 1 Exit Function ErRoutine: Set voWshShell = Nothing Set voFso = Nothing GFnControlPowerByWSH = 0 End Function |
Windows XP以降であれば、電源OFF、再起動、ログオフはshutdown.exeという ユーティリティがあるのでコンソールから呼び出せます。また、サスペンド、休止に関しては SetSuspenStateというAPIが、Powrprof.dllにあるのですが、Rundll32.exeというユーティリティを 使用すれば呼び出すことができます。これらのコマンドを実行してくれるのがシェルであり、 今回利用しようとしているWSH(Windows Script Host)です。
WSHのWshShellオブジェクトのRunメソッドを使用するとコンソールからコマンドを 実行するのと同様にプログラムを実行できます。
上記のような流れになります。