[WINLOGON] Localize the shutdown timeout
[reactos.git] / base / system / winlogon / shutdown.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Winlogon
4 * FILE: base/system/winlogon/shutdown.c
5 * PURPOSE: System shutdown dialog
6 * PROGRAMMERS: alpha5056 <alpha5056@users.noreply.github.com>
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "winlogon.h"
12
13 #include <rpc.h>
14 #include <winreg_s.h>
15
16 /* DEFINES *******************************************************************/
17
18 #define SHUTDOWN_TIMER_ID 2000
19 #define SECONDS_PER_DAY 86400
20 #define SECONDS_PER_DECADE 315360000
21
22
23 /* STRUCTS *******************************************************************/
24
25 typedef struct _SYS_SHUTDOWN_PARAMS
26 {
27 PWSTR pszMessage;
28 ULONG dwTimeout;
29 BOOLEAN bRebootAfterShutdown;
30 BOOLEAN bForceAppsClosed;
31 DWORD dwReason;
32
33 BOOLEAN bShuttingDown;
34 } SYS_SHUTDOWN_PARAMS, *PSYS_SHUTDOWN_PARAMS;
35
36
37 /* GLOBALS *******************************************************************/
38
39 SYS_SHUTDOWN_PARAMS g_ShutdownParams;
40
41
42 /* FUNCTIONS *****************************************************************/
43
44 static
45 BOOL
46 DoSystemShutdown(
47 IN PSYS_SHUTDOWN_PARAMS pShutdownParams)
48 {
49 BOOL Success;
50
51 if (pShutdownParams->pszMessage)
52 {
53 HeapFree(GetProcessHeap(), 0, pShutdownParams->pszMessage);
54 pShutdownParams->pszMessage = NULL;
55 }
56
57 /* If shutdown has been cancelled, bail out now */
58 if (!pShutdownParams->bShuttingDown)
59 return TRUE;
60
61 Success = ExitWindowsEx((pShutdownParams->bRebootAfterShutdown ? EWX_REBOOT : EWX_SHUTDOWN) |
62 (pShutdownParams->bForceAppsClosed ? EWX_FORCE : 0),
63 pShutdownParams->dwReason);
64 if (!Success)
65 {
66 /* Something went wrong, cancel shutdown */
67 pShutdownParams->bShuttingDown = FALSE;
68 }
69
70 return Success;
71 }
72
73
74 static
75 VOID
76 OnTimer(
77 HWND hwndDlg,
78 PSYS_SHUTDOWN_PARAMS pShutdownParams)
79 {
80 WCHAR szFormatBuffer[32];
81 WCHAR szBuffer[32];
82 INT iSeconds, iMinutes, iHours, iDays;
83
84 if (!pShutdownParams->bShuttingDown)
85 {
86 /* Shutdown has been cancelled, close the dialog and bail out */
87 EndDialog(hwndDlg, 0);
88 return;
89 }
90
91 if (pShutdownParams->dwTimeout < SECONDS_PER_DAY)
92 {
93 iSeconds = (INT)pShutdownParams->dwTimeout;
94 iHours = iSeconds / 3600;
95 iSeconds -= iHours * 3600;
96 iMinutes = iSeconds / 60;
97 iSeconds -= iMinutes * 60;
98
99 LoadStringW(hAppInstance, IDS_TIMEOUTSHORTFORMAT, szFormatBuffer, ARRAYSIZE(szFormatBuffer));
100 swprintf(szBuffer, szFormatBuffer, iHours, iMinutes, iSeconds);
101 }
102 else
103 {
104 iDays = (INT)(pShutdownParams->dwTimeout / SECONDS_PER_DAY);
105
106 LoadStringW(hAppInstance, IDS_TIMEOUTLONGFORMAT, szFormatBuffer, ARRAYSIZE(szFormatBuffer));
107 swprintf(szBuffer, szFormatBuffer, iDays);
108 }
109
110 SetDlgItemTextW(hwndDlg, IDC_SYSSHUTDOWNTIMELEFT, szBuffer);
111
112 if (pShutdownParams->dwTimeout == 0)
113 {
114 /* Close the dialog and perform the system shutdown */
115 EndDialog(hwndDlg, 0);
116 DoSystemShutdown(pShutdownParams);
117 return;
118 }
119
120 pShutdownParams->dwTimeout--;
121 }
122
123
124 static
125 INT_PTR
126 CALLBACK
127 ShutdownDialogProc(
128 HWND hwndDlg,
129 UINT uMsg,
130 WPARAM wParam,
131 LPARAM lParam)
132 {
133 PSYS_SHUTDOWN_PARAMS pShutdownParams;
134
135 pShutdownParams = (PSYS_SHUTDOWN_PARAMS)GetWindowLongPtr(hwndDlg, DWLP_USER);
136
137 switch (uMsg)
138 {
139 case WM_INITDIALOG:
140 {
141 pShutdownParams = (PSYS_SHUTDOWN_PARAMS)lParam;
142 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pShutdownParams);
143
144 if (pShutdownParams->pszMessage)
145 {
146 SetDlgItemTextW(hwndDlg,
147 IDC_SYSSHUTDOWNMESSAGE,
148 pShutdownParams->pszMessage);
149 }
150
151 DeleteMenu(GetSystemMenu(hwndDlg, FALSE), SC_CLOSE, MF_BYCOMMAND);
152 SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
153
154 PostMessage(hwndDlg, WM_TIMER, 0, 0);
155 SetTimer(hwndDlg, SHUTDOWN_TIMER_ID, 1000, NULL);
156 break;
157 }
158
159 /* NOTE: Do not handle WM_CLOSE */
160 case WM_DESTROY:
161 KillTimer(hwndDlg, SHUTDOWN_TIMER_ID);
162 break;
163
164 case WM_TIMER:
165 OnTimer(hwndDlg, pShutdownParams);
166 break;
167
168 default:
169 return FALSE;
170 }
171
172 return TRUE;
173 }
174
175
176 static
177 DWORD
178 WINAPI
179 InitiateSystemShutdownThread(
180 LPVOID lpParameter)
181 {
182 PSYS_SHUTDOWN_PARAMS pShutdownParams;
183 INT_PTR status;
184
185 pShutdownParams = (PSYS_SHUTDOWN_PARAMS)lpParameter;
186
187 status = DialogBoxParamW(hAppInstance,
188 MAKEINTRESOURCEW(IDD_SYSSHUTDOWN),
189 NULL,
190 ShutdownDialogProc,
191 (LPARAM)pShutdownParams);
192
193 if (pShutdownParams->pszMessage)
194 {
195 HeapFree(GetProcessHeap(), 0, pShutdownParams->pszMessage);
196 pShutdownParams->pszMessage = NULL;
197 }
198
199 if (status >= 0)
200 return ERROR_SUCCESS;
201
202 pShutdownParams->bShuttingDown = FALSE;
203 return GetLastError();
204 }
205
206
207 DWORD
208 TerminateSystemShutdown(VOID)
209 {
210 if (_InterlockedCompareExchange8((volatile char*)&g_ShutdownParams.bShuttingDown, FALSE, TRUE) == FALSE)
211 return ERROR_NO_SHUTDOWN_IN_PROGRESS;
212
213 return ERROR_SUCCESS;
214 }
215
216
217 DWORD
218 StartSystemShutdown(
219 PUNICODE_STRING lpMessage,
220 ULONG dwTimeout,
221 BOOLEAN bForceAppsClosed,
222 BOOLEAN bRebootAfterShutdown,
223 ULONG dwReason)
224 {
225 HANDLE hThread;
226
227 /* Fail if the timeout is 10 years or more */
228 if (dwTimeout >= SECONDS_PER_DECADE)
229 return ERROR_INVALID_PARAMETER;
230
231 if (_InterlockedCompareExchange8((volatile char*)&g_ShutdownParams.bShuttingDown, TRUE, FALSE) == TRUE)
232 return ERROR_SHUTDOWN_IN_PROGRESS;
233
234 if (lpMessage && lpMessage->Length && lpMessage->Buffer)
235 {
236 g_ShutdownParams.pszMessage = HeapAlloc(GetProcessHeap(),
237 HEAP_ZERO_MEMORY,
238 lpMessage->Length + sizeof(UNICODE_NULL));
239 if (g_ShutdownParams.pszMessage == NULL)
240 {
241 g_ShutdownParams.bShuttingDown = FALSE;
242 return GetLastError();
243 }
244
245 wcsncpy(g_ShutdownParams.pszMessage,
246 lpMessage->Buffer,
247 lpMessage->Length / sizeof(WCHAR));
248 }
249 else
250 {
251 g_ShutdownParams.pszMessage = NULL;
252 }
253
254 g_ShutdownParams.dwTimeout = dwTimeout;
255 g_ShutdownParams.bForceAppsClosed = bForceAppsClosed;
256 g_ShutdownParams.bRebootAfterShutdown = bRebootAfterShutdown;
257 g_ShutdownParams.dwReason = dwReason;
258
259 /* If dwTimeout is zero perform an immediate system shutdown, otherwise display the countdown shutdown dialog */
260 if (g_ShutdownParams.dwTimeout == 0)
261 {
262 if (DoSystemShutdown(&g_ShutdownParams))
263 return ERROR_SUCCESS;
264 }
265 else
266 {
267 hThread = CreateThread(NULL, 0, InitiateSystemShutdownThread, (PVOID)&g_ShutdownParams, 0, NULL);
268 if (hThread)
269 {
270 CloseHandle(hThread);
271 return ERROR_SUCCESS;
272 }
273 }
274
275 if (g_ShutdownParams.pszMessage)
276 {
277 HeapFree(GetProcessHeap(), 0, g_ShutdownParams.pszMessage);
278 g_ShutdownParams.pszMessage = NULL;
279 }
280
281 g_ShutdownParams.bShuttingDown = FALSE;
282 return GetLastError();
283 }
284
285 /* EOF */