[DLLS] Fix 64 bit issues
[reactos.git] / dll / win32 / msgina / shutdown.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS msgina.dll
4 * FILE: lib/msgina/shutdown.c
5 * PURPOSE: Shutdown Dialog Box (GUI only)
6 * PROGRAMMERS: Lee Schroeder (spaceseel at gmail dot com)
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 #include "msgina.h"
11 #include <powrprof.h>
12 #include <wingdi.h>
13
14 /* Shutdown state flags */
15 #define WLX_SHUTDOWN_STATE_LOGOFF 0x01
16 #define WLX_SHUTDOWN_STATE_POWER_OFF 0x02
17 #define WLX_SHUTDOWN_STATE_REBOOT 0x04
18 // 0x08
19 #define WLX_SHUTDOWN_STATE_SLEEP 0x10
20 // 0x20
21 #define WLX_SHUTDOWN_STATE_HIBERNATE 0x40
22 // 0x80
23
24 typedef struct _SHUTDOWN_DLG_CONTEXT
25 {
26 PGINA_CONTEXT pgContext;
27 HBITMAP hBitmap;
28 DWORD ShutdownOptions;
29 BOOL bCloseDlg;
30 BOOL bReasonUI;
31 } SHUTDOWN_DLG_CONTEXT, *PSHUTDOWN_DLG_CONTEXT;
32
33
34 static
35 BOOL
36 GetShutdownReasonUI(VOID)
37 {
38 OSVERSIONINFOEX VersionInfo;
39 DWORD dwValue, dwSize;
40 HKEY hKey;
41 LONG lRet;
42
43 /* Query the policy value */
44 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
45 L"Software\\Policies\\Microsoft\\Windows NT\\Reliability",
46 0,
47 KEY_QUERY_VALUE,
48 &hKey);
49 if (lRet == ERROR_SUCCESS)
50 {
51 dwValue = 0;
52 dwSize = sizeof(dwValue);
53 RegQueryValueExW(hKey,
54 L"ShutdownReasonUI",
55 NULL,
56 NULL,
57 (LPBYTE)&dwValue,
58 &dwSize);
59 RegCloseKey(hKey);
60
61 return (dwValue != 0) ? TRUE : FALSE;
62 }
63
64 /* Query the machine value */
65 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
66 L"Software\\Microsoft\\Windows\\CurrentVersion\\Reliability",
67 0,
68 KEY_QUERY_VALUE,
69 &hKey);
70 if (lRet == ERROR_SUCCESS)
71 {
72 dwValue = 0;
73 dwSize = sizeof(dwValue);
74 RegQueryValueExW(hKey,
75 L"ShutdownReasonUI",
76 NULL,
77 NULL,
78 (LPBYTE)&dwValue,
79 &dwSize);
80 RegCloseKey(hKey);
81
82 return (dwValue != 0) ? TRUE : FALSE;
83 }
84
85 /* Return the default value */
86 VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
87 if (!GetVersionEx((POSVERSIONINFO)&VersionInfo))
88 return FALSE;
89
90 return FALSE;
91 // return (VersionInfo.wProductType == VER_NT_WORKSTATION) ? FALSE : TRUE;
92 }
93
94 DWORD
95 GetDefaultShutdownSelState(VOID)
96 {
97 return WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
98 }
99
100 DWORD
101 LoadShutdownSelState(VOID)
102 {
103 LONG lRet;
104 HKEY hKeyCurrentUser, hKey;
105 DWORD dwValue, dwTemp, dwSize;
106
107 /* Default to shutdown */
108 dwValue = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
109
110 /* Open the current user HKCU key */
111 lRet = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser);
112 if (lRet == ERROR_SUCCESS)
113 {
114 /* Open the subkey */
115 lRet = RegOpenKeyExW(hKeyCurrentUser,
116 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
117 0, KEY_QUERY_VALUE, &hKey);
118 RegCloseKey(hKeyCurrentUser);
119 }
120 if (lRet != ERROR_SUCCESS)
121 return dwValue;
122
123 /* Read the value */
124 dwSize = sizeof(dwTemp);
125 lRet = RegQueryValueExW(hKey,
126 L"Shutdown Setting",
127 NULL, NULL,
128 (LPBYTE)&dwTemp, &dwSize);
129 RegCloseKey(hKey);
130
131 if (lRet == ERROR_SUCCESS)
132 {
133 switch (dwTemp)
134 {
135 case WLX_SHUTDOWN_STATE_LOGOFF:
136 dwValue = WLX_SAS_ACTION_LOGOFF;
137 break;
138
139 case WLX_SHUTDOWN_STATE_POWER_OFF:
140 dwValue = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
141 break;
142
143 case WLX_SHUTDOWN_STATE_REBOOT:
144 dwValue = WLX_SAS_ACTION_SHUTDOWN_REBOOT;
145 break;
146
147 // 0x08
148
149 case WLX_SHUTDOWN_STATE_SLEEP:
150 dwValue = WLX_SAS_ACTION_SHUTDOWN_SLEEP;
151 break;
152
153 // 0x20
154
155 case WLX_SHUTDOWN_STATE_HIBERNATE:
156 dwValue = WLX_SAS_ACTION_SHUTDOWN_HIBERNATE;
157 break;
158
159 // 0x80
160 }
161 }
162
163 return dwValue;
164 }
165
166 VOID
167 SaveShutdownSelState(
168 IN DWORD ShutdownCode)
169 {
170 LONG lRet;
171 HKEY hKeyCurrentUser, hKey;
172 DWORD dwValue = 0;
173
174 /* Open the current user HKCU key */
175 lRet = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser);
176 if (lRet == ERROR_SUCCESS)
177 {
178 /* Create the subkey */
179 lRet = RegCreateKeyExW(hKeyCurrentUser,
180 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
181 0, NULL,
182 REG_OPTION_NON_VOLATILE,
183 KEY_SET_VALUE,
184 NULL, &hKey, NULL);
185 RegCloseKey(hKeyCurrentUser);
186 }
187 if (lRet != ERROR_SUCCESS)
188 return;
189
190 switch (ShutdownCode)
191 {
192 case WLX_SAS_ACTION_LOGOFF:
193 dwValue = WLX_SHUTDOWN_STATE_LOGOFF;
194 break;
195
196 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
197 dwValue = WLX_SHUTDOWN_STATE_POWER_OFF;
198 break;
199
200 case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
201 dwValue = WLX_SHUTDOWN_STATE_REBOOT;
202 break;
203
204 case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
205 dwValue = WLX_SHUTDOWN_STATE_SLEEP;
206 break;
207
208 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
209 dwValue = WLX_SHUTDOWN_STATE_HIBERNATE;
210 break;
211 }
212
213 RegSetValueExW(hKey,
214 L"Shutdown Setting",
215 0, REG_DWORD,
216 (LPBYTE)&dwValue, sizeof(dwValue));
217 RegCloseKey(hKey);
218 }
219
220 DWORD
221 GetDefaultShutdownOptions(VOID)
222 {
223 return WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT;
224 }
225
226 DWORD
227 GetAllowedShutdownOptions(VOID)
228 {
229 DWORD Options = 0;
230
231 // FIXME: Compute those options accordings to current user's rights!
232 Options |= WLX_SHUTDOWN_STATE_LOGOFF | WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT;
233
234 if (IsPwrSuspendAllowed())
235 Options |= WLX_SHUTDOWN_STATE_SLEEP;
236
237 if (IsPwrHibernateAllowed())
238 Options |= WLX_SHUTDOWN_STATE_HIBERNATE;
239
240 return Options;
241 }
242
243 static VOID
244 UpdateShutdownDesc(
245 IN HWND hDlg,
246 IN PSHUTDOWN_DLG_CONTEXT pContext) // HINSTANCE hInstance
247 {
248 UINT DescId = 0;
249 DWORD ShutdownCode;
250 WCHAR szBuffer[256];
251
252 ShutdownCode = SendDlgItemMessageW(hDlg, IDC_SHUTDOWN_ACTION, CB_GETCURSEL, 0, 0);
253 if (ShutdownCode == CB_ERR) // Invalid selection
254 return;
255
256 ShutdownCode = SendDlgItemMessageW(hDlg, IDC_SHUTDOWN_ACTION, CB_GETITEMDATA, ShutdownCode, 0);
257
258 switch (ShutdownCode)
259 {
260 case WLX_SAS_ACTION_LOGOFF:
261 DescId = IDS_SHUTDOWN_LOGOFF_DESC;
262 break;
263
264 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
265 DescId = IDS_SHUTDOWN_SHUTDOWN_DESC;
266 break;
267
268 case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
269 DescId = IDS_SHUTDOWN_RESTART_DESC;
270 break;
271
272 case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
273 DescId = IDS_SHUTDOWN_SLEEP_DESC;
274 break;
275
276 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
277 DescId = IDS_SHUTDOWN_HIBERNATE_DESC;
278 break;
279
280 default:
281 break;
282 }
283
284 LoadStringW(pContext->pgContext->hDllInstance, DescId, szBuffer, _countof(szBuffer));
285 SetDlgItemTextW(hDlg, IDC_SHUTDOWN_DESCRIPTION, szBuffer);
286
287 if (pContext->bReasonUI)
288 {
289 EnableWindow(GetDlgItem(hDlg, IDC_REASON_PLANNED), (ShutdownCode != WLX_SAS_ACTION_LOGOFF));
290 EnableWindow(GetDlgItem(hDlg, IDC_REASON_LIST), (ShutdownCode != WLX_SAS_ACTION_LOGOFF));
291 EnableWindow(GetDlgItem(hDlg, IDC_REASON_COMMENT), (ShutdownCode != WLX_SAS_ACTION_LOGOFF));
292 }
293 }
294
295 static VOID
296 ShutdownOnInit(
297 IN HWND hDlg,
298 IN PSHUTDOWN_DLG_CONTEXT pContext)
299 {
300 PGINA_CONTEXT pgContext = pContext->pgContext;
301 HWND hwndList;
302 INT idx, count, i;
303 WCHAR szBuffer[256];
304 WCHAR szBuffer2[256];
305
306 hwndList = GetDlgItem(hDlg, IDC_SHUTDOWN_ACTION);
307
308 /* Clear the content before it's used */
309 SendMessageW(hwndList, CB_RESETCONTENT, 0, 0);
310
311 /* Log off */
312 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_LOGOFF)
313 {
314 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_LOGOFF, szBuffer, _countof(szBuffer));
315 StringCchPrintfW(szBuffer2, _countof(szBuffer2), szBuffer, pgContext->UserName);
316 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer2);
317 if (idx != CB_ERR)
318 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_LOGOFF);
319 }
320
321 /* Shut down - DEFAULT */
322 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_POWER_OFF)
323 {
324 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_SHUTDOWN, szBuffer, _countof(szBuffer));
325 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
326 if (idx != CB_ERR)
327 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
328 }
329
330 /* Restart */
331 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_REBOOT)
332 {
333 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_RESTART, szBuffer, _countof(szBuffer));
334 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
335 if (idx != CB_ERR)
336 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
337 }
338
339 // if (pContext->ShutdownOptions & 0x08) {}
340
341 /* Sleep */
342 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_SLEEP)
343 {
344 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_SLEEP, szBuffer, _countof(szBuffer));
345 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
346 if (idx != CB_ERR)
347 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_SLEEP);
348 }
349
350 // if (pContext->ShutdownOptions & 0x20) {}
351
352 /* Hibernate */
353 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_HIBERNATE)
354 {
355 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_HIBERNATE, szBuffer, _countof(szBuffer));
356 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
357 if (idx != CB_ERR)
358 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_HIBERNATE);
359 }
360
361 // if (pContext->ShutdownOptions & 0x80) {}
362
363 /* Set the default shut down selection */
364 count = SendMessageW(hwndList, CB_GETCOUNT, 0, 0);
365 for (i = 0; i < count; i++)
366 {
367 if (SendMessageW(hwndList, CB_GETITEMDATA, i, 0) == pgContext->nShutdownAction)
368 {
369 SendMessageW(hwndList, CB_SETCURSEL, i, 0);
370 break;
371 }
372 }
373
374 /* Update the choice description based on the current selection */
375 UpdateShutdownDesc(hDlg, pContext);
376 }
377
378 static VOID
379 ShutdownOnOk(
380 IN HWND hDlg,
381 IN PGINA_CONTEXT pgContext)
382 {
383 INT idx;
384
385 idx = SendDlgItemMessageW(hDlg,
386 IDC_SHUTDOWN_ACTION,
387 CB_GETCURSEL,
388 0,
389 0);
390 if (idx != CB_ERR)
391 {
392 pgContext->nShutdownAction =
393 SendDlgItemMessageW(hDlg,
394 IDC_SHUTDOWN_ACTION,
395 CB_GETITEMDATA,
396 idx,
397 0);
398 }
399 }
400
401 static INT_PTR
402 CALLBACK
403 ShutdownDialogProc(
404 HWND hDlg,
405 UINT uMsg,
406 WPARAM wParam,
407 LPARAM lParam)
408 {
409 PSHUTDOWN_DLG_CONTEXT pContext;
410
411 pContext = (PSHUTDOWN_DLG_CONTEXT)GetWindowLongPtrW(hDlg, GWLP_USERDATA);
412
413 switch (uMsg)
414 {
415 case WM_INITDIALOG:
416 {
417 pContext = (PSHUTDOWN_DLG_CONTEXT)lParam;
418 SetWindowLongPtrW(hDlg, GWLP_USERDATA, (LONG_PTR)pContext);
419
420 ShutdownOnInit(hDlg, pContext);
421
422 /* Draw the logo bitmap */
423 pContext->hBitmap =
424 LoadImageW(pContext->pgContext->hDllInstance, MAKEINTRESOURCEW(IDI_ROSLOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
425 return TRUE;
426 }
427
428 case WM_DESTROY:
429 DeleteObject(pContext->hBitmap);
430 return TRUE;
431
432 case WM_ACTIVATE:
433 {
434 /*
435 * If the user deactivates the shutdown dialog (it loses its focus
436 * while the dialog is not being closed), then destroy the dialog
437 * and cancel shutdown.
438 */
439 if (LOWORD(wParam) == WA_INACTIVE)
440 {
441 if (!pContext->bCloseDlg)
442 {
443 pContext->bCloseDlg = TRUE;
444 EndDialog(hDlg, 0);
445 }
446 }
447 return FALSE;
448 }
449
450 case WM_PAINT:
451 {
452 PAINTSTRUCT ps;
453 if (pContext->hBitmap)
454 {
455 BeginPaint(hDlg, &ps);
456 DrawStateW(ps.hdc, NULL, NULL, (LPARAM)pContext->hBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
457 EndPaint(hDlg, &ps);
458 }
459 return TRUE;
460 }
461
462 case WM_CLOSE:
463 pContext->bCloseDlg = TRUE;
464 EndDialog(hDlg, IDCANCEL);
465 break;
466
467 case WM_COMMAND:
468 switch (LOWORD(wParam))
469 {
470 case IDOK:
471 ShutdownOnOk(hDlg, pContext->pgContext);
472
473 /* Fall back */
474 case IDCANCEL:
475 case IDHELP:
476 pContext->bCloseDlg = TRUE;
477 EndDialog(hDlg, LOWORD(wParam));
478 break;
479
480 case IDC_SHUTDOWN_ACTION:
481 UpdateShutdownDesc(hDlg, pContext);
482 break;
483 }
484 break;
485
486 default:
487 return FALSE;
488 }
489 return TRUE;
490 }
491
492 INT_PTR
493 ShutdownDialog(
494 IN HWND hwndDlg,
495 IN DWORD ShutdownOptions,
496 IN PGINA_CONTEXT pgContext)
497 {
498 INT_PTR ret;
499 SHUTDOWN_DLG_CONTEXT Context;
500
501 #if 0
502 DWORD ShutdownOptions;
503
504 // FIXME: User impersonation!!
505 pgContext->nShutdownAction = LoadShutdownSelState();
506 ShutdownOptions = GetAllowedShutdownOptions();
507 #endif
508
509 Context.pgContext = pgContext;
510 Context.ShutdownOptions = ShutdownOptions;
511 Context.bCloseDlg = FALSE;
512 Context.bReasonUI = GetShutdownReasonUI();
513
514 if (pgContext->hWlx && pgContext->pWlxFuncs)
515 {
516 ret = pgContext->pWlxFuncs->WlxDialogBoxParam(pgContext->hWlx,
517 pgContext->hDllInstance,
518 MAKEINTRESOURCEW(Context.bReasonUI ? IDD_SHUTDOWN_REASON : IDD_SHUTDOWN),
519 hwndDlg,
520 ShutdownDialogProc,
521 (LPARAM)&Context);
522 }
523 else
524 {
525 ret = DialogBoxParamW(pgContext->hDllInstance,
526 MAKEINTRESOURCEW(Context.bReasonUI ? IDD_SHUTDOWN_REASON : IDD_SHUTDOWN),
527 hwndDlg,
528 ShutdownDialogProc,
529 (LPARAM)&Context);
530 }
531
532 #if 0
533 // FIXME: User impersonation!!
534 if (ret == IDOK)
535 SaveShutdownSelState(pgContext->nShutdownAction);
536 #endif
537
538 return ret;
539 }
540
541
542 /*
543 * NOTES:
544 * - Based upon observations on the ShellShutdownDialog() function, the function doesn't actually
545 * do anything except show a dialog box and returning a value based upon the value chosen. That
546 * means that any code that calls the function has to execute the chosen action (shut down,
547 * restart, etc.).
548 * - When this function is called in Windows XP, it shows the classic dialog box regardless if
549 * SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\LogonType is enabled or not.
550 * - When the Help button is pushed, it sends the same return value as IDCANCEL (0x00), but
551 * at the same time, it calls the help file directly from the dialog box.
552 * - When the dialog is created, it doesn't disable all other input from the other windows.
553 * This is done elsewhere. When running the function ShellShutdownDialog() from XP/2K3, if the user clicks
554 * out of the window, it automatically closes itself.
555 * - The parameter, lpUsername never seems to be used when calling the function from Windows XP. Either
556 * it was a parameter that was never used in the final version before release, or it has a use that
557 * is currently not known.
558 */
559 DWORD WINAPI
560 ShellShutdownDialog(
561 HWND hParent,
562 LPWSTR lpUsername,
563 BOOL bHideLogoff)
564 {
565 INT_PTR dlgValue;
566 DWORD ShutdownOptions;
567
568 /*
569 * As we are called by the shell itself, don't use
570 * the cached GINA context but use a local copy here.
571 */
572 GINA_CONTEXT gContext = { 0 };
573 DWORD BufferSize;
574
575 UNREFERENCED_PARAMETER(lpUsername);
576
577 ShutdownOptions = GetAllowedShutdownOptions();
578 if (bHideLogoff)
579 ShutdownOptions &= ~WLX_SHUTDOWN_STATE_LOGOFF;
580
581 /* Initialize our local GINA context */
582 gContext.hDllInstance = hDllInstance;
583 BufferSize = _countof(gContext.UserName);
584 // NOTE: Only when this function is called, Win checks inside
585 // HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
586 // value "Logon User Name", and determines whether it will display
587 // the user name.
588 GetUserNameW(gContext.UserName, &BufferSize);
589 gContext.nShutdownAction = LoadShutdownSelState();
590
591 /* Load the shutdown dialog box */
592 dlgValue = ShutdownDialog(hParent, ShutdownOptions, &gContext);
593
594 /* Determine what to do based on user selection */
595 if (dlgValue == IDOK)
596 {
597 SaveShutdownSelState(gContext.nShutdownAction);
598
599 switch (gContext.nShutdownAction)
600 {
601 case WLX_SAS_ACTION_LOGOFF:
602 return WLX_SHUTDOWN_STATE_LOGOFF;
603
604 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
605 return WLX_SHUTDOWN_STATE_POWER_OFF;
606
607 case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
608 return WLX_SHUTDOWN_STATE_REBOOT;
609
610 // 0x08
611
612 case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
613 return WLX_SHUTDOWN_STATE_SLEEP;
614
615 // 0x20
616
617 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
618 return WLX_SHUTDOWN_STATE_HIBERNATE;
619
620 // 0x80
621 }
622 }
623 /* Help file is called directly here */
624 else if (dlgValue == IDHELP)
625 {
626 FIXME("Help is not implemented yet.");
627 MessageBoxW(hParent, L"Help is not implemented yet.", L"Message", MB_OK | MB_ICONEXCLAMATION);
628 }
629 else if (dlgValue == -1)
630 {
631 ERR("Failed to create dialog\n");
632 }
633
634 return 0;
635 }