InitiateShutdown 関数を使って Windows をシャットダウンするコードは下記のようになります。 シャットダウンをするには SE_SHUTDOWN_NAME 特権を有効にしておく必要があるため AdjustTokenPrivileges 関数を使って特権を有効にしています。 コードでは InitiateShutdown 関数の引数として SHUTDOWN_FORCE_SELF | SHUTDOWN_POWEROFF を渡していますが、SHUTDOWN_RESTART フラグを組み合わせることで再起動させることもできます。

意味
SHUTDOWN_FORCE_OTHERS(0x1) すべてのセッションが強制的にログオフされます。このフラグが設定されておらず、現在のユーザー以外のユーザーがlpMachineNameパラメータで指定されたコンピュータにログオンしている場合、この関数は ERROR_SHUTDOWN_USERS_LOGGED_ONの戻り値で失敗します。
SHUTDOWN_FORCE_SELF(0x2) 発信元のセッションを強制的にログオフすることを指定します。このフラグが設定されていない場合、発信側セッションは対話式にシャットダウンされるため、関数が正常に戻ってもシャットダウンは保証されません。
SHUTDOWN_GRACE_OVERRIDE(0x20) 猶予期間を上書きして、コンピュータがすぐにシャットダウンされるようにします。
SHUTDOWN_HYBRID(0x200) Windows 8 で実行されている初期化シャットダウンから、シャットダウンのオプションを指定するには、この表の 1 つ以上のフラグを含むSHUTDOWN_HYBRIDフラグを含める必要があります。Windows 8 以降では、SHUTDOWN_HYBRIDフラグがない場合は、常に完全なシステムのシャットダウンを開始します。
SHUTDOWN_INSTALL_UPDATES(0x40) コンピュータは、シャットダウンを開始する前に更新プログラムをインストールします。
SHUTDOWN_NOREBOOT(0x10) コンピュータはシャットダウンされていますが、電源が切れたり再起動したりしていません。
SHUTDOWN_POWEROFF(0x8) コンピュータがシャットダウンされ、電源が切れになります。
SHUTDOWN_RESTART(0x4) コンピュータがシャットダウンされ、再起動されます。
SHUTDOWN_RESTARTAPPS(0x80) システムは、EWX_RESTARTAPPS フラグを指定してExitWindowsEx関数を使用して再起動されます。これにより、RegisterApplicationRestart関数を使用して再起動用に登録されているすべてのアプリケーションが再起動されます。

詳しくは、本ページ下記の 参考のリンク先をご参照ください。

プロジェクトのダウンロード

[C++コード]

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

#include <windows.h>

#define DEFAULT_DPI 96
#define SCALEX(X) MulDiv(X, uDpiX, DEFAULT_DPI)
#define SCALEY(Y) MulDiv(Y, uDpiY, DEFAULT_DPI)
#define POINT2PIXEL(PT) MulDiv(PT, uDpiY, 72)

TCHAR szClassName[] = TEXT("Window");

BOOL GetScaling(HWND hWnd, UINT* pnX, UINT* pnY)
{
  BOOL bSetScaling = FALSE;
  const HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
  if (hMonitor)
  {
    HMODULE hShcore = LoadLibrary(TEXT("SHCORE"));
    if (hShcore)
    {
      typedef HRESULT __stdcall GetDpiForMonitor(HMONITOR, int, UINT*, UINT*);
      GetDpiForMonitor* fnGetDpiForMonitor = reinterpret_cast<GetDpiForMonitor*>(GetProcAddress(hShcore, "GetDpiForMonitor"));
      if (fnGetDpiForMonitor)
      {
        UINT uDpiX, uDpiY;
        if (SUCCEEDED(fnGetDpiForMonitor(hMonitor, 0, &uDpiX, &uDpiY)) && uDpiX > 0 && uDpiY > 0)
        {
          *pnX = uDpiX;
          *pnY = uDpiY;
          bSetScaling = TRUE;
        }
      }
      FreeLibrary(hShcore);
    }
  }
  if (!bSetScaling)
  {
    HDC hdc = GetDC(NULL);
    if (hdc)
    {
      *pnX = GetDeviceCaps(hdc, LOGPIXELSX);
      *pnY = GetDeviceCaps(hdc, LOGPIXELSY);
      ReleaseDC(NULL, hdc);
      bSetScaling = TRUE;
    }
  }
  if (!bSetScaling)
  {
    *pnX = DEFAULT_DPI;
    *pnY = DEFAULT_DPI;
    bSetScaling = TRUE;
  }
  return bSetScaling;
}

