Programming Field - Win16 プログラミング

16 ビットでのシャットダウン処理サンプル

このコードは、Win16 と Win32 の双方で利用できるシャットダウンコードです。さらに Win16 下では、実際に実行している OS のバージョンで場合分けを行っています。

※ Win16 環境では必ず thunk16.lib (→ ここに詳細) をインポートしてください。
※ 自分のアプリケーションのコードをそのまま持ってきたため、コメントなどが一部そのままだったり、説明が無い部分もあります。

色分け: Win16 (16 ビット)用Win32 (32 ビット)用

ヘッダー

#ifndef _WIN32
#define _WIN16
#endif

// 独自のシャットダウン フラグ (SDF_FORCE のみ組み合わせ可)
#define SDF_LOGOFF       1
#define SDF_REBOOT       2
#define SDF_SYSREBOOT    3
#define SDF_SHUTDOWN     4
#define SDF_POWEROFF     5
#define SDF_FORCE        0x10

#ifdef _WIN16

#ifndef WINAPIV
#define WINAPIV  CDECL
#endif

extern "C" {
DWORD FAR PASCAL LoadLibraryEx32W(LPCSTR lpszLibFile, DWORD hFile, DWORD dwFlags);
DWORD FAR PASCAL GetProcAddress32W(DWORD hModule, LPCSTR lpszProc);
DWORD FAR PASCAL FreeLibrary32W(DWORD hLibModule);
DWORD FAR WINAPIV CallProcEx32W(DWORD nParams, DWORD fAddressConvert, DWORD lpProcAddress, ... );
DWORD FAR PASCAL GetVDMPointer32W(LPVOID lpPointer, UINT fMode);
}

#define SE_PRIVILEGE_ENABLED_BY_DEFAULT (0x00000001L)
#define SE_PRIVILEGE_ENABLED            (0x00000002L)
#define SE_PRIVILEGE_USED_FOR_ACCESS    (0x80000000L)

#ifndef TEXT
#define TEXT(x)  (x)
#endif
#define SE_SHUTDOWN_NAME                  TEXT("SeShutdownPrivilege")

#define TOKEN_ASSIGN_PRIMARY    (0x0001)
#define TOKEN_DUPLICATE         (0x0002)
#define TOKEN_IMPERSONATE       (0x0004)
#define TOKEN_QUERY             (0x0008)
#define TOKEN_QUERY_SOURCE      (0x0010)
#define TOKEN_ADJUST_PRIVILEGES (0x0020)
#define TOKEN_ADJUST_GROUPS     (0x0040)
#define TOKEN_ADJUST_DEFAULT    (0x0080)
#define TOKEN_ADJUST_SESSIONID  (0x0100)

#define ANYSIZE_ARRAY_32 1       

typedef struct _LUID
{
    DWORD LowPart;
    LONG HighPart;
} LUID, *PLUID;

// #pragma pack(push, 4)
#include <pshpack4.h>

typedef struct _LUID_AND_ATTRIBUTES
{
    LUID Luid;
    DWORD Attributes;
} LUID_AND_ATTRIBUTES, * PLUID_AND_ATTRIBUTES;
typedef LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY_32];
typedef LUID_AND_ATTRIBUTES_ARRAY *PLUID_AND_ATTRIBUTES_ARRAY;

// #pragma pack(pop)
#include <poppack.h>

typedef struct _TOKEN_PRIVILEGES
{
    DWORD PrivilegeCount;
    LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY_32];
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;

#ifndef ERROR_SUCCESS
#define ERROR_SUCCESS                    0L
#endif
#ifndef ERROR_CALL_NOT_IMPLEMENTED
#define ERROR_CALL_NOT_IMPLEMENTED       120L
#endif

// GetWinFlags() の戻り値の 1 つ (Windows NT 下で返される値)
#ifndef WF_WINNT
#define WF_WINNT            0x4000
#endif

#define SYNCHRONIZE                      (0x00100000L)
#define STANDARD_RIGHTS_REQUIRED         (0x000F0000L)
#define PROCESS_ALL_ACCESS               (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF)

#endif

#ifndef EW_RESTARTWINDOWS
#define EW_EXITWINDOWS      0
#define EW_RESTARTWINDOWS   0x42         // Windows のみを再起動
#define EW_REBOOTSYSTEM     0x43         // Windows 終了後、コンピュータを再起動
#endif

#ifndef EWX_LOGOFF
#define EWX_LOGOFF          0
#define EWX_SHUTDOWN        0x00000001
#define EWX_REBOOT          0x00000002
#define EWX_FORCE           0x00000004
#define EWX_POWEROFF        0x00000008
#define EWX_FORCEIFHUNG     0x00000010
#endif

