ReactOS  0.4.15-dev-1152-g6c94e4f
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 
26 typedef struct _SYS_SHUTDOWN_PARAMS
27 {
30 
34 
40 
41 /* GLOBALS *******************************************************************/
42 
44 
45 /* FUNCTIONS *****************************************************************/
46 
47 static
48 BOOL
50  IN PSYS_SHUTDOWN_PARAMS pShutdownParams)
51 {
52  BOOL Success;
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 
70 static
71 VOID
73  IN HWND hwndDlg,
74  IN PSYS_SHUTDOWN_PARAMS pShutdownParams)
75 {
76  HDESK hInputDesktop;
77  BOOL bSuccess;
78  DWORD dwSize;
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 
168 static
169 INT_PTR
170 CALLBACK
172  IN HWND hwndDlg,
173  IN UINT uMsg,
174  IN WPARAM wParam,
175  IN LPARAM lParam)
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:
214  KillTimer(hwndDlg, SHUTDOWN_TIMER_ID);
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 
228 static
229 DWORD
230 WINAPI
233 {
234  PSYS_SHUTDOWN_PARAMS pShutdownParams;
235  HDESK hInputDesktop;
236  DWORD dwSize;
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 
327 DWORD
329 {
332 
333  return ERROR_SUCCESS;
334 }
335 
336 DWORD
338  IN PUNICODE_STRING pMessage,
340  IN BOOLEAN bForceAppsClosed,
341  IN BOOLEAN bRebootAfterShutdown,
342  IN ULONG dwReason)
343 {
344  HANDLE hThread;
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. */
380  if (g_ShutdownParams.dwTimeout == 0)
381  {
383  return ERROR_SUCCESS;
384  }
385  else
386  {
388  &g_ShutdownParams, 0, NULL);
389  if (hThread)
390  {
392  return ERROR_SUCCESS;
393  }
394  }
395 
397  {
400  }
401 
403  return GetLastError();
404 }
405 
406 /* EOF */
#define IDC_SYSSHUTDOWNTIMELEFT
Definition: resource.h:18
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define EWX_FORCE
Definition: winuser.h:630
#define IN
Definition: typedefs.h:39
#define GENERIC_ALL
Definition: nt_native.h:92
WCHAR DesktopName[512]
Definition: shutdown.c:32
#define CloseHandle
Definition: compat.h:487
BOOL WINAPI GetUserObjectInformationW(_In_ HANDLE hObj, _In_ int nIndex, _Out_writes_bytes_opt_(nLength) PVOID pvInfo, _In_ DWORD nLength, _Out_opt_ LPDWORD lpnLengthNeeded)
#define IDABORT
Definition: winuser.h:826
INT_PTR WINAPI DialogBoxParamW(_In_opt_ HINSTANCE, _In_ LPCWSTR, _In_opt_ HWND, _In_opt_ DLGPROC, _In_ LPARAM)
#define MF_BYCOMMAND
Definition: winuser.h:202
#define ERROR_SUCCESS
Definition: deptool.c:10
#define TRUE
Definition: types.h:120
#define IDC_SYSSHUTDOWNMESSAGE
Definition: resource.h:19
uint16_t * PWSTR
Definition: typedefs.h:56
#define IDD_SYSSHUTDOWN
Definition: resource.h:16
#define ERROR_SHUTDOWN_IN_PROGRESS
Definition: winerror.h:651
#define INT
Definition: polytest.cpp:20
#define CALLBACK
Definition: compat.h:35
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1044
#define ZeroMemory
Definition: winbase.h:1648
#define HWND_TOPMOST
Definition: winuser.h:1194
UINT_PTR WPARAM
Definition: windef.h:207
#define GetWindowLongPtrW
Definition: winuser.h:4804
int32_t INT_PTR
Definition: typedefs.h:64
#define EWX_REBOOT
Definition: winuser.h:633
SYS_SHUTDOWN_PARAMS g_ShutdownParams
Definition: shutdown.c:43
#define IDS_TIMEOUTLONGFORMAT
Definition: resource.h:37
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
BOOL WINAPI SetWindowPlacement(_In_ HWND hWnd, _In_ const WINDOWPLACEMENT *)
int32_t INT
Definition: typedefs.h:58
static BOOLEAN bSuccess
Definition: drive.cpp:419
WPARAM wParam
Definition: combotst.c:138
BOOL WINAPI EndDialog(_In_ HWND, _In_ INT_PTR)
char _InterlockedCompareExchange8(_Interlocked_operand_ char volatile *_Destination, char _Exchange, char _Comparand)
BOOL WINAPI SetThreadDesktop(_In_ HDESK)
BOOL WINAPI SetDlgItemTextW(_In_ HWND, _In_ int, _In_ LPCWSTR)
WINDOWPLACEMENT wpPos
Definition: shutdown.c:33
DWORD dwReason
Definition: misc.cpp:154
HDESK WINAPI OpenInputDesktop(_In_ DWORD, _In_ BOOL, _In_ DWORD)
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
#define EWX_SHUTDOWN
Definition: winuser.h:634
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned char BOOLEAN
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:136
HMENU WINAPI GetSystemMenu(_In_ HWND, _In_ BOOL)
smooth NULL
Definition: ftsmooth.c:416
LONG_PTR LPARAM
Definition: windef.h:208
static BOOL DoSystemShutdown(IN PSYS_SHUTDOWN_PARAMS pShutdownParams)
Definition: shutdown.c:49
BOOLEAN bForceAppsClosed
Definition: shutdown.c:37
BOOL WINAPI GetWindowPlacement(_In_ HWND, _Inout_ WINDOWPLACEMENT *)
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define WM_DESTROY
Definition: winuser.h:1591
DWORD StartSystemShutdown(IN PUNICODE_STRING pMessage, IN ULONG dwTimeout, IN BOOLEAN bForceAppsClosed, IN BOOLEAN bRebootAfterShutdown, IN ULONG dwReason)
Definition: shutdown.c:337
DWORD TerminateSystemShutdown(VOID)
Definition: shutdown.c:328
#define TRACE(s)
Definition: solgame.cpp:4
#define GetProcessHeap()
Definition: compat.h:484
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
#define ERROR_NO_SHUTDOWN_IN_PROGRESS
Definition: winerror.h:652
__wchar_t WCHAR
Definition: xmlstorage.h:180
BOOL WINAPI DeleteMenu(_In_ HMENU, _In_ UINT, _In_ UINT)
#define UOI_NAME
Definition: winuser.h:1074
#define WM_TIMER
Definition: winuser.h:1724
#define swprintf(buf, format,...)
Definition: sprintf.c:56
#define WINAPI
Definition: msvc.h:6
unsigned long DWORD
Definition: ntddk_ex.h:95
#define IDS_TIMEOUTSHORTFORMAT
Definition: resource.h:36
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
static INT_PTR CALLBACK ShutdownDialogProc(IN HWND hwndDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam)
Definition: shutdown.c:171
#define DWLP_USER
Definition: winuser.h:866
LPVOID lpParameter
Definition: kernel32.h:241
struct _SYS_SHUTDOWN_PARAMS SYS_SHUTDOWN_PARAMS
struct _SYS_SHUTDOWN_PARAMS * PSYS_SHUTDOWN_PARAMS
BOOL WINAPI ExitWindowsEx(_In_ UINT, _In_ DWORD)
#define SHUTDOWN_TIMER_ID
Definition: shutdown.c:20
#define SWP_NOSIZE
Definition: winuser.h:1230
#define ERR(fmt,...)
Definition: debug.h:110
_In_ void _In_ PCCERT_CONTEXT _In_opt_ LPFILETIME _In_ DWORD _In_ DWORD dwTimeout
Definition: wincrypt.h:6077
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_CRTIMP wchar_t *__cdecl wcsncpy(wchar_t *_Dest, const wchar_t *_Source, size_t _Count)
#define SECONDS_PER_DAY
Definition: shutdown.c:21
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
BOOLEAN bRebootAfterShutdown
Definition: shutdown.c:36
unsigned int UINT
Definition: ndis.h:50
#define SWP_SHOWWINDOW
Definition: winuser.h:1233
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
HANDLE hThread
Definition: wizard.c:27
#define SC_CLOSE
Definition: winuser.h:2567
static DWORD WINAPI InitiateSystemShutdownThread(IN LPVOID lpParameter)
Definition: shutdown.c:231
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
GLuint res
Definition: glext.h:9613
BOOL WINAPI CloseDesktop(_In_ HDESK)
unsigned int ULONG
Definition: retypes.h:1
#define SWP_NOMOVE
Definition: winuser.h:1229
BOOL WINAPI SetWindowPos(_In_ HWND, _In_opt_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ UINT)
#define SetWindowLongPtrW
Definition: winuser.h:5321
#define SECONDS_PER_DECADE
Definition: shutdown.c:22
BOOLEAN bShuttingDown
Definition: shutdown.c:35
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
#define IDCANCEL
Definition: winuser.h:825
#define WM_INITDIALOG
Definition: winuser.h:1721
LPARAM lParam
Definition: combotst.c:139
#define HeapFree(x, y, z)
Definition: compat.h:483
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:54
static VOID OnTimer(IN HWND hwndDlg, IN PSYS_SHUTDOWN_PARAMS pShutdownParams)
Definition: shutdown.c:72
HINSTANCE hAppInstance
Definition: mmc.c:23