ReactOS 0.4.16-dev-197-g92996da
shutdown.c
Go to the documentation of this file.
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: Edward Bronsten <tanki.alpha5056@gmail.com>
7 * Eric Kohl
8 * Hermes Belusca-Maito
9 */
10
11/* INCLUDES ******************************************************************/
12
13#include "winlogon.h"
14
15#include <rpc.h>
16#include <winreg_s.h>
17
18/* DEFINES *******************************************************************/
19
20#define SHUTDOWN_TIMER_ID 2000
21#define SECONDS_PER_DAY 86400
22#define SECONDS_PER_DECADE 315360000
23
24/* STRUCTS *******************************************************************/
25
27{
30
34
40
41/* GLOBALS *******************************************************************/
42
44
45/* FUNCTIONS *****************************************************************/
46
47static
48BOOL
50 IN PSYS_SHUTDOWN_PARAMS pShutdownParams)
51{
53
54 /* If shutdown has been cancelled, bail out now */
55 if (!pShutdownParams->bShuttingDown)
56 return TRUE;
57
58 Success = ExitWindowsEx((pShutdownParams->bRebootAfterShutdown ? EWX_REBOOT : EWX_SHUTDOWN) |
59 (pShutdownParams->bForceAppsClosed ? EWX_FORCE : 0),
60 pShutdownParams->dwReason);
61 if (!Success)
62 {
63 /* Something went wrong, cancel shutdown */
64 pShutdownParams->bShuttingDown = FALSE;
65 }
66
67 return Success;
68}
69
70static
71VOID
73 IN HWND hwndDlg,
74 IN PSYS_SHUTDOWN_PARAMS pShutdownParams)
75{
76 HDESK hInputDesktop;
79 INT iSeconds, iMinutes, iHours, iDays;
80 WCHAR szFormatBuffer[32];
81 WCHAR szBuffer[32];
82 WCHAR DesktopName[512];
83
84 if (!pShutdownParams->bShuttingDown)
85 {
86 /* Shutdown has been cancelled, close the dialog and bail out */
87 EndDialog(hwndDlg, IDABORT);
88 return;
89 }
90
91 /*
92 * Check whether the input desktop has changed. If so, close the dialog,
93 * and let the shutdown thread recreate it on the new desktop.
94 */
95
96 // TODO: Investigate: It would be great if we could also compare with
97 // our internally maintained desktop handles, before calling that heavy
98 // comparison.
99 // (Note that we cannot compare handles with arbitrary input desktop,
100 // since OpenInputDesktop() creates new handle instances everytime.)
101
102 hInputDesktop = OpenInputDesktop(0, FALSE, GENERIC_ALL);
103 if (!hInputDesktop)
104 {
105 /* No input desktop but we have a dialog: kill it */
106 ERR("OpenInputDesktop() failed, error 0x%lx\n", GetLastError());
107 EndDialog(hwndDlg, 0);
108 return;
109 }
110 bSuccess = GetUserObjectInformationW(hInputDesktop,
111 UOI_NAME,
112 DesktopName,
113 sizeof(DesktopName),
114 &dwSize);
115 if (!bSuccess)
116 {
117 ERR("GetUserObjectInformationW(0x%p) failed, error 0x%lx\n",
118 hInputDesktop, GetLastError());
119 }
120 CloseDesktop(hInputDesktop);
121
122 if (bSuccess && (wcscmp(DesktopName, pShutdownParams->DesktopName) != 0))
123 {
124 TRACE("Input desktop has changed: '%S' --> '%S'\n",
125 pShutdownParams->DesktopName, DesktopName);
126
127 /* Save the original dialog position to be restored later */
128 pShutdownParams->wpPos.length = sizeof(pShutdownParams->wpPos);
129 GetWindowPlacement(hwndDlg, &pShutdownParams->wpPos);
130
131 /* Close the dialog */
132 EndDialog(hwndDlg, IDCANCEL);
133 return;
134 }
135
136 /* Update the shutdown timeout */
137 if (pShutdownParams->dwTimeout < SECONDS_PER_DAY)
138 {
139 iSeconds = (INT)pShutdownParams->dwTimeout;
140 iHours = iSeconds / 3600;
141 iSeconds -= iHours * 3600;
142 iMinutes = iSeconds / 60;
143 iSeconds -= iMinutes * 60;
144
145 LoadStringW(hAppInstance, IDS_TIMEOUTSHORTFORMAT, szFormatBuffer, ARRAYSIZE(szFormatBuffer));
146 swprintf(szBuffer, szFormatBuffer, iHours, iMinutes, iSeconds);
147 }
148 else
149 {
150 iDays = (INT)(pShutdownParams->dwTimeout / SECONDS_PER_DAY);
151
152 LoadStringW(hAppInstance, IDS_TIMEOUTLONGFORMAT, szFormatBuffer, ARRAYSIZE(szFormatBuffer));
153 swprintf(szBuffer, szFormatBuffer, iDays);
154 }
155
156 SetDlgItemTextW(hwndDlg, IDC_SYSSHUTDOWNTIMELEFT, szBuffer);
157
158 if (pShutdownParams->dwTimeout == 0)
159 {
160 /* Close the dialog and let the shutdown thread perform the system shutdown */
161 EndDialog(hwndDlg, 0);
162 return;
163 }
164
165 pShutdownParams->dwTimeout--;
166}
167
168static
172 IN HWND hwndDlg,
173 IN UINT uMsg,
176{
177 PSYS_SHUTDOWN_PARAMS pShutdownParams;
178
179 pShutdownParams = (PSYS_SHUTDOWN_PARAMS)GetWindowLongPtrW(hwndDlg, DWLP_USER);
180
181 switch (uMsg)
182 {
183 case WM_INITDIALOG:
184 {
185 pShutdownParams = (PSYS_SHUTDOWN_PARAMS)lParam;
186 SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)pShutdownParams);
187
188 /* Display the shutdown message */
189 if (pShutdownParams->pszMessage)
190 {
191 SetDlgItemTextW(hwndDlg,
193 pShutdownParams->pszMessage);
194 }
195
196 /* Remove the Close menu item */
198
199 /* Position the window (initial position, or restore from old) */
200 if (pShutdownParams->wpPos.length == sizeof(pShutdownParams->wpPos))
201 SetWindowPlacement(hwndDlg, &pShutdownParams->wpPos);
202
203 SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0,
205
206 /* Initialize the timer */
207 PostMessageW(hwndDlg, WM_TIMER, 0, 0);
208 SetTimer(hwndDlg, SHUTDOWN_TIMER_ID, 1000, NULL);
209 break;
210 }
211
212 /* NOTE: Do not handle WM_CLOSE */
213 case WM_DESTROY:
215 break;
216
217 case WM_TIMER:
218 OnTimer(hwndDlg, pShutdownParams);
219 break;
220
221 default:
222 return FALSE;
223 }
224
225 return TRUE;
226}
227
228static
229DWORD
230WINAPI
232 IN LPVOID lpParameter)
233{
234 PSYS_SHUTDOWN_PARAMS pShutdownParams;
235 HDESK hInputDesktop;
237 INT_PTR res;
238
239 pShutdownParams = (PSYS_SHUTDOWN_PARAMS)lpParameter;
240
241 /* Default to initial dialog position */
242 pShutdownParams->wpPos.length = 0;
243
244 /* Continuously display the shutdown dialog on the current input desktop */
245 while (TRUE)
246 {
247 /* Retrieve the current input desktop */
248 hInputDesktop = OpenInputDesktop(0, FALSE, GENERIC_ALL);
249 if (!hInputDesktop)
250 {
251 /* No input desktop on the current WinSta0, just shut down */
252 ERR("OpenInputDesktop() failed, error 0x%lx\n", GetLastError());
253 break;
254 }
255
256 /* Remember it for checking desktop changes later */
257 pShutdownParams->hShutdownDesk = hInputDesktop;
258 if (!GetUserObjectInformationW(pShutdownParams->hShutdownDesk,
259 UOI_NAME,
260 pShutdownParams->DesktopName,
261 sizeof(pShutdownParams->DesktopName),
262 &dwSize))
263 {
264 ERR("GetUserObjectInformationW(0x%p) failed, error 0x%lx\n",
265 pShutdownParams->hShutdownDesk, GetLastError());
266 }
267
268 /* Assign the desktop to the current thread */
269 SetThreadDesktop(hInputDesktop);
270
271 /* Display the shutdown dialog on the current input desktop */
274 NULL,
276 (LPARAM)pShutdownParams);
277
278 /* Close the desktop */
279 CloseDesktop(hInputDesktop);
280
281 /*
282 * Check why the dialog has been closed.
283 *
284 * - If it failed to be created (returned -1), don't care about
285 * re-creating it, and proceed directly to shutdown.
286 *
287 * - If it closed unexpectedly (returned != 1), check whether a
288 * shutdown is in progress. If the shutdown has been cancelled,
289 * just bail out; if a shutdown is in progress and the timeout
290 * is 0, bail out and proceed to shutdown.
291 *
292 * - If the dialog has closed because the input desktop changed,
293 * loop again and recreate it on the new desktop.
294 */
295 if ((res == -1) || (res != IDCANCEL) ||
296 !(pShutdownParams->bShuttingDown && (pShutdownParams->dwTimeout > 0)))
297 {
298 break;
299 }
300 }
301
302 /* Reset dialog information */
303 pShutdownParams->hShutdownDesk = NULL;
304 ZeroMemory(&pShutdownParams->DesktopName, sizeof(pShutdownParams->DesktopName));
305 ZeroMemory(&pShutdownParams->wpPos, sizeof(pShutdownParams->wpPos));
306
307 if (pShutdownParams->pszMessage)
308 {
309 HeapFree(GetProcessHeap(), 0, pShutdownParams->pszMessage);
310 pShutdownParams->pszMessage = NULL;
311 }
312
313 if (pShutdownParams->bShuttingDown)
314 {
315 /* Perform the system shutdown */
316 if (DoSystemShutdown(pShutdownParams))
317 return ERROR_SUCCESS;
318 else
319 return GetLastError();
320 }
321
322 pShutdownParams->bShuttingDown = FALSE;
323 return ERROR_SUCCESS;
324}
325
326
327DWORD
329{
332
333 return ERROR_SUCCESS;
334}
335
336DWORD
338 IN PUNICODE_STRING pMessage,
340 IN BOOLEAN bForceAppsClosed,
341 IN BOOLEAN bRebootAfterShutdown,
343{
345
346 /* Fail if the timeout is 10 years or more */
349
352
353 if ((dwTimeout != 0) && pMessage && pMessage->Length && pMessage->Buffer)
354 {
357 pMessage->Length + sizeof(UNICODE_NULL));
359 {
361 return GetLastError();
362 }
363
365 pMessage->Buffer,
366 pMessage->Length / sizeof(WCHAR));
367 }
368 else
369 {
371 }
372
374 g_ShutdownParams.bForceAppsClosed = bForceAppsClosed;
375 g_ShutdownParams.bRebootAfterShutdown = bRebootAfterShutdown;
377
378 /* If dwTimeout is zero perform an immediate system shutdown,
379 * otherwise display the countdown shutdown dialog. */
381 {
383 return ERROR_SUCCESS;
384 }
385 else
386 {
389 if (hThread)
390 {
392 return ERROR_SUCCESS;
393 }
394 }
395
397 {
400 }
401
403 return GetLastError();
404}
405
406/* EOF */
unsigned char BOOLEAN
HINSTANCE hAppInstance
Definition: mmc.c:23
#define ERR(fmt,...)
Definition: precomp.h:57
DWORD dwReason
Definition: misc.cpp:141
#define IDC_SYSSHUTDOWNTIMELEFT
Definition: resource.h:18
#define IDD_SYSSHUTDOWN
Definition: resource.h:16
#define IDS_TIMEOUTSHORTFORMAT
Definition: resource.h:36
#define IDS_TIMEOUTLONGFORMAT
Definition: resource.h:37
#define IDC_SYSSHUTDOWNMESSAGE
Definition: resource.h:19
#define SECONDS_PER_DECADE
Definition: shutdown.c:22
static VOID OnTimer(IN HWND hwndDlg, IN PSYS_SHUTDOWN_PARAMS pShutdownParams)
Definition: shutdown.c:72
#define SECONDS_PER_DAY
Definition: shutdown.c:21
static BOOL DoSystemShutdown(IN PSYS_SHUTDOWN_PARAMS pShutdownParams)
Definition: shutdown.c:49
#define SHUTDOWN_TIMER_ID
Definition: shutdown.c:20
struct _SYS_SHUTDOWN_PARAMS SYS_SHUTDOWN_PARAMS
static DWORD WINAPI InitiateSystemShutdownThread(IN LPVOID lpParameter)
Definition: shutdown.c:231
SYS_SHUTDOWN_PARAMS g_ShutdownParams
Definition: shutdown.c:43
static INT_PTR CALLBACK ShutdownDialogProc(IN HWND hwndDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam)
Definition: shutdown.c:171
struct _SYS_SHUTDOWN_PARAMS * PSYS_SHUTDOWN_PARAMS
DWORD TerminateSystemShutdown(VOID)
Definition: shutdown.c:328
DWORD StartSystemShutdown(IN PUNICODE_STRING pMessage, IN ULONG dwTimeout, IN BOOLEAN bForceAppsClosed, IN BOOLEAN bRebootAfterShutdown, IN ULONG dwReason)
Definition: shutdown.c:337
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define CloseHandle
Definition: compat.h:739
#define GetProcessHeap()
Definition: compat.h:736
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define HeapAlloc
Definition: compat.h:733
#define HeapFree(x, y, z)
Definition: compat.h:735
#define CALLBACK
Definition: compat.h:35
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
#define swprintf
Definition: precomp.h:40
static BOOLEAN bSuccess
Definition: drive.cpp:477
@ Success
Definition: eventcreate.c:712
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint res
Definition: glext.h:9613
char _InterlockedCompareExchange8(_Interlocked_operand_ char volatile *_Destination, char _Exchange, char _Comparand)
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:56
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
unsigned int UINT
Definition: ndis.h:50
HANDLE hThread
Definition: wizard.c:28
#define GENERIC_ALL
Definition: nt_native.h:92
#define UNICODE_NULL
#define INT
Definition: polytest.cpp:20
_CRTIMP wchar_t *__cdecl wcsncpy(wchar_t *_Dest, const wchar_t *_Source, size_t _Count)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define TRACE(s)
Definition: solgame.cpp:4
WCHAR DesktopName[512]
Definition: shutdown.c:32
BOOLEAN bShuttingDown
Definition: shutdown.c:35
WINDOWPLACEMENT wpPos
Definition: shutdown.c:33
BOOLEAN bForceAppsClosed
Definition: shutdown.c:37
BOOLEAN bRebootAfterShutdown
Definition: shutdown.c:36
uint16_t * PWSTR
Definition: typedefs.h:56
int32_t INT_PTR
Definition: typedefs.h:64
int32_t INT
Definition: typedefs.h:58
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define ZeroMemory
Definition: winbase.h:1736
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
_In_ void _In_ PCCERT_CONTEXT _In_opt_ LPFILETIME _In_ DWORD _In_ DWORD dwTimeout
Definition: wincrypt.h:6081
LONG_PTR LPARAM
Definition: windef.h:208
UINT_PTR WPARAM
Definition: windef.h:207
#define WINAPI
Definition: msvc.h:6
#define ERROR_NO_SHUTDOWN_IN_PROGRESS
Definition: winerror.h:652
#define ERROR_SHUTDOWN_IN_PROGRESS
Definition: winerror.h:651
#define EWX_SHUTDOWN
Definition: winuser.h:639
#define MF_BYCOMMAND
Definition: winuser.h:202
#define DWLP_USER
Definition: winuser.h:875
#define GetWindowLongPtrW
Definition: winuser.h:4832
#define HWND_TOPMOST
Definition: winuser.h:1211
#define IDCANCEL
Definition: winuser.h:834
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
BOOL WINAPI SetThreadDesktop(_In_ HDESK)
BOOL WINAPI GetWindowPlacement(_In_ HWND, _Inout_ WINDOWPLACEMENT *)
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
BOOL WINAPI SetWindowPos(_In_ HWND, _In_opt_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ UINT)
#define UOI_NAME
Definition: winuser.h:1087
HDESK WINAPI OpenInputDesktop(_In_ DWORD, _In_ BOOL, _In_ DWORD)
#define SWP_NOMOVE
Definition: winuser.h:1247
BOOL WINAPI SetDlgItemTextW(_In_ HWND, _In_ int, _In_ LPCWSTR)
BOOL WINAPI DeleteMenu(_In_ HMENU, _In_ UINT, _In_ UINT)
#define SWP_NOSIZE
Definition: winuser.h:1248
#define WM_INITDIALOG
Definition: winuser.h:1742
HMENU WINAPI GetSystemMenu(_In_ HWND, _In_ BOOL)
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define EWX_REBOOT
Definition: winuser.h:638
#define WM_TIMER
Definition: winuser.h:1745
#define SWP_SHOWWINDOW
Definition: winuser.h:1251
#define EWX_FORCE
Definition: winuser.h:635
#define SC_CLOSE
Definition: winuser.h:2595
#define IDABORT
Definition: winuser.h:835
BOOL WINAPI GetUserObjectInformationW(_In_ HANDLE hObj, _In_ int nIndex, _Out_writes_bytes_opt_(nLength) PVOID pvInfo, _In_ DWORD nLength, _Out_opt_ LPDWORD lpnLengthNeeded)
BOOL WINAPI ExitWindowsEx(_In_ UINT, _In_ DWORD)
#define WM_DESTROY
Definition: winuser.h:1612
BOOL WINAPI CloseDesktop(_In_ HDESK)
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
#define SetWindowLongPtrW
Definition: winuser.h:5358
BOOL WINAPI SetWindowPlacement(_In_ HWND hWnd, _In_ const WINDOWPLACEMENT *)
INT_PTR WINAPI DialogBoxParamW(_In_opt_ HINSTANCE, _In_ LPCWSTR, _In_opt_ HWND, _In_opt_ DLGPROC, _In_ LPARAM)
BOOL WINAPI EndDialog(_In_ HWND, _In_ INT_PTR)
__wchar_t WCHAR
Definition: xmlstorage.h:180