ソース

#include <malloc.h>

#ifdef _WIN16
// 32 ビットの ExitWindowsEx で使うフラグから
// 16 ビットの ExitWindows で使うフラグに変換
static DWORD __stdcall ConvertEWFlag(DWORD dw32Bit)
{
    if (dw32Bit & (EWX_LOGOFF | EWX_POWEROFF | EWX_SHUTDOWN))
        return EW_EXITWINDOWS;

    if (dw32Bit & (EWX_REBOOT))
        return EW_REBOOTSYSTEM;
    
    return EW_EXITWINDOWS;
}
#endif

// uFlags: SDF_ フラグを指定
extern "C" bool __stdcall DoExitWindows(UINT uFlags)
{
    // 16 ビットのみのコード - 32 ビットコードでは不要
#ifdef _WIN16
    DWORD dwVersion;
    BYTE bMajorVersion;

    DWORD dwKernel32;
    DWORD dwUser32;
    DWORD dwAdvapi32;

    // 実行中の Windows のバージョンを取得して、
    // Win16 か Win32 かどうかをチェック
    dwVersion = GetVersion();
    if (GetWinFlags() & WF_WINNT)                 // WinNT 系かどうか
        bMajorVersion = 4;
    else if (HIBYTE(LOWORD(dwVersion)) >= 95)  // Win95 以降かどうか
        bMajorVersion = 4;
    else
        bMajorVersion = 3;                        // Win3.1 など

    if (bMajorVersion >= 4)
    {
        dwKernel32 = LoadLibraryEx32W("kernel32.dll", NULL, 0);
        dwUser32 = LoadLibraryEx32W("user32.dll", NULL, 0);
        dwAdvapi32 = LoadLibraryEx32W("advapi32.dll", NULL, 0);
    }
    else
    {
        dwKernel32 = 0;
        dwUser32 = 0;
        dwAdvapi32 = 0;
    }
#endif

    // SDF_ フラグから EW(X)_ フラグに変換
    DWORD dwFlags = 0;
    bool bSucceeded = false;

    // SDF_FORCE を EWX_FORCE に
    if ((uFlags & SDF_FORCE)
#ifdef _WIN16
        && bMajorVersion >= 4        // Win32 で実行されているかどうか
#endif
        )
    {
        uFlags &= ~(SDF_FORCE);
        dwFlags |= EWX_FORCE;
    }
    switch (uFlags & 0x0F)
    {
        case SDF_LOGOFF:
#ifdef _WIN16
            // Win16 にはログオフは無い
            if (bMajorVersion >= 4)
#endif
            {
                dwFlags |= EWX_LOGOFF;
                break;
            }
        case SDF_POWEROFF:
#ifdef _WIN16
            // Win16 には「電源を切る」は無い
            if (bMajorVersion >= 4)
#endif
                dwFlags |= EWX_POWEROFF;
        case SDF_SHUTDOWN:
#ifdef _WIN16
            if (bMajorVersion >= 4)
#endif
                dwFlags |= EWX_SHUTDOWN;
#ifdef _WIN16
            else
                dwFlags = EW_EXITWINDOWS;
#endif
            break;
        case SDF_SYSREBOOT:
#ifdef _WIN16
            if (bMajorVersion < 4)
            {
                dwFlags |= EW_REBOOTSYSTEM;
                break;
            }
#endif
        case SDF_REBOOT:
#ifdef _WIN16
            if (bMajorVersion >= 4)
#endif
                dwFlags |= EWX_REBOOT;
#ifdef _WIN16
            else
                dwFlags |= EW_RESTARTWINDOWS;
#endif
            break;
    }

#ifdef _WIN16
    if (bMajorVersion >= 4)
    {
        DWORD dwGetCurrentProcess;
        DWORD dwOpenProcessToken;
        DWORD dwGetLastError;
        DWORD dwLookupPrivilegeValue;
        DWORD dwAdjustTokenPrivileges;
        DWORD dwCloseHandle;
        DWORD dwExitWindowsEx;
        bool bRet = true;

        if (dwAdvapi32 && dwKernel32)
        {
            DWORD hProcessMe;
            DWORD hToken;
            TOKEN_PRIVILEGES tkp;
            bool bUseDef = false;

            DWORD dwRet;
            DWORD dwPParam1, dwPParam2;

            dwOpenProcessToken = GetProcAddress32W(dwAdvapi32, "OpenProcessToken");
            dwGetCurrentProcess = GetProcAddress32W(dwKernel32, "GetCurrentProcess");
            dwGetLastError = GetProcAddress32W(dwKernel32, "GetLastError");

            // Get this process handle.
            hProcessMe = CallProcEx32W(0 | CPEX_DEST_STDCALL, 0, dwGetCurrentProcess);

            // Get a token for this process.
            if (dwOpenProcessToken)
            {
                dwPParam1 = GetVDMPointer32W(&hToken, 1);
                dwRet = CallProcEx32W(3 | CPEX_DEST_STDCALL, 0, dwOpenProcessToken,
                    hProcessMe, (DWORD) (TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY), dwPParam1);
            }
            else
                dwRet = 0;
            if (!dwRet)
            {
                if (dwGetLastError)
                {
                    dwRet = CallProcEx32W(0 | CPEX_DEST_STDCALL, 0, dwGetLastError);
                    if (dwRet != ERROR_CALL_NOT_IMPLEMENTED)
                        bRet = false;
                }
            }
            else
            {
                // Get the LUID for the shutdown privilege.
                dwLookupPrivilegeValue = GetProcAddress32W(dwAdvapi32, "LookupPrivilegeValueA");
                dwPParam1 = GetVDMPointer32W(SE_SHUTDOWN_NAME, 1);
                dwPParam2 = GetVDMPointer32W(&tkp.Privileges[0].Luid, 1);
                CallProcEx32W(3 | CPEX_DEST_STDCALL, 0, dwLookupPrivilegeValue,
                    (DWORD) NULL, dwPParam1, dwPParam2);

                tkp.PrivilegeCount = 1;  // one privilege to set
                tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

                // Get the shutdown privilege for this process.
                dwAdjustTokenPrivileges = GetProcAddress32W(dwAdvapi32, "AdjustTokenPrivileges");
                dwPParam1 = GetVDMPointer32W((LPBYTE) &tkp, 1);
                dwRet = CallProcEx32W(6 | CPEX_DEST_STDCALL, 0, dwAdjustTokenPrivileges,
                    hToken, (DWORD) FALSE, dwPParam1, (DWORD) 0, (DWORD) NULL, (DWORD) NULL);

                // Cannot test the return value of AdjustTokenPrivileges.
                dwRet = CallProcEx32W(0 | CPEX_DEST_STDCALL, 0, dwGetLastError);
                if (dwRet != ERROR_SUCCESS)
                    bRet = false;
                dwCloseHandle = GetProcAddress32W(dwKernel32, "CloseHandle");
                CallProcEx32W(1 | CPEX_DEST_STDCALL, 0, dwCloseHandle, hToken);
            }

        }
        if (dwAdvapi32)
            FreeLibrary32W(dwAdvapi32);
        if (dwKernel32)
            FreeLibrary32W(dwKernel32);
        if (bRet)
        {
            if (dwUser32)
            {
                // Call ExitWindowsEx() in USER32.DLL to shutdown
                dwExitWindowsEx = GetProcAddress32W(dwUser32, "ExitWindowsEx");
                bSucceeded = (CallProcEx32W(2 | CPEX_DEST_STDCALL, 0, dwExitWindowsEx, dwFlags, 0) != 0);
            }
            else
                // Couldn't load USER32.DLL, so we call ExitWindows() in USER.EXE.
                bSucceeded = (ExitWindows(ConvertEWFlag(dwFlags), 0) != 0);
        }
        if (dwUser32)
            FreeLibrary32W(dwUser32);
    }
    else
        // Call ExitWindows() in USER.EXE because this program is running under Windows 3.1 or earlier.
        bSucceeded = (ExitWindows(dwFlags, 0) != 0);
#else
    HANDLE hProcessMe;
    HANDLE hToken;
    TOKEN_PRIVILEGES tkp;

    // Get this process handle.
    hProcessMe = GetCurrentProcess();

    // Get a token for this process.
    if (!OpenProcessToken(hProcessMe, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    {
        if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
            goto OnExit;
    }
    else
    {
        // Get the LUID for the shutdown privilege.
        LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);

        tkp.PrivilegeCount = 1;  // one privilege to set
        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

        // Get the shutdown privilege for this process.
        AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);

        // Cannot test the return value of AdjustTokenPrivileges.
        if (GetLastError() != ERROR_SUCCESS)
        {
            CloseHandle(hToken);
            goto OnExit;
        }
        CloseHandle(hToken);
    }
    bSucceeded = (ExitWindowsEx((UINT) dwFlags, 0) != 0);

OnExit:
#endif
    return bSucceeded;
}

最終更新日: 2004/12/25