1 /* 2 * ReactOS kernel 3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 /* 20 * PROJECT: ReactOS user32.dll 21 * FILE: win32ss/user/user32/windows/messagebox.c 22 * PURPOSE: Message Boxes 23 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 24 * Thomas Weidenmueller (w3seek@users.sourceforge.net) 25 * Hermes Belusca-Maito 26 * UPDATE HISTORY: 27 * 2003/07/28 Added some NT features 28 * 2003/07/27 Code ported from wine 29 * 09-05-2001 CSH Created 30 */ 31 32 #include <user32.h> 33 #include <ndk/exfuncs.h> 34 35 #include <ntstrsafe.h> 36 37 WINE_DEFAULT_DEBUG_CHANNEL(user32); 38 39 /* DEFINES *******************************************************************/ 40 41 #define MSGBOX_IDICON (1088) 42 #define MSGBOX_IDTEXT (0xffff) 43 44 #define IDI_HANDW MAKEINTRESOURCEW(32513) 45 #define IDI_QUESTIONW MAKEINTRESOURCEW(32514) 46 #define IDI_EXCLAMATIONW MAKEINTRESOURCEW(32515) 47 #define IDI_ASTERISKW MAKEINTRESOURCEW(32516) 48 #define IDI_WINLOGOW MAKEINTRESOURCEW(32517) 49 50 51 /* MessageBox metrics */ 52 53 #define BTN_CX (75) 54 #define BTN_CY (23) 55 56 #define MSGBOXEX_SPACING (16) 57 #define MSGBOXEX_BUTTONSPACING (6) 58 #define MSGBOXEX_MARGIN (12) 59 #define MSGBOXEX_MAXBTNSTR (32) 60 #define MSGBOXEX_MAXBTNS (4) 61 62 /* Rescale logical coordinates */ 63 #define RESCALE_X(_x, _units) (((_x) * 4 + (_units).cx - 1) / (_units).cx) 64 #define RESCALE_Y(_y, _units) (((_y) * 8 + (_units).cy - 1) / (_units).cy) 65 66 67 /* MessageBox button helpers */ 68 69 #define DECLARE_MB_1(_btn0) \ 70 { 1, { ID##_btn0, 0, 0 }, { IDS_##_btn0, 0, 0 } } 71 72 #define DECLARE_MB_2(_btn0, _btn1) \ 73 { 2, { ID##_btn0, ID##_btn1, 0 }, { IDS_##_btn0, IDS_##_btn1, 0 } } 74 75 #define DECLARE_MB_3(_btn0, _btn1, _btn2) \ 76 { 3, { ID##_btn0, ID##_btn1, ID##_btn2 }, { IDS_##_btn0, IDS_##_btn1, IDS_##_btn2 } } 77 78 typedef struct _MSGBTNINFO 79 { 80 DWORD btnCnt; 81 INT btnIdx[MSGBOXEX_MAXBTNS]; 82 UINT btnIds[MSGBOXEX_MAXBTNS]; 83 } MSGBTNINFO, *PMSGBTNINFO; 84 85 /* Default MessageBox buttons */ 86 static const MSGBTNINFO MsgBtnInfo[] = 87 { 88 /* MB_OK (0) */ 89 DECLARE_MB_1(OK), 90 /* MB_OKCANCEL (1) */ 91 DECLARE_MB_2(OK, CANCEL), 92 /* MB_ABORTRETRYIGNORE (2) */ 93 DECLARE_MB_3(ABORT, RETRY, IGNORE), 94 /* MB_YESNOCANCEL (3) */ 95 DECLARE_MB_3(YES, NO, CANCEL), 96 /* MB_YESNO (4) */ 97 DECLARE_MB_2(YES, NO), 98 /* MB_RETRYCANCEL (5) */ 99 DECLARE_MB_2(RETRY, CANCEL), 100 /* MB_CANCELTRYCONTINUE (6) */ 101 DECLARE_MB_3(CANCEL, TRYAGAIN, CONTINUE) 102 }; 103 104 105 /* INTERNAL FUNCTIONS ********************************************************/ 106 107 static UINT 108 LoadAllocStringW( 109 IN HINSTANCE hInstance OPTIONAL, 110 IN UINT uID, 111 OUT PWSTR* pString, 112 IN PCWSTR pDefaultString OPTIONAL) 113 { 114 UINT Length; 115 PCWSTR pStr; 116 117 /* Try to load the string from the resource */ 118 Length = LoadStringW(hInstance, uID, (LPWSTR)&pStr, 0); 119 if (Length == 0) 120 { 121 /* If the resource string was not found, use the fallback default one */ 122 123 if (!pDefaultString) 124 { 125 /* None was specified, return NULL */ 126 *pString = NULL; 127 return 0; 128 } 129 130 pStr = pDefaultString; 131 Length = wcslen(pStr); 132 } 133 134 /* Allocate a new buffer, adding a NULL-terminator */ 135 *pString = RtlAllocateHeap(RtlGetProcessHeap(), 0, (Length + 1) * sizeof(WCHAR)); 136 if (!*pString) 137 return 0; 138 139 /* Copy the string, NULL-terminated */ 140 RtlStringCchCopyNW(*pString, Length + 1, pStr, Length); 141 return Length; 142 } 143 144 static VOID MessageBoxTextToClipboard(HWND DialogWindow) 145 { 146 HWND hwndText; 147 PMSGBOXDATA mbd; 148 int cchTotal, cchTitle, cchText, cchButton, i, n, cchBuffer; 149 LPWSTR pszBuffer, pszBufferPos, pMessageBoxText, pszTitle, pszText, pszButton; 150 WCHAR szButton[MSGBOXEX_MAXBTNSTR]; 151 HGLOBAL hGlobal; 152 153 static const WCHAR szLine[] = L"---------------------------\r\n"; 154 155 mbd = (PMSGBOXDATA)GetPropW(DialogWindow, L"ROS_MSGBOX"); 156 hwndText = GetDlgItem(DialogWindow, MSGBOX_IDTEXT); 157 cchTitle = GetWindowTextLengthW(DialogWindow) + 1; 158 cchText = GetWindowTextLengthW(hwndText) + 1; 159 160 if (!mbd) 161 return; 162 163 pMessageBoxText = (LPWSTR)RtlAllocateHeap(GetProcessHeap(), 0, (cchTitle + cchText) * sizeof(WCHAR)); 164 165 if (pMessageBoxText == NULL) 166 { 167 RtlFreeHeap(GetProcessHeap(), 0, pMessageBoxText); 168 return; 169 } 170 171 pszTitle = pMessageBoxText; 172 pszText = pMessageBoxText + cchTitle; 173 174 if (GetWindowTextW(DialogWindow, pszTitle, cchTitle) == 0 || 175 GetWindowTextW(hwndText, pszText, cchText) == 0) 176 { 177 RtlFreeHeap(GetProcessHeap(), 0, pMessageBoxText); 178 return; 179 } 180 181 /* 182 * Calculate the total buffer size. 183 */ 184 cchTotal = 6 + cchTitle + cchText + (lstrlenW(szLine) * 4) + (mbd->dwButtons * MSGBOXEX_MAXBTNSTR + 3); 185 186 hGlobal = GlobalAlloc(GHND, cchTotal * sizeof(WCHAR)); 187 188 pszBuffer = (LPWSTR)GlobalLock(hGlobal); 189 190 if (pszBuffer == NULL) 191 { 192 RtlFreeHeap(GetProcessHeap(), 0, pMessageBoxText); 193 GlobalFree(hGlobal); 194 return; 195 } 196 197 /* 198 * First format title and text. 199 * ------------------ 200 * Title 201 * ------------------ 202 * Text 203 * ------------------ 204 */ 205 cchBuffer = wsprintfW(pszBuffer, L"%s%s\r\n%s%s\r\n%s", szLine, pszTitle, szLine, pszText, szLine); 206 pszBufferPos = pszBuffer + cchBuffer; 207 208 for (i = 0; i < mbd->dwButtons; i++) 209 { 210 GetDlgItemTextW(DialogWindow, mbd->pidButton[i], szButton, MSGBOXEX_MAXBTNSTR); 211 212 cchButton = strlenW(szButton); 213 pszButton = szButton; 214 215 /* Skip '&' character. */ 216 if (szButton[0] == '&') 217 { 218 pszButton = pszButton + 1; 219 cchButton = cchButton - 1; 220 } 221 222 for (n = 0; n < cchButton; n++) 223 *(pszBufferPos++) = pszButton[n]; 224 225 /* Add spaces. */ 226 *(pszBufferPos++) = L' '; 227 *(pszBufferPos++) = L' '; 228 *(pszBufferPos++) = L' '; 229 } 230 231 wsprintfW(pszBufferPos, L"\r\n%s", szLine); 232 233 GlobalUnlock(hGlobal); 234 235 if (OpenClipboard(DialogWindow)) 236 { 237 EmptyClipboard(); 238 SetClipboardData(CF_UNICODETEXT, hGlobal); 239 CloseClipboard(); 240 } 241 else 242 { 243 GlobalFree(hGlobal); 244 } 245 RtlFreeHeap(GetProcessHeap(), 0, pMessageBoxText); 246 } 247 248 static INT_PTR CALLBACK MessageBoxProc( 249 HWND hwnd, UINT message, 250 WPARAM wParam, LPARAM lParam) 251 { 252 PMSGBOXDATA mbd; 253 254 switch (message) 255 { 256 case WM_INITDIALOG: 257 { 258 int Alert; 259 260 mbd = (PMSGBOXDATA)lParam; 261 262 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)mbd); 263 NtUserxSetMessageBox(hwnd); 264 265 if (!GetPropW(hwnd, L"ROS_MSGBOX")) 266 { 267 SetPropW(hwnd, L"ROS_MSGBOX", (HANDLE)lParam); 268 269 if (mbd->mbp.dwContextHelpId) 270 SetWindowContextHelpId(hwnd, mbd->mbp.dwContextHelpId); 271 272 if (mbd->mbp.lpszIcon) 273 { 274 SendDlgItemMessageW(hwnd, MSGBOX_IDICON, STM_SETICON, (WPARAM)(HICON)mbd->mbp.lpszIcon, 0); 275 Alert = ALERT_SYSTEM_WARNING; 276 } 277 else /* Setup the rest of the alerts */ 278 { 279 switch (mbd->mbp.dwStyle & MB_ICONMASK) 280 { 281 case MB_ICONWARNING: 282 Alert = ALERT_SYSTEM_WARNING; 283 break; 284 case MB_ICONERROR: 285 Alert = ALERT_SYSTEM_ERROR; 286 break; 287 case MB_ICONQUESTION: 288 Alert = ALERT_SYSTEM_QUERY; 289 break; 290 default: 291 Alert = ALERT_SYSTEM_INFORMATIONAL; 292 /* Fall through */ 293 } 294 } 295 /* Send out the alert notifications */ 296 NotifyWinEvent(EVENT_SYSTEM_ALERT, hwnd, OBJID_ALERT, Alert); 297 298 /* Disable the Close menu button if no Cancel button is specified */ 299 if (mbd->uCancelId == 0) 300 { 301 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE); 302 if (hSysMenu) 303 DeleteMenu(hSysMenu, SC_CLOSE, MF_BYCOMMAND); 304 } 305 306 /* Set the focus to the default button */ 307 if (mbd->dwButtons > 0) 308 { 309 ASSERT(mbd->uDefButton < mbd->dwButtons); 310 SetFocus(GetDlgItem(hwnd, mbd->pidButton[mbd->uDefButton])); 311 } 312 313 /* Set up the window timer */ 314 if (mbd->dwTimeout && (mbd->dwTimeout != (UINT)-1)) 315 SetTimer(hwnd, 0, mbd->dwTimeout, NULL); 316 } 317 return FALSE; 318 } 319 320 case WM_COMMAND: 321 { 322 UINT i; 323 INT_PTR iCtrlId = LOWORD(wParam); 324 325 switch (iCtrlId) 326 { 327 /* Handle the default message-box buttons */ 328 case IDOK: 329 case IDCANCEL: 330 /* 331 * The dialog manager always sends IDCANCEL when the user 332 * presses ESCape. We check here whether the message box 333 * has a CANCEL button, or whether we should fall back to 334 * the OK button, by using the correct uCancelId. 335 */ 336 if (iCtrlId == IDCANCEL) 337 { 338 mbd = (PMSGBOXDATA)GetPropW(hwnd, L"ROS_MSGBOX"); 339 if (!mbd) 340 return FALSE; /* Ignore */ 341 342 /* Check whether we can cancel the message box */ 343 if (mbd->uCancelId == 0) 344 return TRUE; // FALSE; /* No, ignore */ 345 /* Quit with the correct return value */ 346 iCtrlId = mbd->uCancelId; 347 } 348 if (!GetDlgItem(hwnd, iCtrlId)) 349 return FALSE; /* Ignore */ 350 351 /* Fall through */ 352 case IDABORT: 353 case IDRETRY: 354 case IDIGNORE: 355 case IDYES: 356 case IDNO: 357 case IDTRYAGAIN: 358 case IDCONTINUE: 359 EndDialog(hwnd, iCtrlId); 360 return TRUE; 361 362 case IDCLOSE: 363 return FALSE; /* Ignore */ 364 365 case IDHELP: 366 { 367 /* Send WM_HELP message to the message-box window */ 368 HELPINFO hi; 369 hi.cbSize = sizeof(hi); 370 hi.iContextType = HELPINFO_WINDOW; 371 hi.iCtrlId = iCtrlId; 372 hi.hItemHandle = (HANDLE)lParam; 373 hi.dwContextId = 0; 374 GetCursorPos(&hi.MousePos); 375 SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi); 376 return TRUE; 377 } 378 379 default: 380 break; 381 } 382 383 /* Check for any other user-defined buttons */ 384 mbd = (PMSGBOXDATA)GetPropW(hwnd, L"ROS_MSGBOX"); 385 if (!mbd) 386 return FALSE; 387 388 for (i = 0; i < mbd->dwButtons; ++i) 389 { 390 if (iCtrlId == mbd->pidButton[i]) 391 { 392 EndDialog(hwnd, iCtrlId); 393 return TRUE; 394 } 395 } 396 397 return FALSE; 398 } 399 400 case WM_COPY: 401 MessageBoxTextToClipboard(hwnd); 402 return TRUE; 403 404 case WM_HELP: 405 { 406 LPHELPINFO phi = (LPHELPINFO)lParam; 407 mbd = (PMSGBOXDATA)GetPropW(hwnd, L"ROS_MSGBOX"); 408 if (!mbd) 409 return FALSE; 410 phi->dwContextId = GetWindowContextHelpId(hwnd); 411 412 if (mbd->mbp.lpfnMsgBoxCallback) 413 { 414 mbd->mbp.lpfnMsgBoxCallback(phi); 415 } 416 else 417 { 418 HWND hwndOwner = GetWindow(hwnd, GW_OWNER); 419 if (hwndOwner) 420 SendMessageW(hwndOwner, WM_HELP, 0, lParam); 421 } 422 return TRUE; 423 } 424 425 case WM_CLOSE: 426 { 427 mbd = (PMSGBOXDATA)GetPropW(hwnd, L"ROS_MSGBOX"); 428 if (!mbd) 429 return FALSE; 430 431 /* Check whether we can cancel the message box */ 432 if (mbd->uCancelId == 0) 433 return TRUE; /* No, ignore */ 434 /* Quit with the correct return value */ 435 EndDialog(hwnd, mbd->uCancelId); 436 return TRUE; 437 } 438 439 case WM_TIMER: 440 if (wParam == 0) 441 EndDialog(hwnd, IDTIMEOUT); 442 return FALSE; 443 } 444 445 return FALSE; 446 } 447 448 static int 449 MessageBoxTimeoutIndirectW( 450 CONST MSGBOXPARAMSW *lpMsgBoxParams, UINT dwTimeout) 451 { 452 int ret = 0; 453 UINT i; 454 LPWSTR defCaption = NULL; 455 MSGBOXDATA mbd; 456 MSGBTNINFO Buttons; 457 LPCWSTR ButtonText[MSGBOXEX_MAXBTNS]; 458 459 // TODO: Check whether the caller is an NT 3.x app and if so, check 460 // instead for the MB_SERVICE_NOTIFICATION_NT3X flag and adjust it. 461 if (lpMsgBoxParams->dwStyle & MB_SERVICE_NOTIFICATION) 462 { 463 NTSTATUS Status; 464 UNICODE_STRING CaptionU, TextU; 465 ULONG Response = ResponseNotHandled; /* HARDERROR_RESPONSE */ 466 ULONG_PTR MsgBoxParams[4] = 467 { 468 (ULONG_PTR)&TextU, 469 (ULONG_PTR)&CaptionU, 470 /* 471 * Retrieve the message box flags. Note that we filter out 472 * MB_SERVICE_NOTIFICATION to not enter an infinite recursive 473 * loop when we will call MessageBox() later on. 474 */ 475 lpMsgBoxParams->dwStyle & ~MB_SERVICE_NOTIFICATION, 476 dwTimeout 477 }; 478 479 /* hwndOwner must be NULL */ 480 if (lpMsgBoxParams->hwndOwner != NULL) 481 { 482 ERR("MessageBoxTimeoutIndirectW(MB_SERVICE_NOTIFICATION): hwndOwner is not NULL!\n"); 483 return 0; 484 } 485 486 // 487 // FIXME: TODO: Implement the special case for Terminal Services. 488 // 489 490 RtlInitUnicodeString(&CaptionU, lpMsgBoxParams->lpszCaption); 491 RtlInitUnicodeString(&TextU, lpMsgBoxParams->lpszText); 492 493 Status = NtRaiseHardError(STATUS_SERVICE_NOTIFICATION | HARDERROR_OVERRIDE_ERRORMODE, 494 ARRAYSIZE(MsgBoxParams), 495 (1 | 2), 496 MsgBoxParams, 497 OptionOk, /* NOTE: This parameter is ignored */ 498 &Response); 499 if (!NT_SUCCESS(Status)) 500 { 501 ERR("MessageBoxTimeoutIndirectW(MB_SERVICE_NOTIFICATION): NtRaiseHardError failed, Status = 0x%08lx\n", Status); 502 return 0; 503 } 504 505 /* Map the returned response to the buttons */ 506 switch (Response) 507 { 508 /* Not handled */ 509 case ResponseReturnToCaller: 510 case ResponseNotHandled: 511 break; 512 513 case ResponseAbort: 514 return IDABORT; 515 case ResponseCancel: 516 return IDCANCEL; 517 case ResponseIgnore: 518 return IDIGNORE; 519 case ResponseNo: 520 return IDNO; 521 case ResponseOk: 522 return IDOK; 523 case ResponseRetry: 524 return IDRETRY; 525 case ResponseYes: 526 return IDYES; 527 case ResponseTryAgain: 528 return IDTRYAGAIN; 529 case ResponseContinue: 530 return IDCONTINUE; 531 532 /* Not handled */ 533 default: 534 break; 535 } 536 return 0; 537 } 538 539 ZeroMemory(&mbd, sizeof(mbd)); 540 memcpy(&mbd.mbp, lpMsgBoxParams, sizeof(mbd.mbp)); 541 mbd.wLanguageId = (WORD)lpMsgBoxParams->dwLanguageId; 542 mbd.dwTimeout = dwTimeout; 543 544 if (!mbd.mbp.lpszCaption) 545 { 546 /* No caption, use the default one */ 547 LoadAllocStringW(User32Instance, 548 IDS_ERROR, 549 &defCaption, 550 L"Error"); 551 mbd.mbp.lpszCaption = (defCaption ? defCaption : L"Error"); 552 } 553 554 /* Create the selected buttons; unknown types will fall back to MB_OK */ 555 i = (lpMsgBoxParams->dwStyle & MB_TYPEMASK); 556 if (i >= ARRAYSIZE(MsgBtnInfo)) 557 i = MB_OK; 558 559 /* Get the buttons IDs */ 560 Buttons = MsgBtnInfo[i]; 561 562 /* Add the Help button */ 563 if (lpMsgBoxParams->dwStyle & MB_HELP) 564 { 565 Buttons.btnIdx[Buttons.btnCnt] = IDHELP; 566 Buttons.btnIds[Buttons.btnCnt] = IDS_HELP; 567 Buttons.btnCnt++; 568 } 569 570 ASSERT(Buttons.btnCnt <= MSGBOXEX_MAXBTNS); 571 572 /* Retrieve the pointers to the button labels and find the Cancel button */ 573 mbd.uCancelId = (i == MB_OK ? IDOK : 0); 574 for (i = 0; i < Buttons.btnCnt; ++i) 575 { 576 // FIXME: Use the strings in the correct language. 577 // MB_GetString gives the string in default system language. 578 ButtonText[i] = MB_GetString(Buttons.btnIds[i] - IDS_OK); /* or: Buttons.btnIdx[i] - IDOK */ 579 #if 0 580 LoadAllocStringW(User32Instance, 581 Buttons.btnIds[i], 582 &ButtonText[i], 583 L""); 584 #endif 585 if (Buttons.btnIdx[i] == IDCANCEL) 586 mbd.uCancelId = IDCANCEL; 587 } 588 589 mbd.pidButton = Buttons.btnIdx; 590 mbd.ppszButtonText = ButtonText; 591 mbd.dwButtons = Buttons.btnCnt; 592 593 mbd.uDefButton = ((lpMsgBoxParams->dwStyle & MB_DEFMASK) >> 8); 594 /* Make the first button the default button if none other is */ 595 if (mbd.uDefButton >= mbd.dwButtons) 596 mbd.uDefButton = 0; 597 598 /* Call the helper function */ 599 ret = SoftModalMessageBox(&mbd); 600 601 #if 0 602 for (i = 0; i < mbd.dwButtons; i++) 603 { 604 if (ButtonText[i] && *ButtonText[i]) 605 RtlFreeHeap(RtlGetProcessHeap(), 0, ButtonText[i]); 606 } 607 #endif 608 609 if (defCaption) 610 RtlFreeHeap(RtlGetProcessHeap(), 0, defCaption); 611 612 return ret; 613 } 614 615 int 616 WINAPI 617 SoftModalMessageBox(IN LPMSGBOXDATA lpMsgBoxData) 618 { 619 int ret = 0; 620 MSGBOXDATA mbd; 621 LPMSGBOXPARAMSW lpMsgBoxParams = &mbd.mbp; 622 DLGTEMPLATE *tpl; 623 DLGITEMTEMPLATE *iico, *itxt, *ibtn; 624 NONCLIENTMETRICSW nclm; 625 LPVOID buf; 626 BYTE *dest; 627 LPWSTR caption, text; 628 HFONT hFont, hOldFont; 629 HICON hIcon; 630 HWND hDCWnd; 631 HDC hDC; 632 SIZE units; 633 int bufsize, caplen, textlen, i, btnleft, btntop; 634 size_t ButtonLen; 635 RECT btnrect, txtrect, rc; 636 SIZE btnsize; 637 POINT iconPos; SIZE iconSize; 638 639 /* Capture the MsgBoxData */ 640 memcpy(&mbd, lpMsgBoxData, sizeof(mbd)); 641 642 /* Load the caption */ 643 caption = NULL; 644 if (lpMsgBoxParams->lpszCaption && IS_INTRESOURCE(lpMsgBoxParams->lpszCaption)) 645 { 646 /* User-defined resource string */ 647 caplen = LoadAllocStringW(lpMsgBoxParams->hInstance, 648 PtrToUlong(lpMsgBoxParams->lpszCaption), 649 &caption, 650 NULL); 651 lpMsgBoxParams->lpszCaption = caption; 652 } 653 else if (lpMsgBoxParams->lpszCaption) 654 { 655 /* UNICODE string pointer */ 656 caplen = wcslen(lpMsgBoxParams->lpszCaption); 657 } 658 if (!lpMsgBoxParams->lpszCaption) 659 { 660 /* No caption, use blank */ 661 lpMsgBoxParams->lpszCaption = L""; 662 caplen = 0; 663 } 664 665 /* Load the text */ 666 text = NULL; 667 if (lpMsgBoxParams->lpszText && IS_INTRESOURCE(lpMsgBoxParams->lpszText)) 668 { 669 /* User-defined resource string */ 670 textlen = LoadAllocStringW(lpMsgBoxParams->hInstance, 671 PtrToUlong(lpMsgBoxParams->lpszText), 672 &text, 673 NULL); 674 lpMsgBoxParams->lpszText = text; 675 } 676 else if (lpMsgBoxParams->lpszText) 677 { 678 /* UNICODE string pointer */ 679 textlen = wcslen(lpMsgBoxParams->lpszText); 680 } 681 if (!lpMsgBoxParams->lpszText) 682 { 683 /* No text, use blank */ 684 lpMsgBoxParams->lpszText = L""; 685 textlen = 0; 686 } 687 688 /* Load the icon */ 689 switch (lpMsgBoxParams->dwStyle & MB_ICONMASK) 690 { 691 case MB_ICONEXCLAMATION: // case MB_ICONWARNING: 692 hIcon = LoadIconW(NULL, IDI_EXCLAMATIONW); 693 MessageBeep(MB_ICONEXCLAMATION); 694 break; 695 case MB_ICONQUESTION: 696 hIcon = LoadIconW(NULL, IDI_QUESTIONW); 697 MessageBeep(MB_ICONQUESTION); 698 break; 699 case MB_ICONASTERISK: // case MB_ICONINFORMATION: 700 hIcon = LoadIconW(NULL, IDI_ASTERISKW); 701 MessageBeep(MB_ICONASTERISK); 702 break; 703 case MB_ICONHAND: // case MB_ICONSTOP: case MB_ICONERROR: 704 hIcon = LoadIconW(NULL, IDI_HANDW); 705 MessageBeep(MB_ICONHAND); 706 break; 707 case MB_USERICON: 708 hIcon = LoadIconW(lpMsgBoxParams->hInstance, lpMsgBoxParams->lpszIcon); 709 MessageBeep(MB_OK); 710 break; 711 default: 712 /* 713 * By default, Windows 95/98/NT does not associate an icon 714 * to message boxes. So ReactOS should do the same. 715 */ 716 hIcon = NULL; 717 MessageBeep(MB_OK); 718 break; 719 } 720 /* Reuse the internal pointer! */ 721 lpMsgBoxParams->lpszIcon = (LPCWSTR)hIcon; 722 723 /* Basic space */ 724 bufsize = sizeof(DLGTEMPLATE) + 725 2 * sizeof(WORD) + /* menu and class */ 726 (caplen + 1) * sizeof(WCHAR) + /* title */ 727 sizeof(WORD); /* font height */ 728 729 /* Space for the icon */ 730 if (hIcon) 731 { 732 bufsize = ALIGN_UP(bufsize, DWORD); 733 bufsize += sizeof(DLGITEMTEMPLATE) + 734 4 * sizeof(WORD) + 735 sizeof(WCHAR); 736 } 737 738 /* Space for the text */ 739 bufsize = ALIGN_UP(bufsize, DWORD); 740 bufsize += sizeof(DLGITEMTEMPLATE) + 741 3 * sizeof(WORD) + 742 (textlen + 1) * sizeof(WCHAR); 743 744 /* Space for the buttons */ 745 for (i = 0; i < mbd.dwButtons; i++) 746 { 747 if (!mbd.ppszButtonText[i] || !*mbd.ppszButtonText[i]) 748 { 749 /* No text, use blank */ 750 mbd.ppszButtonText[i] = L""; 751 ButtonLen = 0; 752 } 753 else 754 { 755 /* UNICODE string pointer */ 756 ButtonLen = wcslen(mbd.ppszButtonText[i]); 757 } 758 759 bufsize = ALIGN_UP(bufsize, DWORD); 760 bufsize += sizeof(DLGITEMTEMPLATE) + 761 3 * sizeof(WORD) + 762 (ButtonLen + 1) * sizeof(WCHAR); 763 } 764 765 /* Allocate the dialog template */ 766 buf = RtlAllocateHeap(RtlGetProcessHeap(), 0, bufsize); 767 if (!buf) 768 goto Quit; 769 770 iico = itxt = NULL; 771 772 773 nclm.cbSize = sizeof(nclm); 774 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0); 775 hFont = CreateFontIndirectW(&nclm.lfMessageFont); 776 if (!hFont) 777 { 778 ERR("Cannot retrieve nclm.lfMessageFont! (error %lu)\n", GetLastError()); 779 goto Quit; 780 } 781 782 hDCWnd = NULL; 783 hDC = GetDCEx(hDCWnd, NULL, DCX_WINDOW | DCX_CACHE); 784 if (!hDC) 785 { 786 /* Retry with the DC of the owner window */ 787 hDCWnd = lpMsgBoxParams->hwndOwner; 788 hDC = GetDCEx(hDCWnd, NULL, DCX_WINDOW | DCX_CACHE); 789 } 790 if (!hDC) 791 { 792 ERR("GetDCEx() failed, bail out! (error %lu)\n", GetLastError()); 793 goto Quit; 794 } 795 hOldFont = SelectObject(hDC, hFont); 796 797 units.cx = GdiGetCharDimensions(hDC, NULL, &units.cy); 798 if (!units.cx) 799 { 800 DWORD defUnits; 801 ERR("GdiGetCharDimensions() failed, falling back to default values (error %lu)\n", GetLastError()); 802 defUnits = GetDialogBaseUnits(); 803 units.cx = LOWORD(defUnits); 804 units.cy = HIWORD(defUnits); 805 } 806 807 /* Calculate the caption rectangle */ 808 txtrect.right = MulDiv(GetSystemMetrics(SM_CXSCREEN), 4, 5); 809 if (hIcon) 810 txtrect.right -= GetSystemMetrics(SM_CXICON) + MSGBOXEX_SPACING; 811 txtrect.top = txtrect.left = txtrect.bottom = 0; 812 if (textlen != 0) 813 { 814 DrawTextW(hDC, lpMsgBoxParams->lpszText, textlen, &txtrect, 815 DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_EXPANDTABS | DT_EXTERNALLEADING | DT_EDITCONTROL | DT_CALCRECT); 816 } 817 else 818 { 819 txtrect.right = txtrect.left + 1; 820 txtrect.bottom = txtrect.top + 1; 821 } 822 txtrect.right++; 823 824 /* Calculate the maximum buttons size */ 825 btnsize.cx = BTN_CX; 826 btnsize.cy = BTN_CY; 827 btnrect.left = btnrect.top = 0; 828 for (i = 0; i < mbd.dwButtons; i++) 829 { 830 // btnrect.right = btnrect.bottom = 0; // FIXME: Is it needed?? 831 DrawTextW(hDC, mbd.ppszButtonText[i], wcslen(mbd.ppszButtonText[i]), 832 &btnrect, DT_LEFT | DT_SINGLELINE | DT_CALCRECT); 833 btnsize.cx = max(btnsize.cx, btnrect.right); 834 btnsize.cy = max(btnsize.cy, btnrect.bottom); 835 } 836 837 if (hOldFont) 838 SelectObject(hDC, hOldFont); 839 840 ReleaseDC(hDCWnd, hDC); 841 842 if (hFont) 843 DeleteObject(hFont); 844 845 846 /* Calculate position and size of controls */ 847 848 849 /* Calculate position and size of the icon */ 850 rc.left = rc.bottom = rc.right = 0; 851 btntop = 0; 852 if (hIcon) 853 { 854 rc.right = GetSystemMetrics(SM_CXICON); 855 rc.bottom = GetSystemMetrics(SM_CYICON); 856 #ifdef MSGBOX_ICONVCENTER 857 rc.top = MSGBOXEX_MARGIN + ((max(txtrect.bottom, rc.bottom) - rc.bottom) / 2); 858 rc.top = max(MSGBOXEX_SPACING, rc.top); 859 #else 860 rc.top = MSGBOXEX_MARGIN; 861 #endif 862 btnleft = (mbd.dwButtons * (btnsize.cx + MSGBOXEX_BUTTONSPACING)) - MSGBOXEX_BUTTONSPACING; 863 if (btnleft > txtrect.right + rc.right + MSGBOXEX_SPACING) 864 { 865 #ifdef MSGBOX_TEXTHCENTER 866 rc.left = MSGBOXEX_MARGIN + ((btnleft - txtrect.right - rc.right - MSGBOXEX_SPACING) / 2); 867 #else 868 rc.left = MSGBOXEX_MARGIN; 869 #endif 870 btnleft = MSGBOXEX_MARGIN; 871 } 872 else 873 { 874 rc.left = MSGBOXEX_MARGIN; 875 btnleft = MSGBOXEX_MARGIN + ((txtrect.right + rc.right + MSGBOXEX_SPACING - btnleft) / 2); 876 } 877 878 iconPos.x = RESCALE_X(rc.left, units); 879 iconPos.y = RESCALE_Y(rc.top, units); 880 iconSize.cx = RESCALE_X(rc.right, units); 881 iconSize.cy = RESCALE_Y(rc.bottom, units); 882 883 btntop = rc.top + rc.bottom + MSGBOXEX_SPACING; 884 rc.left += rc.right + MSGBOXEX_SPACING; 885 } 886 else 887 { 888 btnleft = (mbd.dwButtons * (btnsize.cx + MSGBOXEX_BUTTONSPACING)) - MSGBOXEX_BUTTONSPACING; 889 if (btnleft > txtrect.right) 890 { 891 #ifdef MSGBOX_TEXTHCENTER 892 rc.left = MSGBOXEX_MARGIN + ((btnleft - txtrect.right) / 2); 893 #else 894 rc.left = MSGBOXEX_MARGIN; 895 #endif 896 btnleft = MSGBOXEX_MARGIN; 897 } 898 else 899 { 900 rc.left = MSGBOXEX_MARGIN; 901 btnleft = MSGBOXEX_MARGIN + ((txtrect.right - btnleft) / 2); 902 } 903 } 904 905 906 /* Initialize the dialog template */ 907 tpl = (DLGTEMPLATE *)buf; 908 909 tpl->style = WS_CAPTION | WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SYSMENU | 910 DS_CENTER | DS_SETFONT | DS_MODALFRAME | DS_NOIDLEMSG; 911 tpl->dwExtendedStyle = WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; 912 if (lpMsgBoxParams->dwStyle & MB_TOPMOST) 913 tpl->dwExtendedStyle |= WS_EX_TOPMOST; 914 if (lpMsgBoxParams->dwStyle & MB_RIGHT) 915 tpl->dwExtendedStyle |= WS_EX_RIGHT; 916 tpl->x = 100; 917 tpl->y = 100; 918 tpl->cdit = mbd.dwButtons + (hIcon ? 1 : 0) + 1; /* Buttons, icon and text */ 919 920 dest = (BYTE *)(tpl + 1); 921 922 *(DWORD*)dest = 0; /* no menu and use default window class */ 923 dest += 2 * sizeof(WORD); 924 memcpy(dest, lpMsgBoxParams->lpszCaption, caplen * sizeof(WCHAR)); 925 dest += caplen * sizeof(WCHAR); 926 *(WCHAR*)dest = L'\0'; 927 dest += sizeof(WCHAR); 928 929 /* 930 * A font point size (height) of 0x7FFF means that we use 931 * the message box font (NONCLIENTMETRICSW.lfMessageFont). 932 */ 933 *(WORD*)dest = 0x7FFF; 934 dest += sizeof(WORD); 935 936 /* Create the icon */ 937 if (hIcon) 938 { 939 dest = ALIGN_UP_POINTER(dest, DWORD); 940 iico = (DLGITEMTEMPLATE *)dest; 941 iico->style = WS_CHILD | WS_VISIBLE | SS_ICON; 942 iico->dwExtendedStyle = 0; 943 iico->id = MSGBOX_IDICON; 944 945 iico->x = iconPos.x; 946 iico->y = iconPos.y; 947 iico->cx = iconSize.cx; 948 iico->cy = iconSize.cy; 949 950 dest += sizeof(DLGITEMTEMPLATE); 951 *(WORD*)dest = 0xFFFF; 952 dest += sizeof(WORD); 953 *(WORD*)dest = 0x0082; /* static control */ 954 dest += sizeof(WORD); 955 *(WORD*)dest = 0xFFFF; 956 dest += sizeof(WORD); 957 *(WCHAR*)dest = 0; 958 dest += sizeof(WCHAR); 959 *(WORD*)dest = 0; 960 dest += sizeof(WORD); 961 } 962 963 /* Create static for text */ 964 dest = ALIGN_UP_POINTER(dest, DWORD); 965 itxt = (DLGITEMTEMPLATE *)dest; 966 itxt->style = WS_CHILD | WS_VISIBLE | SS_NOPREFIX; 967 if (lpMsgBoxParams->dwStyle & MB_RIGHT) 968 itxt->style |= SS_RIGHT; 969 else 970 itxt->style |= SS_LEFT; 971 itxt->dwExtendedStyle = 0; 972 itxt->id = MSGBOX_IDTEXT; 973 dest += sizeof(DLGITEMTEMPLATE); 974 *(WORD*)dest = 0xFFFF; 975 dest += sizeof(WORD); 976 *(WORD*)dest = 0x0082; /* static control */ 977 dest += sizeof(WORD); 978 memcpy(dest, lpMsgBoxParams->lpszText, textlen * sizeof(WCHAR)); 979 dest += textlen * sizeof(WCHAR); 980 *(WCHAR*)dest = 0; 981 dest += sizeof(WCHAR); 982 *(WORD*)dest = 0; 983 dest += sizeof(WORD); 984 985 986 /* Calculate position of the text */ 987 rc.top = MSGBOXEX_MARGIN + ((rc.bottom - txtrect.bottom) / 2); 988 rc.top = max(rc.top, MSGBOXEX_MARGIN); 989 990 991 /* Make the first button the default button if none other is */ 992 if (mbd.uDefButton >= mbd.dwButtons) 993 mbd.uDefButton = 0; 994 995 /* Create and calculate the position of the buttons */ 996 btntop = max(rc.top + txtrect.bottom + MSGBOXEX_SPACING, btntop); 997 for (i = 0; i < mbd.dwButtons; i++) 998 { 999 ButtonLen = wcslen(mbd.ppszButtonText[i]); 1000 1001 dest = ALIGN_UP_POINTER(dest, DWORD); 1002 ibtn = (DLGITEMTEMPLATE *)dest; 1003 1004 ibtn->style = WS_CHILD | WS_VISIBLE | WS_TABSTOP; 1005 if (i == mbd.uDefButton) 1006 ibtn->style |= BS_DEFPUSHBUTTON; 1007 else 1008 ibtn->style |= BS_PUSHBUTTON; 1009 1010 ibtn->dwExtendedStyle = 0; 1011 ibtn->id = mbd.pidButton[i]; 1012 dest += sizeof(DLGITEMTEMPLATE); 1013 *(WORD*)dest = 0xFFFF; 1014 dest += sizeof(WORD); 1015 *(WORD*)dest = 0x0080; /* button control */ 1016 dest += sizeof(WORD); 1017 memcpy(dest, mbd.ppszButtonText[i], ButtonLen * sizeof(WCHAR)); 1018 dest += ButtonLen * sizeof(WCHAR); 1019 *(WORD*)dest = 0; 1020 dest += sizeof(WORD); 1021 *(WORD*)dest = 0; 1022 dest += sizeof(WORD); 1023 1024 ibtn->x = RESCALE_X(btnleft, units); 1025 ibtn->y = RESCALE_Y(btntop, units); 1026 ibtn->cx = RESCALE_X(btnsize.cx, units); 1027 ibtn->cy = RESCALE_Y(btnsize.cy, units); 1028 btnleft += btnsize.cx + MSGBOXEX_BUTTONSPACING; 1029 } 1030 1031 /* Calculate the size and position of the message-box window */ 1032 btnleft = max(btnleft - MSGBOXEX_BUTTONSPACING, rc.left + txtrect.right); 1033 btnleft += MSGBOXEX_MARGIN; 1034 if (mbd.dwButtons > 0) 1035 btntop += btnsize.cy + MSGBOXEX_MARGIN; 1036 1037 /* Set the size and position of the static message */ 1038 itxt->x = RESCALE_X(rc.left, units); 1039 itxt->y = RESCALE_Y(rc.top, units); 1040 itxt->cx = RESCALE_X(btnleft - rc.left - MSGBOXEX_MARGIN, units); 1041 itxt->cy = RESCALE_Y(txtrect.bottom, units); 1042 1043 /* Set the size of the window */ 1044 tpl->cx = RESCALE_X(btnleft, units); 1045 tpl->cy = RESCALE_Y(btntop, units); 1046 1047 /* Finally show the message-box */ 1048 ERR("MessageBox: %s\n", wine_dbgstr_wn(lpMsgBoxParams->lpszText, textlen)); 1049 ret = DialogBoxIndirectParamW(lpMsgBoxParams->hInstance, tpl, 1050 lpMsgBoxParams->hwndOwner, 1051 MessageBoxProc, (LPARAM)&mbd); 1052 1053 Quit: 1054 if (buf) 1055 RtlFreeHeap(RtlGetProcessHeap(), 0, buf); 1056 1057 if (text) 1058 RtlFreeHeap(RtlGetProcessHeap(), 0, text); 1059 1060 if (caption) 1061 RtlFreeHeap(RtlGetProcessHeap(), 0, caption); 1062 1063 return ret; 1064 } 1065 1066 1067 /* FUNCTIONS *****************************************************************/ 1068 1069 /* 1070 * @implemented 1071 */ 1072 int 1073 WINAPI 1074 MessageBoxA( 1075 IN HWND hWnd, 1076 IN LPCSTR lpText, 1077 IN LPCSTR lpCaption, 1078 IN UINT uType) 1079 { 1080 return MessageBoxExA(hWnd, lpText, lpCaption, uType, LANG_NEUTRAL); 1081 } 1082 1083 /* 1084 * @implemented 1085 */ 1086 int 1087 WINAPI 1088 MessageBoxW( 1089 IN HWND hWnd, 1090 IN LPCWSTR lpText, 1091 IN LPCWSTR lpCaption, 1092 IN UINT uType) 1093 { 1094 return MessageBoxExW(hWnd, lpText, lpCaption, uType, LANG_NEUTRAL); 1095 } 1096 1097 1098 /* 1099 * @implemented 1100 */ 1101 int 1102 WINAPI 1103 MessageBoxExA( 1104 IN HWND hWnd, 1105 IN LPCSTR lpText, 1106 IN LPCSTR lpCaption, 1107 IN UINT uType, 1108 IN WORD wLanguageId) 1109 { 1110 MSGBOXPARAMSA msgbox; 1111 1112 msgbox.cbSize = sizeof(msgbox); 1113 msgbox.hwndOwner = hWnd; 1114 msgbox.hInstance = 0; 1115 msgbox.lpszText = lpText; 1116 msgbox.lpszCaption = lpCaption; 1117 msgbox.dwStyle = uType; 1118 msgbox.lpszIcon = NULL; 1119 msgbox.dwContextHelpId = 0; 1120 msgbox.lpfnMsgBoxCallback = NULL; 1121 msgbox.dwLanguageId = wLanguageId; 1122 1123 return MessageBoxIndirectA(&msgbox); 1124 } 1125 1126 /* 1127 * @implemented 1128 */ 1129 int 1130 WINAPI 1131 MessageBoxExW( 1132 IN HWND hWnd, 1133 IN LPCWSTR lpText, 1134 IN LPCWSTR lpCaption, 1135 IN UINT uType, 1136 IN WORD wLanguageId) 1137 { 1138 MSGBOXPARAMSW msgbox; 1139 1140 msgbox.cbSize = sizeof(msgbox); 1141 msgbox.hwndOwner = hWnd; 1142 msgbox.hInstance = 0; 1143 msgbox.lpszText = lpText; 1144 msgbox.lpszCaption = lpCaption; 1145 msgbox.dwStyle = uType; 1146 msgbox.lpszIcon = NULL; 1147 msgbox.dwContextHelpId = 0; 1148 msgbox.lpfnMsgBoxCallback = NULL; 1149 msgbox.dwLanguageId = wLanguageId; 1150 1151 return MessageBoxTimeoutIndirectW(&msgbox, (UINT)-1); 1152 } 1153 1154 1155 /* 1156 * @implemented 1157 */ 1158 int 1159 WINAPI 1160 MessageBoxIndirectA( 1161 IN CONST MSGBOXPARAMSA* lpMsgBoxParams) 1162 { 1163 MSGBOXPARAMSW msgboxW; 1164 UNICODE_STRING textW, captionW, iconW; 1165 int ret; 1166 1167 if (!IS_INTRESOURCE(lpMsgBoxParams->lpszText)) 1168 { 1169 RtlCreateUnicodeStringFromAsciiz(&textW, (PCSZ)lpMsgBoxParams->lpszText); 1170 /* 1171 * UNICODE_STRING objects are always allocated with an extra byte so you 1172 * can null-term if you want 1173 */ 1174 textW.Buffer[textW.Length / sizeof(WCHAR)] = L'\0'; 1175 } 1176 else 1177 textW.Buffer = (LPWSTR)lpMsgBoxParams->lpszText; 1178 1179 if (!IS_INTRESOURCE(lpMsgBoxParams->lpszCaption)) 1180 { 1181 RtlCreateUnicodeStringFromAsciiz(&captionW, (PCSZ)lpMsgBoxParams->lpszCaption); 1182 /* 1183 * UNICODE_STRING objects are always allocated with an extra byte so you 1184 * can null-term if you want 1185 */ 1186 captionW.Buffer[captionW.Length / sizeof(WCHAR)] = L'\0'; 1187 } 1188 else 1189 captionW.Buffer = (LPWSTR)lpMsgBoxParams->lpszCaption; 1190 1191 if (lpMsgBoxParams->dwStyle & MB_USERICON) 1192 { 1193 if (!IS_INTRESOURCE(lpMsgBoxParams->lpszIcon)) 1194 { 1195 RtlCreateUnicodeStringFromAsciiz(&iconW, (PCSZ)lpMsgBoxParams->lpszIcon); 1196 /* 1197 * UNICODE_STRING objects are always allocated with an extra byte so you 1198 * can null-term if you want 1199 */ 1200 iconW.Buffer[iconW.Length / sizeof(WCHAR)] = L'\0'; 1201 } 1202 else 1203 iconW.Buffer = (LPWSTR)lpMsgBoxParams->lpszIcon; 1204 } 1205 else 1206 iconW.Buffer = NULL; 1207 1208 msgboxW.cbSize = sizeof(msgboxW); 1209 msgboxW.hwndOwner = lpMsgBoxParams->hwndOwner; 1210 msgboxW.hInstance = lpMsgBoxParams->hInstance; 1211 msgboxW.lpszText = textW.Buffer; 1212 msgboxW.lpszCaption = captionW.Buffer; 1213 msgboxW.dwStyle = lpMsgBoxParams->dwStyle; 1214 msgboxW.lpszIcon = iconW.Buffer; 1215 msgboxW.dwContextHelpId = lpMsgBoxParams->dwContextHelpId; 1216 msgboxW.lpfnMsgBoxCallback = lpMsgBoxParams->lpfnMsgBoxCallback; 1217 msgboxW.dwLanguageId = lpMsgBoxParams->dwLanguageId; 1218 1219 ret = MessageBoxTimeoutIndirectW(&msgboxW, (UINT)-1); 1220 1221 if (!IS_INTRESOURCE(lpMsgBoxParams->lpszText)) 1222 RtlFreeUnicodeString(&textW); 1223 1224 if (!IS_INTRESOURCE(lpMsgBoxParams->lpszCaption)) 1225 RtlFreeUnicodeString(&captionW); 1226 1227 if ((lpMsgBoxParams->dwStyle & MB_USERICON) && !IS_INTRESOURCE(iconW.Buffer)) 1228 RtlFreeUnicodeString(&iconW); 1229 1230 return ret; 1231 } 1232 1233 /* 1234 * @implemented 1235 */ 1236 int 1237 WINAPI 1238 MessageBoxIndirectW( 1239 IN CONST MSGBOXPARAMSW* lpMsgBoxParams) 1240 { 1241 return MessageBoxTimeoutIndirectW(lpMsgBoxParams, (UINT)-1); 1242 } 1243 1244 1245 /* 1246 * @implemented 1247 */ 1248 int 1249 WINAPI 1250 MessageBoxTimeoutA( 1251 IN HWND hWnd, 1252 IN LPCSTR lpText, 1253 IN LPCSTR lpCaption, 1254 IN UINT uType, 1255 IN WORD wLanguageId, 1256 IN DWORD dwTimeout) 1257 { 1258 MSGBOXPARAMSW msgboxW; 1259 UNICODE_STRING textW, captionW; 1260 int ret; 1261 1262 if (!IS_INTRESOURCE(lpText)) 1263 RtlCreateUnicodeStringFromAsciiz(&textW, (PCSZ)lpText); 1264 else 1265 textW.Buffer = (LPWSTR)lpText; 1266 1267 if (!IS_INTRESOURCE(lpCaption)) 1268 RtlCreateUnicodeStringFromAsciiz(&captionW, (PCSZ)lpCaption); 1269 else 1270 captionW.Buffer = (LPWSTR)lpCaption; 1271 1272 msgboxW.cbSize = sizeof(msgboxW); 1273 msgboxW.hwndOwner = hWnd; 1274 msgboxW.hInstance = 0; 1275 msgboxW.lpszText = textW.Buffer; 1276 msgboxW.lpszCaption = captionW.Buffer; 1277 msgboxW.dwStyle = uType; 1278 msgboxW.lpszIcon = NULL; 1279 msgboxW.dwContextHelpId = 0; 1280 msgboxW.lpfnMsgBoxCallback = NULL; 1281 msgboxW.dwLanguageId = wLanguageId; 1282 1283 ret = MessageBoxTimeoutIndirectW(&msgboxW, (UINT)dwTimeout); 1284 1285 if (!IS_INTRESOURCE(textW.Buffer)) 1286 RtlFreeUnicodeString(&textW); 1287 1288 if (!IS_INTRESOURCE(captionW.Buffer)) 1289 RtlFreeUnicodeString(&captionW); 1290 1291 return ret; 1292 } 1293 1294 /* 1295 * @implemented 1296 */ 1297 int 1298 WINAPI 1299 MessageBoxTimeoutW( 1300 IN HWND hWnd, 1301 IN LPCWSTR lpText, 1302 IN LPCWSTR lpCaption, 1303 IN UINT uType, 1304 IN WORD wLanguageId, 1305 IN DWORD dwTimeout) 1306 { 1307 MSGBOXPARAMSW msgbox; 1308 1309 msgbox.cbSize = sizeof(msgbox); 1310 msgbox.hwndOwner = hWnd; 1311 msgbox.hInstance = 0; 1312 msgbox.lpszText = lpText; 1313 msgbox.lpszCaption = lpCaption; 1314 msgbox.dwStyle = uType; 1315 msgbox.lpszIcon = NULL; 1316 msgbox.dwContextHelpId = 0; 1317 msgbox.lpfnMsgBoxCallback = NULL; 1318 msgbox.dwLanguageId = wLanguageId; 1319 1320 return MessageBoxTimeoutIndirectW(&msgbox, (UINT)dwTimeout); 1321 } 1322 1323 1324 /* 1325 * @implemented 1326 */ 1327 BOOL 1328 WINAPI 1329 MessageBeep( 1330 IN UINT uType) 1331 { 1332 return NtUserxMessageBeep(uType); 1333 } 1334 1335 1336 /* 1337 * @implemented 1338 * 1339 * See: https://msdn.microsoft.com/en-us/library/windows/desktop/dn910915(v=vs.85).aspx 1340 * and: http://undoc.airesoft.co.uk/user32.dll/MB_GetString.php 1341 * for more information. 1342 */ 1343 LPCWSTR 1344 WINAPI 1345 MB_GetString( 1346 IN UINT wBtn) 1347 { 1348 static BOOL bCached = FALSE; 1349 static MBSTRING MBStrings[MAX_MB_STRINGS]; // FIXME: Use gpsi->MBStrings when this is loaded by Win32k! 1350 1351 // 1352 // FIXME - TODO: The gpsi->MBStrings[] array should be loaded by win32k! 1353 // 1354 ASSERT(IDCONTINUE <= MAX_MB_STRINGS); 1355 if (!bCached) 1356 { 1357 UINT i; 1358 for (i = 0; i < MAX_MB_STRINGS; ++i) 1359 { 1360 /*gpsi->*/MBStrings[i].uID = IDOK + i; 1361 /*gpsi->*/MBStrings[i].uStr = IDS_OK + i; // See user32/include/resource.h 1362 LoadStringW(User32Instance, 1363 /*gpsi->*/MBStrings[i].uStr, 1364 /*gpsi->*/MBStrings[i].szName, 1365 ARRAYSIZE(/*gpsi->*/MBStrings[i].szName)); 1366 } 1367 bCached = TRUE; 1368 } 1369 1370 /* 1371 * The allowable IDs are between "IDOK - 1" (0) and "IDCONTINUE - 1" (10) inclusive. 1372 * See psdk/winuser.h and user32/include/resource.h . 1373 */ 1374 if (wBtn > IDCONTINUE - 1) 1375 return NULL; 1376 1377 return /*gpsi->*/MBStrings[wBtn].szName; 1378 } 1379 1380 /* EOF */ 1381