d3b86aa1408fd23ccc32479c8ac14d1e93738265
[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 szBuffer[12];
81 INT iSeconds, iMinutes, iHours, iDays;
82
83 if (!pShutdownParams->bShuttingDown)
84 {
85 /* Shutdown has been cancelled, close the dialog and bail out */
86 EndDialog(hwndDlg, 0);
87 return;
88 }
89
90 if (pShutdownParams->dwTimeout < SECONDS_PER_DAY)
91 {
92 iSeconds = (INT)pShutdownParams->dwTimeout;
93 iHours = iSeconds / 3600;
94 iSeconds -= iHours * 3600;
95 iMinutes = iSeconds / 60;
96 iSeconds -= iMinutes * 60;
97
98 swprintf(szBuffer, L"%02d:%02d:%02d", iHours, iMinutes, iSeconds);
99 }
100 else
101 {
102 iDays = (INT)(pShutdownParams->dwTimeout / SECONDS_PER_DAY);
103 swprintf(szBuffer, L"%d days", iDays); // FIXME: Localize
104 }
105
106 SetDlgItemTextW(hwndDlg, IDC_SYSSHUTDOWNTIMELEFT, szBuffer);
107
108 if (pShutdownParams->dwTimeout == 0)
109 {
110 /* Close the dialog and perform the system shutdown */
111 EndDialog(hwndDlg, 0);
112 DoSystemShutdown(pShutdownParams);
113 return;
114 }
115
116 pShutdownParams->dwTimeout--;
117 }
118
119
120 static
121 INT_PTR
122 CALLBACK
123 ShutdownDialogProc(
124 HWND hwndDlg,
125 UINT uMsg,
126 WPARAM wParam,
127 LPARAM lParam)
128 {
129 PSYS_SHUTDOWN_PARAMS pShutdownParams;
130
131 pShutdownParams = (PSYS_SHUTDOWN_PARAMS)GetWindowLongPtr(hwndDlg, DWLP_USER);
132
133 switch (uMsg)
134 {
135 case WM_INITDIALOG:
136 {
137 pShutdownParams = (PSYS_SHUTDOWN_PARAMS)lParam;
138 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pShutdownParams);
139
140 if (pShutdownParams->pszMessage)
141 {
142 SetDlgItemTextW(hwndDlg,
143 IDC_SYSSHUTDOWNMESSAGE,
144 pShutdownParams->pszMessage);
145 }
146
147 DeleteMenu(GetSystemMenu(hwndDlg, FALSE), SC_CLOSE, MF_BYCOMMAND);
148 SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
149
150 PostMessage(hwndDlg, WM_TIMER, 0, 0);
151 SetTimer(hwndDlg, SHUTDOWN_TIMER_ID, 1000, NULL);
152 break;
153 }
154
155 /* NOTE: Do not handle WM_CLOSE */
156 case WM_DESTROY:
157 KillTimer(hwndDlg, SHUTDOWN_TIMER_ID);
158 break;
159
160 case WM_TIMER:
161 OnTimer(hwndDlg, pShutdownParams);
162 break;
163
164 default:
165 return FALSE;
166 }
167
168 return TRUE;
169 }
170
171
172 static
173 DWORD
174 WINAPI
175 InitiateSystemShutdownThread(
176 LPVOID lpParameter)
177 {
178 PSYS_SHUTDOWN_PARAMS pShutdownParams;
179 INT_PTR status;
180
181 pShutdownParams = (PSYS_SHUTDOWN_PARAMS)lpParameter;
182
183 status = DialogBoxParamW(hAppInstance,
184 MAKEINTRESOURCEW(IDD_SYSSHUTDOWN),
185 NULL,
186 ShutdownDialogProc,
187 (LPARAM)pShutdownParams);
188
189 if (pShutdownParams->pszMessage)
190 {
191 HeapFree(GetProcessHeap(), 0, pShutdownParams->pszMessage);
192 pShutdownParams->pszMessage = NULL;
193 }
194
195 if (status >= 0)
196 return ERROR_SUCCESS;
197
198 pShutdownParams->bShuttingDown = FALSE;
199 return GetLastError();
200 }
201
202
203 DWORD
204 TerminateSystemShutdown(VOID)
205 {
206 if (_InterlockedCompareExchange8((volatile char*)&g_ShutdownParams.bShuttingDown, FALSE, TRUE) == FALSE)
207 return ERROR_NO_SHUTDOWN_IN_PROGRESS;
208
209 return ERROR_SUCCESS;
210 }
211
212
213 DWORD
214 StartSystemShutdown(
215 PUNICODE_STRING lpMessage,
216 ULONG dwTimeout,
217 BOOLEAN bForceAppsClosed,
218 BOOLEAN bRebootAfterShutdown,
219 ULONG dwReason)
220 {
221 HANDLE hThread;
222
223 /* Fail if the timeout is 10 years or more */
224 if (dwTimeout >= SECONDS_PER_DECADE)
225 return ERROR_INVALID_PARAMETER;
226
227 if (_InterlockedCompareExchange8((volatile char*)&g_ShutdownParams.bShuttingDown, TRUE, FALSE) == TRUE)
228 return ERROR_SHUTDOWN_IN_PROGRESS;
229
230 if (lpMessage && lpMessage->Length && lpMessage->Buffer)
231 {
232 g_ShutdownParams.pszMessage = HeapAlloc(GetProcessHeap(),
233 HEAP_ZERO_MEMORY,
234 lpMessage->Length + sizeof(UNICODE_NULL));
235 if (g_ShutdownParams.pszMessage == NULL)
236 {
237 g_ShutdownParams.bShuttingDown = FALSE;
238 return GetLastError();
239 }
240
241 wcsncpy(g_ShutdownParams.pszMessage,
242 lpMessage->Buffer,
243 lpMessage->Length / sizeof(WCHAR));
244 }
245 else
246 {
247 g_ShutdownParams.pszMessage = NULL;
248 }
249
250 g_ShutdownParams.dwTimeout = dwTimeout;
251 g_ShutdownParams.bForceAppsClosed = bForceAppsClosed;
252 g_ShutdownParams.bRebootAfterShutdown = bRebootAfterShutdown;
253 g_ShutdownParams.dwReason = dwReason;
254
255 /* If dwTimeout is zero perform an immediate system shutdown, otherwise display the countdown shutdown dialog */
256 if (g_ShutdownParams.dwTimeout == 0)
257 {
258 if (DoSystemShutdown(&g_ShutdownParams))
259 return ERROR_SUCCESS;
260 }
261 else
262 {
263 hThread = CreateThread(NULL, 0, InitiateSystemShutdownThread, (PVOID)&g_ShutdownParams, 0, NULL);
264 if (hThread)
265 {
266 CloseHandle(hThread);
267 return ERROR_SUCCESS;
268 }
269 }
270
271 if (g_ShutdownParams.pszMessage)
272 {
273 HeapFree(GetProcessHeap(), 0, g_ShutdownParams.pszMessage);
274 g_ShutdownParams.pszMessage = NULL;
275 }
276
277 g_ShutdownParams.bShuttingDown = FALSE;
278 return GetLastError();
279 }
280
281 /* EOF */