71b1f6052bd9ceb93a729a504e8d524a1ea7a639
[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 <ntstrsafe.h>
14 #include <rpc.h>
15 #include <winreg_s.h>
16
17 /* DEFINES *******************************************************************/
18
19 #define IDT_SYSSHUTDOWN 2000
20
21 /* STRUCTS *******************************************************************/
22
23 typedef struct _SYS_SHUTDOWN_PARAMS
24 {
25 UNICODE_STRING usMessage;
26 ULONG dwTimeout;
27 BOOLEAN bRebootAfterShutdown;
28 BOOLEAN bForceAppsClosed;
29 DWORD dwReason;
30
31 HWND hShutdownDialog;
32 BOOLEAN bShuttingDown;
33 } SYS_SHUTDOWN_PARAMS, *PSYS_SHUTDOWN_PARAMS;
34
35 /* GLOBALS *******************************************************************/
36
37 SYS_SHUTDOWN_PARAMS g_ShutdownParams;
38
39 /* FUNCTIONS *****************************************************************/
40
41 static
42 VOID
43 OnTimer(
44 HWND hwndDlg,
45 PSYS_SHUTDOWN_PARAMS pShutdownParams)
46 {
47 WCHAR strbuf[34];
48 INT seconds, minutes, hours;
49
50 seconds = (INT)pShutdownParams->dwTimeout;
51 hours = seconds / 3600;
52 seconds -= hours * 3600;
53 minutes = seconds / 60;
54 seconds -= minutes * 60;
55
56 RtlStringCbPrintfW(strbuf, sizeof(strbuf), L"%d:%d:%d", hours, minutes, seconds);
57 SetDlgItemTextW(hwndDlg, IDC_SHUTDOWNTIMELEFT, strbuf);
58
59 if (pShutdownParams->dwTimeout == 0)
60 {
61 PostMessage(hwndDlg, WM_CLOSE, 0, 0);
62 ExitWindowsEx((pShutdownParams->bRebootAfterShutdown ? EWX_REBOOT : EWX_SHUTDOWN) |
63 (pShutdownParams->bForceAppsClosed ? EWX_FORCE : 0),
64 pShutdownParams->dwReason);
65 }
66
67 pShutdownParams->dwTimeout--;
68 }
69
70
71 static
72 INT_PTR
73 CALLBACK
74 ShutdownDialogProc(
75 HWND hwndDlg,
76 UINT uMsg,
77 WPARAM wParam,
78 LPARAM lParam)
79 {
80 PSYS_SHUTDOWN_PARAMS pShutdownParams;
81
82 pShutdownParams = (PSYS_SHUTDOWN_PARAMS)GetWindowLongPtr(hwndDlg, DWLP_USER);
83
84 switch (uMsg)
85 {
86 case WM_INITDIALOG:
87 pShutdownParams = (PSYS_SHUTDOWN_PARAMS)lParam;
88 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pShutdownParams);
89
90 pShutdownParams->hShutdownDialog = hwndDlg;
91
92 if (pShutdownParams->usMessage.Length)
93 {
94 SetDlgItemTextW(hwndDlg,
95 IDC_SHUTDOWNCOMMENT,
96 pShutdownParams->usMessage.Buffer);
97 }
98 RemoveMenu(GetSystemMenu(hwndDlg, FALSE), SC_CLOSE, MF_BYCOMMAND);
99 SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
100 PostMessage(hwndDlg, WM_TIMER, 0, 0);
101 SetTimer(hwndDlg, IDT_SYSSHUTDOWN, 1000, NULL);
102 break;
103
104 case WM_CLOSE:
105 pShutdownParams->hShutdownDialog = NULL;
106 pShutdownParams->bShuttingDown = FALSE;
107
108 KillTimer(hwndDlg, IDT_SYSSHUTDOWN);
109
110 if (pShutdownParams->usMessage.Buffer)
111 {
112 HeapFree(GetProcessHeap(), 0, pShutdownParams->usMessage.Buffer);
113 RtlInitEmptyUnicodeString(&pShutdownParams->usMessage, NULL, 0);
114 }
115
116 EndDialog(hwndDlg, 0);
117 break;
118
119 case WM_TIMER:
120 OnTimer(hwndDlg, pShutdownParams);
121 break;
122
123 default:
124 return FALSE;
125 }
126
127 return TRUE;
128 }
129
130
131 static
132 DWORD
133 WINAPI
134 InitiateSystemShutdownThread(
135 LPVOID lpParameter)
136 {
137 PSYS_SHUTDOWN_PARAMS pShutdownParams;
138 INT_PTR status;
139
140 pShutdownParams = (PSYS_SHUTDOWN_PARAMS)lpParameter;
141
142 status = DialogBoxParamW(hAppInstance,
143 MAKEINTRESOURCEW(IDD_SYSSHUTDOWN),
144 NULL,
145 ShutdownDialogProc,
146 (LPARAM)pShutdownParams);
147 if (status >= 0)
148 {
149 return ERROR_SUCCESS;
150 }
151
152 if (pShutdownParams->usMessage.Buffer)
153 {
154 HeapFree(GetProcessHeap(), 0, pShutdownParams->usMessage.Buffer);
155 RtlInitEmptyUnicodeString(&pShutdownParams->usMessage, NULL, 0);
156 }
157 pShutdownParams->bShuttingDown = FALSE;
158
159 return GetLastError();
160 }
161
162
163 DWORD
164 TerminateSystemShutdown(VOID)
165 {
166 if (g_ShutdownParams.bShuttingDown == FALSE)
167 return ERROR_NO_SHUTDOWN_IN_PROGRESS;
168
169 return PostMessage(g_ShutdownParams.hShutdownDialog, WM_CLOSE, 0, 0) ? ERROR_SUCCESS : GetLastError();
170 }
171
172
173 DWORD
174 StartSystemShutdown(
175 PUNICODE_STRING lpMessage,
176 ULONG dwTimeout,
177 BOOLEAN bForceAppsClosed,
178 BOOLEAN bRebootAfterShutdown,
179 ULONG dwReason)
180 {
181 HANDLE hThread;
182
183 if (_InterlockedCompareExchange8((volatile char*)&g_ShutdownParams.bShuttingDown, TRUE, FALSE) == TRUE)
184 return ERROR_SHUTDOWN_IN_PROGRESS;
185
186 if (lpMessage && lpMessage->Length && lpMessage->Buffer)
187 {
188 g_ShutdownParams.usMessage.Buffer = HeapAlloc(GetProcessHeap(), 0, lpMessage->Length + sizeof(UNICODE_NULL));
189 if (g_ShutdownParams.usMessage.Buffer == NULL)
190 {
191 g_ShutdownParams.bShuttingDown = FALSE;
192 return GetLastError();
193 }
194
195 RtlInitEmptyUnicodeString(&g_ShutdownParams.usMessage, g_ShutdownParams.usMessage.Buffer, lpMessage->Length + sizeof(UNICODE_NULL));
196 RtlCopyUnicodeString(&(g_ShutdownParams.usMessage), (PUNICODE_STRING)lpMessage);
197 }
198 else
199 {
200 RtlInitEmptyUnicodeString(&g_ShutdownParams.usMessage, NULL, 0);
201 }
202
203 g_ShutdownParams.dwTimeout = dwTimeout;
204 g_ShutdownParams.bForceAppsClosed = bForceAppsClosed;
205 g_ShutdownParams.bRebootAfterShutdown = bRebootAfterShutdown;
206 g_ShutdownParams.dwReason = dwReason;
207
208 hThread = CreateThread(NULL, 0, InitiateSystemShutdownThread, (PVOID)&g_ShutdownParams, 0, NULL);
209 if (hThread)
210 {
211 CloseHandle(hThread);
212 return ERROR_SUCCESS;
213 }
214
215 if (g_ShutdownParams.usMessage.Buffer)
216 {
217 HeapFree(GetProcessHeap(), 0, g_ShutdownParams.usMessage.Buffer);
218 RtlInitEmptyUnicodeString(&g_ShutdownParams.usMessage, NULL, 0);
219 }
220
221 g_ShutdownParams.bShuttingDown = FALSE;
222
223 return GetLastError();
224 }
225
226 /* EOF */