void Shutdown()
{
  HANDLE hToken = NULL;
  TOKEN_PRIVILEGES tp = { 0 };

  OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
  LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tp.Privileges[0].Luid);

  tp.PrivilegeCount = 1;
  tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

  AdjustTokenPrivileges(hToken, FALSE, &tp, 0, 0, 0);

  InitiateShutdown(0, 0, 0, SHUTDOWN_FORCE_SELF | SHUTDOWN_POWEROFF, 0);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static HWND hButton;
  static HFONT hFont;
  static UINT uDpiX = DEFAULT_DPI, uDpiY = DEFAULT_DPI;
  switch (msg)
  {
  case WM_CREATE:
    hButton = CreateWindow(TEXT("BUTTON"), TEXT("Shutdown"), WS_VISIBLE | WS_CHILD, 0, 0, 0, 0, hWnd, (HMENU)IDOK, ((LPCREATESTRUCT)lParam)->hInstance, 0);
    SendMessage(hWnd, WM_DPICHANGED, 0, 0);
    break;
  case WM_SIZE:
    MoveWindow(hButton, POINT2PIXEL(10), POINT2PIXEL(10), POINT2PIXEL(256), POINT2PIXEL(32), TRUE);
    break;
  case WM_COMMAND:
    if (LOWORD(wParam) == IDOK)
    {
      Shutdown();
    }
    break;
  case WM_NCCREATE:
    {
      const HMODULE hModUser32 = GetModuleHandle(TEXT("user32.dll"));
      if (hModUser32)
      {
        typedef BOOL(WINAPI*fnTypeEnableNCScaling)(HWND);
        const fnTypeEnableNCScaling fnEnableNCScaling = (fnTypeEnableNCScaling)GetProcAddress(hModUser32, "EnableNonClientDpiScaling");
        if (fnEnableNCScaling)
        {
          fnEnableNCScaling(hWnd);
        }
      }
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
  case WM_DPICHANGED:
    GetScaling(hWnd, &uDpiX, &uDpiY);
    DeleteObject(hFont);
    hFont = CreateFontW(-POINT2PIXEL(10), 0, 0, 0, FW_NORMAL, 0, 0, 0, SHIFTJIS_CHARSET, 0, 0, 0, 0, L"MS Shell Dlg");
    SendMessage(hButton, WM_SETFONT, (WPARAM)hFont, 0);
    break;
  case WM_DESTROY:
    DeleteObject(hFont);
    PostQuitMessage(0);
    break;
  default:
    return DefWindowProc(hWnd, msg, wParam, lParam);
  }
  return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR pCmdLine, int nCmdShow)
{
  MSG msg;
  WNDCLASS wndclass = {
    CS_HREDRAW | CS_VREDRAW,
    WndProc,
    0,
    0,
    hInstance,
    0,
    LoadCursor(0,IDC_ARROW),
    (HBRUSH)(COLOR_WINDOW + 1),
    0,
    szClassName
  };
  RegisterClass(&wndclass);
  HWND hWnd = CreateWindow(
    szClassName,
    TEXT("Window"),
    WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
    CW_USEDEFAULT,
    0,
    CW_USEDEFAULT,
    0,
    0,
    0,
    hInstance,
    0
  );
  ShowWindow(hWnd, SW_SHOWDEFAULT);
  UpdateWindow(hWnd);
  while (GetMessage(&msg, 0, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return (int)msg.wParam;
}

その他の方法について

プログラムでWindowsをシャットダウンさせる方法をご紹介しましたが、Windowsの標準のプログラム(コマンド)にshutdown.exeというものがあり、 こちらのコマンドでWindowsをシャットダウンさせることもできます。詳しくは下記のURLをご参照ください。

shutdown.exe とタスクで Windows を自動シャットダウン

参考