2010年1月18日月曜日

[WIN]NT系OSでシャットダウンする

これも、定石の一種かもしれませんが...
制御系など、専用システムではOSの振る舞いを極力見せないのが肝要です。
起動は、スタートアップでアプリをダイレクトに起動するのでいいんだけど、終了が問題。
では、単純にExitWindowsEx()を使用してもシャットダウン出来ません。
ヘルプに書かれているように「シャットダウン特権」が必要なのです。
では、その特権をどうやったら得られるか...

それが、下記のコードです。下記コードを少し修正してDLL化してしまえば、VBからでも簡単にシャットダウンできるようになります。
(NT系(NT4.0、2000、XP)では確認済。Vistaや7は試したこと無いけど、UAE回避の手法が必要か?)

BOOL ShutDown(BOOL bReboot, UINT nShutdownTime)
{
    HANDLE hToken;
    TOKEN_PRIVILEGES tkp;
    BOOL fResult;

    // プロセストークンの取得
    if (!OpenProcessToken(GetCurrentProcess(),
        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 
        return FALSE;
        
    // シャットダウン特権の取得
    LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); 
 
    tkp.PrivilegeCount = 1;     // one privilege to set    
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
 
    // このプロセスに対するシャットダウン特権を有効化する
    AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, 
        (PTOKEN_PRIVILEGES) NULL, 0); 

    if (GetLastError() != ERROR_SUCCESS) 
        return FALSE;
 
    // シャットダウンを実行する
    fResult = InitiateSystemShutdown( 
        NULL,
        NULL,
        nShutdownTime,
        FALSE,
        bReboot);

    if (!fResult) 
        return FALSE;
    
    // シャットダウン特権を無効化する
    tkp.Privileges[0].Attributes = 0; 
    AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, 
        (PTOKEN_PRIVILEGES) NULL, 0); 

    if (GetLastError() != ERROR_SUCCESS) 
        return FALSE;

    return TRUE;
}

【注意事項】ここに掲載されている内容について引用流用は自由ですが、内容やサンプルに基づくいかなる結果に関して一切の責任を負いません。自己の責任の上でご活用ください。