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 * Arnav Bhatt (arnavbhatt288 at gmail dot com) 9 */ 10 11 #include "msgina.h" 12 #include <powrprof.h> 13 #include <wingdi.h> 14 #include <windowsx.h> 15 #include <commctrl.h> 16 17 /* Shutdown state flags */ 18 #define WLX_SHUTDOWN_STATE_LOGOFF 0x01 19 #define WLX_SHUTDOWN_STATE_POWER_OFF 0x02 20 #define WLX_SHUTDOWN_STATE_REBOOT 0x04 21 // 0x08 22 #define WLX_SHUTDOWN_STATE_SLEEP 0x10 23 // 0x20 24 #define WLX_SHUTDOWN_STATE_HIBERNATE 0x40 25 // 0x80 26 27 /* Macros for fancy shut down dialog */ 28 #define FONT_POINT_SIZE 13 29 30 #define DARK_GREY_COLOR RGB(244, 244, 244) 31 #define LIGHT_GREY_COLOR RGB(38, 38, 38) 32 33 /* Bitmap's size for buttons */ 34 #define CX_BITMAP 33 35 #define CY_BITMAP 33 36 37 #define NUMBER_OF_BUTTONS 4 38 39 /* After determining the button as well as its state paint the image strip bitmap using these predefined positions */ 40 #define BUTTON_SHUTDOWN 0 41 #define BUTTON_SHUTDOWN_PRESSED (CY_BITMAP + BUTTON_SHUTDOWN) 42 #define BUTTON_SHUTDOWN_FOCUSED (CY_BITMAP + BUTTON_SHUTDOWN_PRESSED) 43 #define BUTTON_REBOOT (CY_BITMAP + BUTTON_SHUTDOWN_FOCUSED) 44 #define BUTTON_REBOOT_PRESSED (CY_BITMAP + BUTTON_REBOOT) 45 #define BUTTON_REBOOT_FOCUSED (CY_BITMAP + BUTTON_REBOOT_PRESSED) 46 #define BUTTON_SLEEP (CY_BITMAP + BUTTON_REBOOT_FOCUSED) 47 #define BUTTON_SLEEP_PRESSED (CY_BITMAP + BUTTON_SLEEP) 48 #define BUTTON_SLEEP_FOCUSED (CY_BITMAP + BUTTON_SLEEP_PRESSED) 49 #define BUTTON_SLEEP_DISABLED (CY_BITMAP + BUTTON_SLEEP_FOCUSED) 50 51 /* For bIsButtonHot */ 52 #define SHUTDOWN_BUTTON_HOT 0 53 #define REBOOT_BUTTON_HOT 1 54 #define SLEEP_BUTTON_HOT 2 55 #define HIBERNATE_BUTTON_HOT 3 56 57 typedef struct _SHUTDOWN_DLG_CONTEXT 58 { 59 PGINA_CONTEXT pgContext; 60 HBITMAP hBitmap; 61 HBITMAP hImageStrip; 62 DWORD ShutdownDialogId; 63 DWORD ShutdownOptions; 64 HBRUSH hBrush; 65 HFONT hfFont; 66 BOOL bCloseDlg; 67 BOOL bIsSleepButtonReplaced; 68 BOOL bReasonUI; 69 BOOL bFriendlyUI; 70 BOOL bIsButtonHot[NUMBER_OF_BUTTONS]; 71 BOOL bTimer; 72 UINT_PTR iTimer; 73 WNDPROC OldButtonProc; 74 } SHUTDOWN_DLG_CONTEXT, *PSHUTDOWN_DLG_CONTEXT; 75 76 static 77 BOOL 78 GetShutdownReasonUI(VOID) 79 { 80 OSVERSIONINFOEX VersionInfo; 81 DWORD dwValue, dwSize; 82 HKEY hKey; 83 LONG lRet; 84 85 /* Query the policy value */ 86 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 87 L"Software\\Policies\\Microsoft\\Windows NT\\Reliability", 88 0, 89 KEY_QUERY_VALUE, 90 &hKey); 91 if (lRet == ERROR_SUCCESS) 92 { 93 dwValue = 0; 94 dwSize = sizeof(dwValue); 95 RegQueryValueExW(hKey, 96 L"ShutdownReasonUI", 97 NULL, 98 NULL, 99 (LPBYTE)&dwValue, 100 &dwSize); 101 RegCloseKey(hKey); 102 103 return (dwValue != 0) ? TRUE : FALSE; 104 } 105 106 /* Query the machine value */ 107 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 108 L"Software\\Microsoft\\Windows\\CurrentVersion\\Reliability", 109 0, 110 KEY_QUERY_VALUE, 111 &hKey); 112 if (lRet == ERROR_SUCCESS) 113 { 114 dwValue = 0; 115 dwSize = sizeof(dwValue); 116 RegQueryValueExW(hKey, 117 L"ShutdownReasonUI", 118 NULL, 119 NULL, 120 (LPBYTE)&dwValue, 121 &dwSize); 122 RegCloseKey(hKey); 123 124 return (dwValue != 0) ? TRUE : FALSE; 125 } 126 127 /* Return the default value */ 128 VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo); 129 if (!GetVersionEx((POSVERSIONINFO)&VersionInfo)) 130 return FALSE; 131 132 return FALSE; 133 // return (VersionInfo.wProductType == VER_NT_WORKSTATION) ? FALSE : TRUE; 134 } 135 136 static 137 BOOL 138 IsFriendlyUIActive(VOID) 139 { 140 DWORD dwType, dwValue, dwSize; 141 HKEY hKey; 142 LONG lRet; 143 144 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 145 L"SYSTEM\\CurrentControlSet\\Control\\Windows", 146 0, 147 KEY_QUERY_VALUE, 148 &hKey); 149 if (lRet != ERROR_SUCCESS) 150 return FALSE; 151 152 /* CORE-17282 First check an optional ReactOS specific override, that Windows does not check. 153 We use this to allow users pairing 'Server'-configuration with FriendlyShutdown. 154 Otherwise users would have to change CSDVersion or LogonType (side-effects AppCompat) */ 155 dwValue = 0; 156 dwSize = sizeof(dwValue); 157 lRet = RegQueryValueExW(hKey, 158 L"EnforceFriendlyShutdown", 159 NULL, 160 &dwType, 161 (LPBYTE)&dwValue, 162 &dwSize); 163 164 if (lRet == ERROR_SUCCESS && dwType == REG_DWORD && dwValue == 0x1) 165 { 166 RegCloseKey(hKey); 167 return TRUE; 168 } 169 170 /* Check product version number */ 171 dwValue = 0; 172 dwSize = sizeof(dwValue); 173 lRet = RegQueryValueExW(hKey, 174 L"CSDVersion", 175 NULL, 176 &dwType, 177 (LPBYTE)&dwValue, 178 &dwSize); 179 RegCloseKey(hKey); 180 181 if (lRet != ERROR_SUCCESS || dwType != REG_DWORD || dwValue != 0x300) 182 { 183 /* Allow Friendly UI only on Workstation */ 184 return FALSE; 185 } 186 187 /* Check LogonType value */ 188 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 189 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 190 0, 191 KEY_QUERY_VALUE, 192 &hKey); 193 if (lRet != ERROR_SUCCESS) 194 return FALSE; 195 196 dwValue = 0; 197 dwSize = sizeof(dwValue); 198 lRet = RegQueryValueExW(hKey, 199 L"LogonType", 200 NULL, 201 &dwType, 202 (LPBYTE)&dwValue, 203 &dwSize); 204 RegCloseKey(hKey); 205 206 if (lRet != ERROR_SUCCESS || dwType != REG_DWORD) 207 return FALSE; 208 209 return (dwValue != 0); 210 } 211 212 static 213 BOOL 214 IsDomainMember(VOID) 215 { 216 UNIMPLEMENTED; 217 return FALSE; 218 } 219 220 static 221 BOOL 222 IsNetwareActive(VOID) 223 { 224 UNIMPLEMENTED; 225 return FALSE; 226 } 227 228 static 229 BOOL 230 IsShowHibernateButtonActive(VOID) 231 { 232 INT_PTR lRet; 233 HKEY hKey; 234 DWORD dwValue, dwSize; 235 236 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 237 L"SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Shutdown", 238 0, KEY_QUERY_VALUE, &hKey); 239 if (lRet == ERROR_SUCCESS) 240 { 241 dwValue = 0; 242 dwSize = sizeof(dwValue); 243 244 lRet = RegQueryValueExW(hKey, 245 L"ShowHibernateButton", 246 NULL, NULL, 247 (LPBYTE)&dwValue, &dwSize); 248 RegCloseKey(hKey); 249 if (lRet != ERROR_SUCCESS) 250 { 251 return FALSE; 252 } 253 return (dwValue != 0); 254 } 255 return FALSE; 256 } 257 258 static 259 BOOL 260 ForceFriendlyUI(VOID) 261 { 262 DWORD dwType, dwValue, dwSize; 263 HKEY hKey; 264 LONG lRet; 265 266 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 267 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", 268 0, 269 KEY_QUERY_VALUE, 270 &hKey); 271 if (lRet == ERROR_SUCCESS) 272 { 273 dwValue = 0; 274 dwSize = sizeof(dwValue); 275 lRet = RegQueryValueExW(hKey, 276 L"ForceFriendlyUI", 277 NULL, 278 &dwType, 279 (LPBYTE)&dwValue, 280 &dwSize); 281 RegCloseKey(hKey); 282 283 if (lRet == ERROR_SUCCESS && dwType == REG_DWORD) 284 return (dwValue != 0); 285 } 286 287 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 288 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 289 0, 290 KEY_QUERY_VALUE, 291 &hKey); 292 if (lRet == ERROR_SUCCESS) 293 { 294 dwValue = 0; 295 dwSize = sizeof(dwValue); 296 lRet = RegQueryValueExW(hKey, 297 L"ForceFriendlyUI", 298 NULL, 299 &dwType, 300 (LPBYTE)&dwValue, 301 &dwSize); 302 303 RegCloseKey(hKey); 304 305 if (lRet == ERROR_SUCCESS && dwType == REG_DWORD) 306 return (dwValue != 0); 307 } 308 309 return FALSE; 310 } 311 312 static 313 BOOL 314 DrawIconOnOwnerDrawnButtons( 315 DRAWITEMSTRUCT* pdis, 316 PSHUTDOWN_DLG_CONTEXT pContext) 317 { 318 BOOL bRet; 319 HDC hdcMem; 320 HBITMAP hbmOld; 321 int y; 322 RECT rect; 323 324 hdcMem = CreateCompatibleDC(pdis->hDC); 325 hbmOld = SelectObject(hdcMem, pContext->hImageStrip); 326 rect = pdis->rcItem; 327 328 /* Check the button ID for revelant bitmap to be used */ 329 switch (pdis->CtlID) 330 { 331 case IDC_BUTTON_SHUTDOWN: 332 { 333 switch (pdis->itemAction) 334 { 335 case ODA_DRAWENTIRE: 336 case ODA_FOCUS: 337 case ODA_SELECT: 338 { 339 y = BUTTON_SHUTDOWN; 340 if (pdis->itemState & ODS_SELECTED) 341 { 342 y = BUTTON_SHUTDOWN_PRESSED; 343 } 344 else if (pContext->bIsButtonHot[SHUTDOWN_BUTTON_HOT] || (pdis->itemState & ODS_FOCUS)) 345 { 346 y = BUTTON_SHUTDOWN_FOCUSED; 347 } 348 break; 349 } 350 } 351 break; 352 } 353 354 case IDC_BUTTON_REBOOT: 355 { 356 switch (pdis->itemAction) 357 { 358 case ODA_DRAWENTIRE: 359 case ODA_FOCUS: 360 case ODA_SELECT: 361 { 362 y = BUTTON_REBOOT; 363 if (pdis->itemState & ODS_SELECTED) 364 { 365 y = BUTTON_REBOOT_PRESSED; 366 } 367 else if (pContext->bIsButtonHot[REBOOT_BUTTON_HOT] || (pdis->itemState & ODS_FOCUS)) 368 { 369 y = BUTTON_REBOOT_FOCUSED; 370 } 371 break; 372 } 373 } 374 break; 375 } 376 377 case IDC_BUTTON_HIBERNATE: 378 case IDC_BUTTON_SLEEP: 379 { 380 switch (pdis->itemAction) 381 { 382 case ODA_DRAWENTIRE: 383 case ODA_FOCUS: 384 case ODA_SELECT: 385 { 386 y = BUTTON_SLEEP; 387 if (pdis->itemState & ODS_DISABLED) 388 { 389 y = BUTTON_SLEEP_DISABLED; 390 } 391 else if (pdis->itemState & ODS_SELECTED) 392 { 393 y = BUTTON_SLEEP_PRESSED; 394 } 395 else if ((pdis->CtlID == IDC_BUTTON_SLEEP && pContext->bIsButtonHot[SLEEP_BUTTON_HOT]) || 396 (pdis->CtlID == IDC_BUTTON_HIBERNATE && pContext->bIsButtonHot[HIBERNATE_BUTTON_HOT]) || 397 (pdis->itemState & ODS_FOCUS)) 398 { 399 y = BUTTON_SLEEP_FOCUSED; 400 } 401 break; 402 } 403 } 404 break; 405 } 406 } 407 408 /* Draw it on the required button */ 409 bRet = BitBlt(pdis->hDC, 410 (rect.right - rect.left - CX_BITMAP) / 2, 411 (rect.bottom - rect.top - CY_BITMAP) / 2, 412 CX_BITMAP, CY_BITMAP, hdcMem, 0, y, SRCCOPY); 413 414 SelectObject(hdcMem, hbmOld); 415 DeleteDC(hdcMem); 416 417 return bRet; 418 } 419 420 BOOL 421 WINAPI 422 ShellIsFriendlyUIActive(VOID) 423 { 424 BOOL bActive; 425 426 bActive = IsFriendlyUIActive(); 427 428 if ((IsDomainMember() || IsNetwareActive()) && !ForceFriendlyUI()) 429 return FALSE; 430 431 return bActive; 432 } 433 434 DWORD 435 GetDefaultShutdownSelState(VOID) 436 { 437 return WLX_SAS_ACTION_SHUTDOWN_POWER_OFF; 438 } 439 440 DWORD 441 LoadShutdownSelState(VOID) 442 { 443 LONG lRet; 444 HKEY hKeyCurrentUser, hKey; 445 DWORD dwValue, dwTemp, dwSize; 446 447 /* Default to shutdown */ 448 dwValue = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF; 449 450 /* Open the current user HKCU key */ 451 lRet = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser); 452 if (lRet == ERROR_SUCCESS) 453 { 454 /* Open the subkey */ 455 lRet = RegOpenKeyExW(hKeyCurrentUser, 456 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", 457 0, KEY_QUERY_VALUE, &hKey); 458 RegCloseKey(hKeyCurrentUser); 459 } 460 if (lRet != ERROR_SUCCESS) 461 return dwValue; 462 463 /* Read the value */ 464 dwSize = sizeof(dwTemp); 465 lRet = RegQueryValueExW(hKey, 466 L"Shutdown Setting", 467 NULL, NULL, 468 (LPBYTE)&dwTemp, &dwSize); 469 RegCloseKey(hKey); 470 471 if (lRet == ERROR_SUCCESS) 472 { 473 switch (dwTemp) 474 { 475 case WLX_SHUTDOWN_STATE_LOGOFF: 476 dwValue = WLX_SAS_ACTION_LOGOFF; 477 break; 478 479 case WLX_SHUTDOWN_STATE_POWER_OFF: 480 dwValue = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF; 481 break; 482 483 case WLX_SHUTDOWN_STATE_REBOOT: 484 dwValue = WLX_SAS_ACTION_SHUTDOWN_REBOOT; 485 break; 486 487 // 0x08 488 489 case WLX_SHUTDOWN_STATE_SLEEP: 490 dwValue = WLX_SAS_ACTION_SHUTDOWN_SLEEP; 491 break; 492 493 // 0x20 494 495 case WLX_SHUTDOWN_STATE_HIBERNATE: 496 dwValue = WLX_SAS_ACTION_SHUTDOWN_HIBERNATE; 497 break; 498 499 // 0x80 500 } 501 } 502 503 return dwValue; 504 } 505 506 static INT_PTR 507 CALLBACK 508 OwnerDrawButtonSubclass( 509 HWND hButton, 510 UINT uMsg, 511 WPARAM wParam, 512 LPARAM lParam) 513 { 514 PSHUTDOWN_DLG_CONTEXT pContext; 515 pContext = (PSHUTDOWN_DLG_CONTEXT)GetWindowLongPtrW(GetParent(hButton), GWLP_USERDATA); 516 int buttonID = GetDlgCtrlID(hButton); 517 518 switch (uMsg) 519 { 520 case WM_MOUSEMOVE: 521 { 522 HWND hwndTarget; 523 POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; 524 525 if (GetCapture() != hButton) 526 { 527 SetCapture(hButton); 528 if (buttonID == IDC_BUTTON_SHUTDOWN) 529 { 530 pContext->bIsButtonHot[SHUTDOWN_BUTTON_HOT] = TRUE; 531 } 532 else if (buttonID == IDC_BUTTON_REBOOT) 533 { 534 pContext->bIsButtonHot[REBOOT_BUTTON_HOT] = TRUE; 535 } 536 else if (buttonID == IDC_BUTTON_SLEEP) 537 { 538 pContext->bIsButtonHot[SLEEP_BUTTON_HOT] = TRUE; 539 } 540 else if (buttonID == IDC_BUTTON_HIBERNATE) 541 { 542 pContext->bIsButtonHot[HIBERNATE_BUTTON_HOT] = TRUE; 543 } 544 SetCursor(LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_HAND))); 545 } 546 547 ClientToScreen(hButton, &pt); 548 hwndTarget = WindowFromPoint(pt); 549 550 if (hwndTarget != hButton) 551 { 552 ReleaseCapture(); 553 if (buttonID == IDC_BUTTON_SHUTDOWN) 554 { 555 pContext->bIsButtonHot[SHUTDOWN_BUTTON_HOT] = FALSE; 556 } 557 else if (buttonID == IDC_BUTTON_REBOOT) 558 { 559 pContext->bIsButtonHot[REBOOT_BUTTON_HOT] = FALSE; 560 } 561 else if (buttonID == IDC_BUTTON_SLEEP) 562 { 563 pContext->bIsButtonHot[SLEEP_BUTTON_HOT] = FALSE; 564 } 565 else if (buttonID == IDC_BUTTON_HIBERNATE) 566 { 567 pContext->bIsButtonHot[HIBERNATE_BUTTON_HOT] = FALSE; 568 } 569 } 570 InvalidateRect(hButton, NULL, FALSE); 571 break; 572 } 573 574 /* Whenever one of the buttons gets the keyboard focus, set it as default button */ 575 case WM_SETFOCUS: 576 { 577 SendMessageW(GetParent(hButton), DM_SETDEFID, buttonID, 0); 578 break; 579 } 580 581 /* Otherwise, set IDCANCEL as default button */ 582 case WM_KILLFOCUS: 583 { 584 SendMessageW(GetParent(hButton), DM_SETDEFID, IDCANCEL, 0); 585 break; 586 } 587 } 588 return CallWindowProcW(pContext->OldButtonProc, hButton, uMsg, wParam, lParam); 589 } 590 591 VOID 592 CreateToolTipForButtons( 593 int controlID, 594 int detailID, 595 HWND hDlg, 596 int titleID, 597 HINSTANCE hInst) 598 { 599 HWND hwndTool, hwndTip; 600 WCHAR szBuffer[256]; 601 TTTOOLINFOW tool; 602 603 hwndTool = GetDlgItem(hDlg, controlID); 604 605 tool.cbSize = sizeof(tool); 606 tool.hwnd = hDlg; 607 tool.uFlags = TTF_IDISHWND | TTF_SUBCLASS; 608 tool.uId = (UINT_PTR)hwndTool; 609 610 /* Create the tooltip */ 611 hwndTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 612 WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON, 613 CW_USEDEFAULT, CW_USEDEFAULT, 614 CW_USEDEFAULT, CW_USEDEFAULT, 615 hDlg, NULL, hInst, NULL); 616 617 /* Associate the tooltip with the tool. */ 618 LoadStringW(hInst, detailID, szBuffer, _countof(szBuffer)); 619 tool.lpszText = szBuffer; 620 SendMessageW(hwndTip, TTM_ADDTOOLW, 0, (LPARAM)&tool); 621 LoadStringW(hInst, titleID, szBuffer, _countof(szBuffer)); 622 SendMessageW(hwndTip, TTM_SETTITLEW, TTI_NONE, (LPARAM)szBuffer); 623 SendMessageW(hwndTip, TTM_SETMAXTIPWIDTH, 0, 250); 624 } 625 626 VOID 627 EndFriendlyDialog( 628 HWND hDlg, 629 PSHUTDOWN_DLG_CONTEXT pContext) 630 { 631 if (pContext->bTimer) 632 { 633 KillTimer(hDlg, pContext->iTimer); 634 } 635 636 DeleteObject(pContext->hBitmap); 637 DeleteObject(pContext->hBrush); 638 DeleteObject(pContext->hImageStrip); 639 DeleteObject(pContext->hfFont); 640 641 /* Remove the subclass from the buttons */ 642 for (int i = 0; i < NUMBER_OF_BUTTONS; i++) 643 { 644 SetWindowLongPtrW(GetDlgItem(hDlg, IDC_BUTTON_SHUTDOWN + i), 645 GWLP_WNDPROC, 646 (LONG_PTR)pContext->OldButtonProc); 647 } 648 } 649 650 VOID 651 ChangeRequiredButton( 652 HWND hDlg, 653 PSHUTDOWN_DLG_CONTEXT pContext) 654 { 655 int destID = IDC_BUTTON_SLEEP; 656 int targetedID = IDC_BUTTON_HIBERNATE; 657 HWND hwndDest, hwndTarget; 658 RECT rect; 659 WCHAR szBuffer[30]; 660 661 /* If the sleep button has been already replaced earlier, bring sleep button back to its original position */ 662 if (pContext->bIsSleepButtonReplaced) 663 { 664 destID = IDC_BUTTON_HIBERNATE; 665 targetedID = IDC_BUTTON_SLEEP; 666 } 667 668 hwndDest = GetDlgItem(hDlg, destID); 669 hwndTarget = GetDlgItem(hDlg, targetedID); 670 671 /* Get the position of the destination button */ 672 GetWindowRect(hwndDest, &rect); 673 674 /* Get the corrected translated coordinates which is relative to the client window */ 675 MapWindowPoints(HWND_DESKTOP, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT)); 676 677 /* Set the position of targeted button and hide the destination button */ 678 SetWindowPos(hwndTarget, 679 HWND_TOP, 680 rect.left, rect.top, 681 0, 0, 682 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 683 684 EnableWindow(hwndDest, FALSE); 685 ShowWindow(hwndDest, SW_HIDE); 686 EnableWindow(hwndTarget, TRUE); 687 ShowWindow(hwndTarget, SW_SHOW); 688 SetFocus(hwndTarget); 689 690 if (!pContext->bIsSleepButtonReplaced) 691 { 692 LoadStringW(pContext->pgContext->hDllInstance, IDS_SHUTDOWN_HIBERNATE, szBuffer, _countof(szBuffer)); 693 SetDlgItemTextW(hDlg, IDC_SLEEP_STATIC, szBuffer); 694 } 695 else 696 { 697 LoadStringW(pContext->pgContext->hDllInstance, IDS_SHUTDOWN_SLEEP, szBuffer, _countof(szBuffer)); 698 SetDlgItemTextW(hDlg, IDC_SLEEP_STATIC, szBuffer); 699 } 700 701 InvalidateRect(hDlg, NULL, FALSE); 702 } 703 704 VOID OnTimer( 705 HWND hDlg, 706 PSHUTDOWN_DLG_CONTEXT pContext) 707 { 708 BOOL ReplaceButton = !!(GetKeyState(VK_SHIFT) & 0x8000); 709 710 if (ReplaceButton && !pContext->bIsSleepButtonReplaced) 711 { 712 ChangeRequiredButton(hDlg, pContext); 713 pContext->bIsSleepButtonReplaced = TRUE; 714 } 715 else if (!ReplaceButton && pContext->bIsSleepButtonReplaced) 716 { 717 ChangeRequiredButton(hDlg, pContext); 718 pContext->bIsSleepButtonReplaced = FALSE; 719 } 720 } 721 722 VOID 723 SaveShutdownSelState( 724 IN DWORD ShutdownCode) 725 { 726 LONG lRet; 727 HKEY hKeyCurrentUser, hKey; 728 DWORD dwValue = 0; 729 730 /* Open the current user HKCU key */ 731 lRet = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser); 732 if (lRet == ERROR_SUCCESS) 733 { 734 /* Create the subkey */ 735 lRet = RegCreateKeyExW(hKeyCurrentUser, 736 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", 737 0, NULL, 738 REG_OPTION_NON_VOLATILE, 739 KEY_SET_VALUE, 740 NULL, &hKey, NULL); 741 RegCloseKey(hKeyCurrentUser); 742 } 743 if (lRet != ERROR_SUCCESS) 744 return; 745 746 switch (ShutdownCode) 747 { 748 case WLX_SAS_ACTION_LOGOFF: 749 dwValue = WLX_SHUTDOWN_STATE_LOGOFF; 750 break; 751 752 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF: 753 dwValue = WLX_SHUTDOWN_STATE_POWER_OFF; 754 break; 755 756 case WLX_SAS_ACTION_SHUTDOWN_REBOOT: 757 dwValue = WLX_SHUTDOWN_STATE_REBOOT; 758 break; 759 760 case WLX_SAS_ACTION_SHUTDOWN_SLEEP: 761 dwValue = WLX_SHUTDOWN_STATE_SLEEP; 762 break; 763 764 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE: 765 dwValue = WLX_SHUTDOWN_STATE_HIBERNATE; 766 break; 767 } 768 769 RegSetValueExW(hKey, 770 L"Shutdown Setting", 771 0, REG_DWORD, 772 (LPBYTE)&dwValue, sizeof(dwValue)); 773 RegCloseKey(hKey); 774 } 775 776 DWORD 777 GetDefaultShutdownOptions(VOID) 778 { 779 return WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT; 780 } 781 782 DWORD 783 GetAllowedShutdownOptions(VOID) 784 { 785 DWORD Options = 0; 786 787 // FIXME: Compute those options accordings to current user's rights! 788 Options |= WLX_SHUTDOWN_STATE_LOGOFF | WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT; 789 790 if (IsPwrSuspendAllowed()) 791 Options |= WLX_SHUTDOWN_STATE_SLEEP; 792 793 if (IsPwrHibernateAllowed()) 794 Options |= WLX_SHUTDOWN_STATE_HIBERNATE; 795 796 return Options; 797 } 798 799 static VOID 800 UpdateShutdownDesc( 801 IN HWND hDlg, 802 IN PSHUTDOWN_DLG_CONTEXT pContext) // HINSTANCE hInstance 803 { 804 UINT DescId = 0; 805 DWORD ShutdownCode; 806 WCHAR szBuffer[256]; 807 808 ShutdownCode = SendDlgItemMessageW(hDlg, IDC_SHUTDOWN_ACTION, CB_GETCURSEL, 0, 0); 809 if (ShutdownCode == CB_ERR) // Invalid selection 810 return; 811 812 ShutdownCode = SendDlgItemMessageW(hDlg, IDC_SHUTDOWN_ACTION, CB_GETITEMDATA, ShutdownCode, 0); 813 814 switch (ShutdownCode) 815 { 816 case WLX_SAS_ACTION_LOGOFF: 817 DescId = IDS_SHUTDOWN_LOGOFF_DESC; 818 break; 819 820 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF: 821 DescId = IDS_SHUTDOWN_SHUTDOWN_DESC; 822 break; 823 824 case WLX_SAS_ACTION_SHUTDOWN_REBOOT: 825 DescId = IDS_SHUTDOWN_RESTART_DESC; 826 break; 827 828 case WLX_SAS_ACTION_SHUTDOWN_SLEEP: 829 DescId = IDS_SHUTDOWN_SLEEP_DESC; 830 break; 831 832 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE: 833 DescId = IDS_SHUTDOWN_HIBERNATE_DESC; 834 break; 835 836 default: 837 break; 838 } 839 840 LoadStringW(pContext->pgContext->hDllInstance, DescId, szBuffer, _countof(szBuffer)); 841 SetDlgItemTextW(hDlg, IDC_SHUTDOWN_DESCRIPTION, szBuffer); 842 843 if (pContext->bReasonUI) 844 { 845 EnableWindow(GetDlgItem(hDlg, IDC_REASON_PLANNED), (ShutdownCode != WLX_SAS_ACTION_LOGOFF)); 846 EnableWindow(GetDlgItem(hDlg, IDC_REASON_LIST), (ShutdownCode != WLX_SAS_ACTION_LOGOFF)); 847 EnableWindow(GetDlgItem(hDlg, IDC_REASON_COMMENT), (ShutdownCode != WLX_SAS_ACTION_LOGOFF)); 848 } 849 } 850 851 static VOID 852 ShutdownOnFriendlyInit( 853 IN HWND hDlg, 854 IN PSHUTDOWN_DLG_CONTEXT pContext) 855 { 856 PGINA_CONTEXT pgContext = pContext->pgContext; 857 HDC hdc; 858 LONG lfHeight; 859 860 /* Create font for the IDC_TURN_OFF_STATIC static control */ 861 hdc = GetDC(hDlg); 862 lfHeight = -MulDiv(FONT_POINT_SIZE, GetDeviceCaps(hdc, LOGPIXELSY), 72); 863 ReleaseDC(hDlg, hdc); 864 pContext->hfFont = CreateFontW(lfHeight, 0, 0, 0, FW_MEDIUM, FALSE, 0, 0, 0, 0, 0, 0, 0, L"MS Shell Dlg"); 865 SendDlgItemMessageW(hDlg, IDC_TURN_OFF_STATIC, WM_SETFONT, (WPARAM)pContext->hfFont, TRUE); 866 867 /* Create a brush for static controls for fancy shut down dialog */ 868 pContext->hBrush = CreateSolidBrush(DARK_GREY_COLOR); 869 870 /* Gather image strip */ 871 pContext->hImageStrip = LoadBitmapW(pgContext->hDllInstance, MAKEINTRESOURCEW(IDB_IMAGE_STRIP)); 872 873 /* Set the boolean flags to false */ 874 pContext->bIsSleepButtonReplaced = FALSE; 875 pContext->bTimer = FALSE; 876 877 EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_HIBERNATE), FALSE); 878 EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_SLEEP), IsPwrSuspendAllowed()); 879 880 /* Gather old button func */ 881 pContext->OldButtonProc = (WNDPROC)GetWindowLongPtrW(GetDlgItem(hDlg, IDC_BUTTON_HIBERNATE), GWLP_WNDPROC); 882 883 /* Set bIsButtonHot to false, create tooltips for each buttons, make buttons to remember pContext and subclass the buttons */ 884 for (int i = 0; i < NUMBER_OF_BUTTONS; i++) 885 { 886 pContext->bIsButtonHot[i] = FALSE; 887 SetWindowLongPtrW(GetDlgItem(hDlg, IDC_BUTTON_SHUTDOWN + i), 888 GWLP_WNDPROC, 889 (LONG_PTR)OwnerDrawButtonSubclass); 890 CreateToolTipForButtons(IDC_BUTTON_SHUTDOWN + i, 891 IDS_SHUTDOWN_SHUTDOWN_DESC + i, 892 hDlg, IDS_SHUTDOWN_SHUTDOWN + i, 893 pContext->pgContext->hDllInstance); 894 } 895 896 if (pContext->ShutdownDialogId == IDD_SHUTDOWN_FANCY && IsPwrSuspendAllowed()) 897 { 898 pContext->iTimer = SetTimer(hDlg, 0, 50, NULL); 899 pContext->bTimer = TRUE; 900 } 901 } 902 903 static VOID 904 ShutdownOnInit( 905 IN HWND hDlg, 906 IN PSHUTDOWN_DLG_CONTEXT pContext) 907 { 908 PGINA_CONTEXT pgContext = pContext->pgContext; 909 HWND hwndList; 910 INT idx, count, i; 911 WCHAR szBuffer[256]; 912 WCHAR szBuffer2[256]; 913 914 if (pContext->bFriendlyUI) 915 { 916 ShutdownOnFriendlyInit(hDlg, pContext); 917 return; 918 } 919 920 hwndList = GetDlgItem(hDlg, IDC_SHUTDOWN_ACTION); 921 922 /* Clear the content before it's used */ 923 SendMessageW(hwndList, CB_RESETCONTENT, 0, 0); 924 925 /* Log off */ 926 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_LOGOFF) 927 { 928 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_LOGOFF, szBuffer, _countof(szBuffer)); 929 StringCchPrintfW(szBuffer2, _countof(szBuffer2), szBuffer, pgContext->UserName); 930 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer2); 931 if (idx != CB_ERR) 932 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_LOGOFF); 933 } 934 935 /* Shut down - DEFAULT */ 936 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_POWER_OFF) 937 { 938 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_SHUTDOWN, szBuffer, _countof(szBuffer)); 939 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer); 940 if (idx != CB_ERR) 941 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_POWER_OFF); 942 } 943 944 /* Restart */ 945 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_REBOOT) 946 { 947 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_RESTART, szBuffer, _countof(szBuffer)); 948 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer); 949 if (idx != CB_ERR) 950 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_REBOOT); 951 } 952 953 // if (pContext->ShutdownOptions & 0x08) {} 954 955 /* Sleep */ 956 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_SLEEP) 957 { 958 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_SLEEP, szBuffer, _countof(szBuffer)); 959 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer); 960 if (idx != CB_ERR) 961 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_SLEEP); 962 } 963 964 // if (pContext->ShutdownOptions & 0x20) {} 965 966 /* Hibernate */ 967 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_HIBERNATE) 968 { 969 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_HIBERNATE, szBuffer, _countof(szBuffer)); 970 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer); 971 if (idx != CB_ERR) 972 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_HIBERNATE); 973 } 974 975 // if (pContext->ShutdownOptions & 0x80) {} 976 977 /* Set the default shut down selection */ 978 count = SendMessageW(hwndList, CB_GETCOUNT, 0, 0); 979 for (i = 0; i < count; i++) 980 { 981 if (SendMessageW(hwndList, CB_GETITEMDATA, i, 0) == pgContext->nShutdownAction) 982 { 983 SendMessageW(hwndList, CB_SETCURSEL, i, 0); 984 break; 985 } 986 } 987 988 /* Update the choice description based on the current selection */ 989 UpdateShutdownDesc(hDlg, pContext); 990 } 991 992 static VOID 993 ShutdownOnOk( 994 IN HWND hDlg, 995 IN PGINA_CONTEXT pgContext) 996 { 997 INT idx; 998 999 idx = SendDlgItemMessageW(hDlg, 1000 IDC_SHUTDOWN_ACTION, 1001 CB_GETCURSEL, 1002 0, 1003 0); 1004 if (idx != CB_ERR) 1005 { 1006 pgContext->nShutdownAction = 1007 SendDlgItemMessageW(hDlg, 1008 IDC_SHUTDOWN_ACTION, 1009 CB_GETITEMDATA, 1010 idx, 1011 0); 1012 } 1013 } 1014 1015 static INT_PTR 1016 CALLBACK 1017 ShutdownDialogProc( 1018 HWND hDlg, 1019 UINT uMsg, 1020 WPARAM wParam, 1021 LPARAM lParam) 1022 { 1023 PSHUTDOWN_DLG_CONTEXT pContext; 1024 1025 pContext = (PSHUTDOWN_DLG_CONTEXT)GetWindowLongPtrW(hDlg, GWLP_USERDATA); 1026 1027 switch (uMsg) 1028 { 1029 case WM_INITDIALOG: 1030 { 1031 pContext = (PSHUTDOWN_DLG_CONTEXT)lParam; 1032 SetWindowLongPtrW(hDlg, GWLP_USERDATA, (LONG_PTR)pContext); 1033 1034 ShutdownOnInit(hDlg, pContext); 1035 return TRUE; 1036 } 1037 1038 case WM_DESTROY: 1039 if (pContext->bFriendlyUI) 1040 { 1041 EndFriendlyDialog(hDlg, pContext); 1042 } 1043 return TRUE; 1044 1045 case WM_ACTIVATE: 1046 { 1047 /* 1048 * If the user deactivates the shutdown dialog (it loses its focus 1049 * while the dialog is not being closed), then destroy the dialog 1050 * and cancel shutdown. 1051 */ 1052 if (LOWORD(wParam) == WA_INACTIVE) 1053 { 1054 if (!pContext->bCloseDlg) 1055 { 1056 pContext->bCloseDlg = TRUE; 1057 EndDialog(hDlg, IDCANCEL); 1058 } 1059 } 1060 return FALSE; 1061 } 1062 1063 case WM_CLOSE: 1064 pContext->bCloseDlg = TRUE; 1065 EndDialog(hDlg, IDCANCEL); 1066 break; 1067 1068 case WM_COMMAND: 1069 switch (LOWORD(wParam)) 1070 { 1071 case IDC_BUTTON_SHUTDOWN: 1072 ExitWindowsEx(EWX_SHUTDOWN, SHTDN_REASON_MAJOR_OTHER); 1073 break; 1074 1075 case IDC_BUTTON_REBOOT: 1076 ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_OTHER); 1077 break; 1078 1079 case IDC_BUTTON_SLEEP: 1080 SetSuspendState(TRUE, TRUE, TRUE); 1081 break; 1082 1083 case IDOK: 1084 ShutdownOnOk(hDlg, pContext->pgContext); 1085 1086 /* Fall back */ 1087 case IDCANCEL: 1088 case IDHELP: 1089 pContext->bCloseDlg = TRUE; 1090 EndDialog(hDlg, LOWORD(wParam)); 1091 break; 1092 1093 case IDC_SHUTDOWN_ACTION: 1094 UpdateShutdownDesc(hDlg, pContext); 1095 break; 1096 } 1097 break; 1098 1099 case WM_CTLCOLORSTATIC: 1100 { 1101 /* Either make background transparent or fill it with color for required static controls */ 1102 HDC hdcStatic = (HDC)wParam; 1103 UINT StaticID = (UINT)GetWindowLongPtrW((HWND)lParam, GWL_ID); 1104 1105 switch (StaticID) 1106 { 1107 case IDC_TURN_OFF_STATIC: 1108 SetTextColor(hdcStatic, DARK_GREY_COLOR); 1109 SetBkMode(hdcStatic, TRANSPARENT); 1110 return (INT_PTR)GetStockObject(HOLLOW_BRUSH); 1111 1112 case IDC_HIBERNATE_STATIC: 1113 case IDC_SHUTDOWN_STATIC: 1114 case IDC_SLEEP_STATIC: 1115 case IDC_RESTART_STATIC: 1116 SetTextColor(hdcStatic, LIGHT_GREY_COLOR); 1117 SetBkMode(hdcStatic, TRANSPARENT); 1118 return (LONG_PTR)pContext->hBrush; 1119 } 1120 return FALSE; 1121 } 1122 1123 case WM_DRAWITEM: 1124 { 1125 /* Draw bitmaps on required buttons */ 1126 DRAWITEMSTRUCT* pdis = (DRAWITEMSTRUCT*)lParam; 1127 switch (pdis->CtlID) 1128 { 1129 case IDC_BUTTON_SHUTDOWN: 1130 case IDC_BUTTON_REBOOT: 1131 case IDC_BUTTON_SLEEP: 1132 case IDC_BUTTON_HIBERNATE: 1133 return DrawIconOnOwnerDrawnButtons(pdis, pContext); 1134 } 1135 break; 1136 } 1137 1138 case WM_TIMER: 1139 OnTimer(hDlg, pContext); 1140 return TRUE; 1141 1142 default: 1143 return FALSE; 1144 } 1145 return TRUE; 1146 } 1147 1148 INT_PTR 1149 ShutdownDialog( 1150 IN HWND hwndDlg, 1151 IN DWORD ShutdownOptions, 1152 IN PGINA_CONTEXT pgContext) 1153 { 1154 INT_PTR ret; 1155 SHUTDOWN_DLG_CONTEXT Context; 1156 1157 #if 0 1158 DWORD ShutdownOptions; 1159 1160 // FIXME: User impersonation!! 1161 pgContext->nShutdownAction = LoadShutdownSelState(); 1162 ShutdownOptions = GetAllowedShutdownOptions(); 1163 #endif 1164 1165 Context.pgContext = pgContext; 1166 Context.ShutdownOptions = ShutdownOptions; 1167 Context.ShutdownDialogId = IDD_SHUTDOWN; 1168 Context.bCloseDlg = FALSE; 1169 Context.bReasonUI = GetShutdownReasonUI(); 1170 Context.bFriendlyUI = ShellIsFriendlyUIActive(); 1171 1172 if (pgContext->hWlx && pgContext->pWlxFuncs && !Context.bFriendlyUI) 1173 { 1174 ret = pgContext->pWlxFuncs->WlxDialogBoxParam(pgContext->hWlx, 1175 pgContext->hDllInstance, 1176 MAKEINTRESOURCEW(Context.bReasonUI ? IDD_SHUTDOWN_REASON : IDD_SHUTDOWN), 1177 hwndDlg, 1178 ShutdownDialogProc, 1179 (LPARAM)&Context); 1180 } 1181 else 1182 { 1183 if (Context.bFriendlyUI) 1184 { 1185 if (IsShowHibernateButtonActive()) 1186 { 1187 Context.ShutdownDialogId = IDD_SHUTDOWN_FANCY_LONG; 1188 } 1189 else 1190 { 1191 Context.ShutdownDialogId = IDD_SHUTDOWN_FANCY; 1192 } 1193 } 1194 1195 ret = DialogBoxParamW(pgContext->hDllInstance, 1196 MAKEINTRESOURCEW(Context.bReasonUI ? IDD_SHUTDOWN_REASON : Context.ShutdownDialogId), 1197 hwndDlg, 1198 ShutdownDialogProc, 1199 (LPARAM)&Context); 1200 } 1201 1202 #if 0 1203 // FIXME: User impersonation!! 1204 if (ret == IDOK) 1205 SaveShutdownSelState(pgContext->nShutdownAction); 1206 #endif 1207 1208 return ret; 1209 } 1210 1211 1212 /* 1213 * NOTES: 1214 * - Based upon observations on the ShellShutdownDialog() function, the function doesn't actually 1215 * do anything except show a dialog box and returning a value based upon the value chosen. That 1216 * means that any code that calls the function has to execute the chosen action (shut down, 1217 * restart, etc.). 1218 * - When this function is called in Windows XP, it shows the classic dialog box regardless if 1219 * SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\LogonType is enabled or not. 1220 * - When the Help button is pushed, it sends the same return value as IDCANCEL (0x00), but 1221 * at the same time, it calls the help file directly from the dialog box. 1222 * - When the dialog is created, it doesn't disable all other input from the other windows. 1223 * This is done elsewhere. When running the function ShellShutdownDialog() from XP/2K3, if the user clicks 1224 * out of the window, it automatically closes itself. 1225 * - The parameter, lpUsername never seems to be used when calling the function from Windows XP. Either 1226 * it was a parameter that was never used in the final version before release, or it has a use that 1227 * is currently not known. 1228 */ 1229 DWORD WINAPI 1230 ShellShutdownDialog( 1231 HWND hParent, 1232 LPWSTR lpUsername, 1233 BOOL bHideLogoff) 1234 { 1235 INT_PTR dlgValue; 1236 DWORD ShutdownOptions; 1237 1238 /* 1239 * As we are called by the shell itself, don't use 1240 * the cached GINA context but use a local copy here. 1241 */ 1242 GINA_CONTEXT gContext = { 0 }; 1243 DWORD BufferSize; 1244 1245 UNREFERENCED_PARAMETER(lpUsername); 1246 1247 ShutdownOptions = GetAllowedShutdownOptions(); 1248 if (bHideLogoff) 1249 ShutdownOptions &= ~WLX_SHUTDOWN_STATE_LOGOFF; 1250 1251 /* Initialize our local GINA context */ 1252 gContext.hDllInstance = hDllInstance; 1253 BufferSize = _countof(gContext.UserName); 1254 // NOTE: Only when this function is called, Win checks inside 1255 // HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", 1256 // value "Logon User Name", and determines whether it will display 1257 // the user name. 1258 GetUserNameW(gContext.UserName, &BufferSize); 1259 gContext.nShutdownAction = LoadShutdownSelState(); 1260 1261 /* Load the shutdown dialog box */ 1262 dlgValue = ShutdownDialog(hParent, ShutdownOptions, &gContext); 1263 1264 /* Determine what to do based on user selection */ 1265 if (dlgValue == IDOK) 1266 { 1267 SaveShutdownSelState(gContext.nShutdownAction); 1268 1269 switch (gContext.nShutdownAction) 1270 { 1271 case WLX_SAS_ACTION_LOGOFF: 1272 return WLX_SHUTDOWN_STATE_LOGOFF; 1273 1274 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF: 1275 return WLX_SHUTDOWN_STATE_POWER_OFF; 1276 1277 case WLX_SAS_ACTION_SHUTDOWN_REBOOT: 1278 return WLX_SHUTDOWN_STATE_REBOOT; 1279 1280 // 0x08 1281 1282 case WLX_SAS_ACTION_SHUTDOWN_SLEEP: 1283 return WLX_SHUTDOWN_STATE_SLEEP; 1284 1285 // 0x20 1286 1287 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE: 1288 return WLX_SHUTDOWN_STATE_HIBERNATE; 1289 1290 // 0x80 1291 } 1292 } 1293 /* Help file is called directly here */ 1294 else if (dlgValue == IDHELP) 1295 { 1296 FIXME("Help is not implemented yet.\n"); 1297 MessageBoxW(hParent, L"Help is not implemented yet.", L"Message", MB_OK | MB_ICONEXCLAMATION); 1298 } 1299 else if (dlgValue == -1) 1300 { 1301 ERR("Failed to create dialog\n"); 1302 } 1303 1304 return 0; 1305 } 1306 1307 /* 1308 * NOTES: 1309 * - Undocumented, called from MS shell32.dll to show the turn off dialog. 1310 * - Seems to have the same purpose as ShellShutdownDialog. 1311 */ 1312 DWORD WINAPI 1313 ShellTurnOffDialog(HWND hWnd) 1314 { 1315 return ShellShutdownDialog(hWnd, NULL, FALSE); 1316 } 1317