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
LoadAllocStringW(IN HINSTANCE hInstance OPTIONAL,IN UINT uID,OUT PWSTR * pString,IN PCWSTR pDefaultString OPTIONAL)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 
MessageBoxTextToClipboard(HWND DialogWindow)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 
MessageBoxProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)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
MessageBoxTimeoutIndirectW(CONST MSGBOXPARAMSW * lpMsgBoxParams,UINT dwTimeout)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
SoftModalMessageBox(IN LPMSGBOXDATA lpMsgBoxData)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
MessageBoxA(IN HWND hWnd,IN LPCSTR lpText,IN LPCSTR lpCaption,IN UINT uType)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
MessageBoxW(IN HWND hWnd,IN LPCWSTR lpText,IN LPCWSTR lpCaption,IN UINT uType)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
MessageBoxExA(IN HWND hWnd,IN LPCSTR lpText,IN LPCSTR lpCaption,IN UINT uType,IN WORD wLanguageId)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
MessageBoxExW(IN HWND hWnd,IN LPCWSTR lpText,IN LPCWSTR lpCaption,IN UINT uType,IN WORD wLanguageId)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
MessageBoxIndirectA(IN CONST MSGBOXPARAMSA * lpMsgBoxParams)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
MessageBoxIndirectW(IN CONST MSGBOXPARAMSW * lpMsgBoxParams)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
MessageBoxTimeoutA(IN HWND hWnd,IN LPCSTR lpText,IN LPCSTR lpCaption,IN UINT uType,IN WORD wLanguageId,IN DWORD dwTimeout)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
MessageBoxTimeoutW(IN HWND hWnd,IN LPCWSTR lpText,IN LPCWSTR lpCaption,IN UINT uType,IN WORD wLanguageId,IN DWORD dwTimeout)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
MessageBeep(IN UINT uType)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
MB_GetString(IN UINT wBtn)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