xref: /reactos/base/system/winlogon/shutdown.c (revision cc439606)
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 */
286