update for HEAD-2003091401
[reactos.git] / lib / user32 / windows / messagebox.c
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 /* $Id$
20  *
21  * PROJECT:         ReactOS user32.dll
22  * FILE:            lib/user32/windows/messagebox.c
23  * PURPOSE:         Input
24  * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
25  *                  Thomas Weidenmueller (w3seek@users.sourceforge.net)
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 /* INCLUDES ******************************************************************/
33
34 #include <windows.h>
35 #include <messages.h>
36 #include <user32.h>
37 #include <string.h>
38 #include <ntos/rtl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <debug.h>
42
43 typedef UINT *LPUINT;
44 #include <mmsystem.h>
45
46 /* DEFINES *******************************************************************/
47
48 #define MSGBOX_IDICON 1088
49 #define MSGBOX_IDTEXT 100
50 #define IDS_ERROR     2
51
52 #define IDI_HANDA          MAKEINTRESOURCEA(32513)
53 #define IDI_HANDW          MAKEINTRESOURCEW(32513)
54 #define IDI_QUESTIONA      MAKEINTRESOURCEA(32514)
55 #define IDI_QUESTIONW      MAKEINTRESOURCEW(32514)
56 #define IDI_EXCLAMATIONA   MAKEINTRESOURCEA(32515)
57 #define IDI_EXCLAMATIONW   MAKEINTRESOURCEW(32515)
58 #define IDI_ASTERISKA      MAKEINTRESOURCEA(32516)
59 #define IDI_ASTERISKW      MAKEINTRESOURCEW(32516)
60 #define IDI_WINLOGOA       MAKEINTRESOURCEA(32517)
61 #define IDI_WINLOGOW       MAKEINTRESOURCEW(32517)
62
63 #ifndef MB_TYPEMASK
64 #define MB_TYPEMASK             0x0000000F
65 #endif
66 #ifndef MB_ICONMASK
67 #define MB_ICONMASK             0x000000F0
68 #endif
69 #ifndef MB_DEFMASK
70 #define MB_DEFMASK              0x00000F00
71 #endif
72
73 #define DWL_INIT (12)
74
75 /* FUNCTIONS *****************************************************************/
76
77 static HWND MSGBOX_CreateButton(HWND hwnd, LONG ID, LPWSTR Caption)
78 {
79   return CreateWindowExW(0, L"BUTTON", Caption, WS_CHILD | WS_TABSTOP | WS_VISIBLE,
80                         0, 0, 10, 10, hwnd, (HMENU)ID, 0, NULL);
81 }
82
83 static HFONT MSGBOX_OnInit(HWND hwnd, LPMSGBOXPARAMS lpmb)
84 {
85     HFONT hFont = 0, hPrevFont = 0;
86     RECT rect;
87     HWND hItem;
88     HDC hdc;
89     int i;
90     int bspace, bw, bh, theight, tleft, wwidth, wheight, bpos;
91     int borheight, borwidth, iheight, ileft, iwidth, twidth, tiheight;
92     BOOL sdefbtn = FALSE;
93     LPCWSTR lpszText;
94     WCHAR buf[256];
95     NONCLIENTMETRICSW nclm;
96     int nButtons = 0;
97     HWND Buttons[4];
98
99     nclm.cbSize = sizeof(nclm);
100     SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0);
101     hFont = CreateFontIndirectW (&nclm.lfMessageFont);
102     /* set button font */
103     for (i = 1; i < 10; i++)
104         SendDlgItemMessageW (hwnd, i, WM_SETFONT, (WPARAM)hFont, 0);
105     /* set text font */
106     SendDlgItemMessageW (hwnd, MSGBOX_IDTEXT, WM_SETFONT, (WPARAM)hFont, 0);
107
108     if (HIWORD(lpmb->lpszCaption))
109     {
110         SetWindowTextW(hwnd, (LPCWSTR)lpmb->lpszCaption);
111     }
112     else
113     {
114         UINT res_id = LOWORD((UINT)lpmb->lpszCaption); /* FIXME: (UINT) ??? */
115         if (res_id)
116         {
117             if (LoadStringW(lpmb->hInstance, res_id, buf, 256))
118                 SetWindowTextW(hwnd, buf);
119         }
120         else
121         {
122             if (LoadStringW(GetModuleHandleA("user32.dll"), IDS_ERROR, buf, 256))
123                 SetWindowTextW(hwnd, buf);
124         }
125     }
126     if (HIWORD(lpmb->lpszText))
127     {
128         lpszText = (LPCWSTR)lpmb->lpszText;
129     }
130     else
131     {
132        lpszText = buf;
133        if (!LoadStringW(lpmb->hInstance, LOWORD((UINT)lpmb->lpszText), buf, 256)) /* FIXME: (UINT) ??? */
134            *buf = 0;    /* FIXME ?? */
135     }
136
137     /* Create selected buttons */
138     switch(lpmb->dwStyle & MB_TYPEMASK)
139     {
140         case MB_OKCANCEL:
141             Buttons[0] = MSGBOX_CreateButton(hwnd, IDOK, L"OK");
142             Buttons[1] = MSGBOX_CreateButton(hwnd, IDCANCEL, L"Cancel");
143             nButtons = 2;
144             break;
145         case MB_CANCELTRYCONTINUE:
146             Buttons[0] = MSGBOX_CreateButton(hwnd, IDCANCEL, L"Cancel");
147             Buttons[1] = MSGBOX_CreateButton(hwnd, IDTRYAGAIN, L"Try Again");
148             Buttons[2] = MSGBOX_CreateButton(hwnd, IDCONTINUE, L"Continue");
149             nButtons = 3;
150             break;
151         case MB_ABORTRETRYIGNORE:
152             Buttons[0] = MSGBOX_CreateButton(hwnd, IDABORT, L"Abort");
153             Buttons[1] = MSGBOX_CreateButton(hwnd, IDRETRY, L"Retry");
154             Buttons[2] = MSGBOX_CreateButton(hwnd, IDIGNORE, L"Ignore");
155             nButtons = 3;
156             break;
157         case MB_YESNO:
158             Buttons[0] = MSGBOX_CreateButton(hwnd, IDYES, L"Yes");
159             Buttons[1] = MSGBOX_CreateButton(hwnd, IDNO, L"No");
160             nButtons = 2;
161             break;
162         case MB_YESNOCANCEL:
163             Buttons[0] = MSGBOX_CreateButton(hwnd, IDYES, L"Yes");
164             Buttons[1] = MSGBOX_CreateButton(hwnd, IDNO, L"No");
165             Buttons[2] = MSGBOX_CreateButton(hwnd, IDCANCEL, L"Cancel");
166             nButtons = 3;
167             break;
168         case MB_RETRYCANCEL:
169             Buttons[0] = MSGBOX_CreateButton(hwnd, IDRETRY, L"Retry");
170             Buttons[1] = MSGBOX_CreateButton(hwnd, IDCANCEL, L"Cancel");
171             nButtons = 2;
172             break;
173         case MB_OK:
174             /* fall through */
175         default:
176             Buttons[0] = MSGBOX_CreateButton(hwnd, IDOK, L"OK");
177             nButtons = 1;
178             break;
179     }
180     /* Create Help button */
181     if(lpmb->dwStyle & MB_HELP)
182       Buttons[nButtons++] = MSGBOX_CreateButton(hwnd, IDHELP, L"Help");
183
184     /* Set the icon */
185     switch(lpmb->dwStyle & MB_ICONMASK)
186     {
187         case MB_ICONEXCLAMATION:
188             SendDlgItemMessageW(hwnd, 0x0440, STM_SETICON,
189                 (WPARAM)LoadIconW(0, IDI_EXCLAMATIONW), 0);
190             MessageBeep(MB_ICONEXCLAMATION);
191             break;
192         case MB_ICONQUESTION:
193             SendDlgItemMessageW(hwnd, 0x0440, STM_SETICON,
194                 (WPARAM)LoadIconW(0, IDI_QUESTIONW), 0);
195             MessageBeep(MB_ICONQUESTION);
196             break;
197         case MB_ICONASTERISK:
198             SendDlgItemMessageW(hwnd, 0x0440, STM_SETICON,
199                 (WPARAM)LoadIconW(0, IDI_ASTERISKW), 0);
200             MessageBeep(MB_ICONASTERISK);
201             break;
202         case MB_ICONHAND:
203             SendDlgItemMessageW(hwnd, 0x0440, STM_SETICON,
204                 (WPARAM)LoadIconW(0, IDI_HANDW), 0);
205             MessageBeep(MB_ICONHAND);
206             break;
207         case MB_USERICON:
208             SendDlgItemMessageW(hwnd, 0x0440, STM_SETICON,
209                 (WPARAM)LoadIconW(lpmb->hInstance, (LPCWSTR)lpmb->lpszIcon), 0);
210             MessageBeep(MB_OK);
211         break;
212         default:
213             /* By default, Windows 95/98/NT does not associate an icon to message boxes.
214              * So ReactOS should do the same.
215              */
216             MessageBeep(MB_OK);
217         break;
218     }
219
220     /* Position everything */
221     GetWindowRect(hwnd, &rect);
222     borheight = rect.bottom - rect.top;
223     borwidth  = rect.right - rect.left;
224     GetClientRect(hwnd, &rect);
225     borheight -= rect.bottom;
226     borwidth  -= rect.right;
227
228     /* Get the icon height */
229     GetWindowRect(GetDlgItem(hwnd, MSGBOX_IDICON), &rect);
230     if (!(lpmb->dwStyle & MB_ICONMASK))
231     {
232         rect.bottom = rect.top;
233         rect.right = rect.left;
234     }
235     iheight = rect.bottom - rect.top;
236     ileft = rect.left;
237     iwidth = rect.right - ileft;
238
239     hdc = GetDC(hwnd);
240     if (hFont)
241         hPrevFont = SelectObject(hdc, hFont);
242
243     /* Calculate the button's sizes */
244     bh = bw = 1; // Minimum button sizes 
245     for(i = 0; i <= nButtons; i++)
246     {
247       WCHAR buttonText[1024];
248       int w, h;
249       if (GetWindowTextW(Buttons[i], buttonText, 1024))
250       {
251         DrawTextW(hdc, buttonText, -1, &rect, DT_LEFT | DT_EXPANDTABS | DT_CALCRECT);
252         h = rect.bottom - rect.top;
253         w = rect.right - rect.left;
254         if (h > bh)
255           bh = h;
256         if (w > bw)
257           bw = w ;
258       }
259     }
260     
261     bw = max(bw, bh * 2);
262     /* Button white space */
263     bh = bh * 2 - 4;
264     bw = bw * 2;
265     bspace = 10; /* Fixed space between buttons */
266
267     /* Get the text size */
268     GetClientRect(GetDlgItem(hwnd, MSGBOX_IDTEXT), &rect);
269     rect.top = rect.left = rect.bottom = 0;
270     rect.right = (((GetSystemMetrics(SM_CXSCREEN) - borwidth) * 4) / 5);
271     DrawTextW( hdc, lpszText, -1, &rect,
272               DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_CALCRECT);
273
274     /* Min text width corresponds to space for the buttons */
275     tleft = ileft;
276     if (iwidth)
277         tleft += ileft + iwidth;
278     twidth = max((LONG) (((bw + bspace) * nButtons) + bspace - tleft), rect.right);
279     theight = rect.bottom;
280
281     if (hFont)
282         SelectObject(hdc, hPrevFont);
283     ReleaseDC(hItem, hdc);
284
285     tiheight = 16 + max(iheight, theight) + 16;
286     wwidth  = tleft + twidth + ileft + borwidth;
287     wheight = 8 + tiheight + bh + borheight;
288
289     /* Resize the window */
290     SetWindowPos(hwnd, 0, 0, 0, wwidth, wheight,
291                  SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
292
293     /* Position the icon */
294     SetWindowPos(GetDlgItem(hwnd, MSGBOX_IDICON), 0, ileft, (tiheight - iheight) / 2, 0, 0,
295                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
296
297     /* Position the text */
298     SetWindowPos(GetDlgItem(hwnd, MSGBOX_IDTEXT), 0, tleft, (tiheight - theight) / 2, twidth, theight,
299                  SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
300     SetWindowTextW(GetDlgItem(hwnd, MSGBOX_IDTEXT), lpszText);
301
302     /* Position the buttons */
303     bpos = (wwidth - ((bw + bspace) * nButtons) + bspace) / 2;
304     for(i = 0; i <= nButtons; i++)
305     {
306       if (i == ((lpmb->dwStyle & MB_DEFMASK) >> 8))
307       {
308         SetFocus(Buttons[i]);
309         SendMessageW(Buttons[i], BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE);
310         sdefbtn = TRUE;
311       }
312       SetWindowPos(Buttons[i], 0, bpos, tiheight, bw, bh,
313                    SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
314       bpos += bw + bspace;
315     }
316
317     /* if there's no (valid) default selection, select first button */
318     if(!sdefbtn)
319     {
320       SetFocus(Buttons[0]);
321       SendMessageW(Buttons[0], BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE);
322     }
323
324     if(lpmb->dwStyle & MB_RIGHT)
325     {
326         hItem = GetDlgItem(hwnd, MSGBOX_IDTEXT);
327         SetWindowLongW(hItem, GWL_STYLE, 
328                       GetWindowLongW(hItem, GWL_STYLE) | SS_RIGHT);
329     }
330
331     /* handle modal MessageBoxes */
332     if (lpmb->dwStyle & (MB_TASKMODAL|MB_SYSTEMMODAL))
333     {
334         DbgPrint("%s modal msgbox ! Not modal yet.\n",
335                  lpmb->dwStyle & MB_TASKMODAL ? "task" : "system");
336         /* Probably do EnumTaskWindows etc. here for TASKMODAL
337          * and work your way up to the top - I'm lazy (HWND_TOP) */
338         SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
339                      SWP_NOSIZE | SWP_NOMOVE);
340         if (lpmb->dwStyle & MB_TASKMODAL)
341             /* at least MB_TASKMODAL seems to imply a ShowWindow */
342             ShowWindow(hwnd, SW_SHOW);
343     }
344
345     if (lpmb->dwStyle & MB_APPLMODAL)
346         DbgPrint("app modal msgbox ! Not modal yet.\n");
347
348     return hFont;
349 }
350
351
352 /**************************************************************************
353  *           MSGBOX_DlgProc
354  *
355  * Dialog procedure for message boxes.
356  */
357 static INT_PTR CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message,
358                                         WPARAM wParam, LPARAM lParam )
359 {
360   HFONT hFont;
361   HELPINFO hi;
362
363   switch(message) {
364    case WM_INITDIALOG:
365    {
366        if(GetWindowLongA(hwnd, DWL_INIT))
367        {
368             LPMSGBOXPARAMS mbp = (LPMSGBOXPARAMS)lParam;
369             SetWindowLongA(hwnd, DWL_INIT, (LONG)mbp);
370             SetWindowContextHelpId(hwnd, mbp->dwContextHelpId);
371             hFont = MSGBOX_OnInit(hwnd, mbp);
372             SetPropA(hwnd, "ROS_MSGBOX_HFONT", (HANDLE)hFont);
373             SetPropA(hwnd, "ROS_MSGBOX_HELPCALLBACK", (HANDLE)mbp->lpfnMsgBoxCallback);
374             return 1;
375        }
376        return 0;
377    }
378
379    case WM_COMMAND:
380     switch (LOWORD(wParam))
381     {
382      case IDOK:
383      case IDCANCEL:
384      case IDABORT:
385      case IDRETRY:
386      case IDIGNORE:
387      case IDYES:
388      case IDNO:
389      case IDTRYAGAIN:
390      case IDCONTINUE:
391       hFont = GetPropA(hwnd, "ROS_MSGBOX_HFONT");
392       EndDialog(hwnd, wParam);
393       if (hFont)
394         DeleteObject(hFont);
395       return 0;
396     case IDHELP:
397       /* send WM_HELP message to messagebox window */
398       hi.cbSize = sizeof(HELPINFO);
399       hi.iContextType = HELPINFO_WINDOW;
400       hi.iCtrlId = LOWORD(wParam);
401       hi.hItemHandle = (HANDLE)lParam;
402       hi.dwContextId = 0;
403       GetCursorPos(&hi.MousePos);
404       SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi);
405       return 0;
406     }
407     return 0;
408
409     case WM_HELP:
410     {
411         MSGBOXCALLBACK callback = (MSGBOXCALLBACK)GetPropA(hwnd, "ROS_MSGBOX_HELPCALLBACK");
412
413         memcpy(&hi, (void *)lParam, sizeof(hi));
414         hi.dwContextId = GetWindowContextHelpId(hwnd);
415
416         if (callback)
417             callback(&hi);
418         else {
419             HWND owner = GetWindow(hwnd, GW_OWNER);
420             if(owner)
421             SendMessageW(GetWindow(hwnd, GW_OWNER), WM_HELP, 0, (LPARAM)&hi);
422             }
423         return 0;
424     }
425   }
426   return 0;
427 }
428
429
430 /*
431  * @implemented
432  */
433 int
434 STDCALL
435 MessageBoxA(
436   HWND hWnd,
437   LPCSTR lpText,
438   LPCSTR lpCaption,
439   UINT uType)
440 {
441     return MessageBoxExA(hWnd, lpText, lpCaption, uType, LANG_NEUTRAL);
442 }
443
444
445 /*
446  * @implemented
447  */
448 int
449 STDCALL
450 MessageBoxExA(
451   HWND hWnd,
452   LPCSTR lpText,
453   LPCSTR lpCaption,
454   UINT uType,
455   WORD wLanguageId)
456 {
457     MSGBOXPARAMS msgbox;
458
459     msgbox.cbSize = sizeof(msgbox);
460     msgbox.hwndOwner = hWnd;
461     msgbox.hInstance = 0;
462     msgbox.lpszText = lpText;
463     msgbox.lpszCaption = lpCaption;
464     msgbox.dwStyle = uType;
465     msgbox.lpszIcon = NULL;
466     msgbox.dwContextHelpId = 0;
467     msgbox.lpfnMsgBoxCallback = NULL;
468     msgbox.dwLanguageId = wLanguageId;
469
470     return MessageBoxIndirectA(&msgbox);
471 }
472
473
474 /*
475  * @implemented
476  */
477 int
478 STDCALL
479 MessageBoxExW(
480   HWND hWnd,
481   LPCWSTR lpText,
482   LPCWSTR lpCaption,
483   UINT uType,
484   WORD wLanguageId)
485 {
486     MSGBOXPARAMS msgbox;
487
488     msgbox.cbSize = sizeof(msgbox);
489     msgbox.hwndOwner = hWnd;
490     msgbox.hInstance = 0;
491     msgbox.lpszText = (LPCSTR)lpText;
492     msgbox.lpszCaption =(LPCSTR) lpCaption;
493     msgbox.dwStyle = uType;
494     msgbox.lpszIcon = NULL;
495     msgbox.dwContextHelpId = 0;
496     msgbox.lpfnMsgBoxCallback = NULL;
497     msgbox.dwLanguageId = wLanguageId;
498
499     return MessageBoxIndirectW(&msgbox);
500 }
501
502
503 /*
504  * @implemented
505  */
506 int
507 STDCALL
508 MessageBoxIndirectA(
509   CONST LPMSGBOXPARAMS lpMsgBoxParams)
510 {
511     MSGBOXPARAMS msgboxW;
512     UNICODE_STRING textW, captionW, iconW;
513     int ret;
514
515     if (HIWORD((UINT)lpMsgBoxParams->lpszText))
516         RtlCreateUnicodeStringFromAsciiz(&textW, (PCSZ)lpMsgBoxParams->lpszText);
517     else
518         textW.Buffer = (LPWSTR)lpMsgBoxParams->lpszText;
519
520     if (HIWORD((UINT)lpMsgBoxParams->lpszCaption))
521         RtlCreateUnicodeStringFromAsciiz(&captionW, (PCSZ)lpMsgBoxParams->lpszCaption);
522     else
523         captionW.Buffer = (LPWSTR)lpMsgBoxParams->lpszCaption;
524
525     if (HIWORD((UINT)lpMsgBoxParams->lpszIcon))
526         RtlCreateUnicodeStringFromAsciiz(&iconW, (PCSZ)lpMsgBoxParams->lpszIcon);
527     else
528         iconW.Buffer = (LPWSTR)lpMsgBoxParams->lpszIcon;
529
530     msgboxW.cbSize = sizeof(msgboxW);
531     msgboxW.hwndOwner = lpMsgBoxParams->hwndOwner;
532     msgboxW.hInstance = lpMsgBoxParams->hInstance;
533     msgboxW.lpszText = (LPCSTR)textW.Buffer;
534     msgboxW.lpszCaption = (LPCSTR)captionW.Buffer;
535     msgboxW.dwStyle = lpMsgBoxParams->dwStyle;
536     msgboxW.lpszIcon = (LPCSTR)iconW.Buffer;
537     msgboxW.dwContextHelpId = lpMsgBoxParams->dwContextHelpId;
538     msgboxW.lpfnMsgBoxCallback = lpMsgBoxParams->lpfnMsgBoxCallback;
539     msgboxW.dwLanguageId = lpMsgBoxParams->dwLanguageId;
540
541     ret = MessageBoxIndirectW(&msgboxW);
542
543     if (HIWORD(textW.Buffer))
544         RtlFreeUnicodeString(&textW);
545
546     if (HIWORD(captionW.Buffer))
547         RtlFreeUnicodeString(&captionW);
548
549     if (HIWORD(iconW.Buffer))
550         RtlFreeUnicodeString(&iconW);
551
552     return ret;
553 }
554
555
556 /*
557  * @implemented
558  */
559 int
560 STDCALL
561 MessageBoxIndirectW(
562   CONST LPMSGBOXPARAMS lpMsgBoxParams)
563 {
564     LPVOID tmplate, ctmplate;
565     HRSRC hRes;
566     HMODULE hUser32;
567     DWORD ressize;
568     WORD *style;
569     WORD *exstyle;
570
571     hUser32 = GetModuleHandleW(L"user32.dll");
572     if (!(hRes = FindResourceExW(hUser32, RT_DIALOGW, L"MSGBOX", lpMsgBoxParams->dwLanguageId)))
573         return 0;
574
575     if (!(tmplate = (LPVOID)LoadResource(hUser32, hRes)))
576         return 0;
577
578     /* Copy template */
579     ressize = SizeofResource(hUser32, hRes);
580     ctmplate = RtlAllocateHeap(RtlGetProcessHeap(), 0, ressize);
581     RtlMoveMemory(ctmplate, tmplate, ressize);
582
583     /* change dialog's style in the template before 
584        passing it to DialogBoxIndirectParamW        */
585
586     style = (WORD *)ctmplate;
587     exstyle = style + 2;
588     if(*(DWORD*)style == 0xffff0001)   /* DIALOGEX resource */
589     {
590         /* skip help id */
591         exstyle = style + 4;
592         style = exstyle + 2;
593     }
594
595     /* change window style before creating it */
596     if(lpMsgBoxParams->dwStyle & MB_RIGHT)
597         *exstyle = (WORD)(*(DWORD*)exstyle | WS_EX_RIGHT);
598     if(lpMsgBoxParams->dwStyle & MB_TOPMOST)
599         *exstyle = (WORD)(*(DWORD*)exstyle | WS_EX_TOPMOST);
600
601     return DialogBoxIndirectParamW(lpMsgBoxParams->hInstance, ctmplate, lpMsgBoxParams->hwndOwner,
602                                    MSGBOX_DlgProc, (LPARAM)lpMsgBoxParams);
603
604     RtlFreeHeap(RtlGetProcessHeap(), 0, ctmplate);
605 }
606
607
608 /*
609  * @implemented
610  */
611 int
612 STDCALL
613 MessageBoxW(
614   HWND hWnd,
615   LPCWSTR lpText,
616   LPCWSTR lpCaption,
617   UINT uType)
618 {
619     return MessageBoxExW(hWnd, lpText, lpCaption, uType, LANG_NEUTRAL);
620 }
621
622
623 /*
624  * @unimplemented
625  */
626 DWORD
627 STDCALL
628 SoftModalMessageBox(DWORD Unknown0)
629 {
630   UNIMPLEMENTED;
631   return 0;
632 }
633
634
635 /*
636  * @implemented
637  */
638 WINBOOL
639 STDCALL
640 MessageBeep(UINT uType)
641 {
642 #if 0
643   LPWSTR EventName;
644
645   switch(uType)
646   {
647     case 0xFFFFFFFF:
648       if(waveOutGetNumDevs() == 0)
649         return Beep(500, 100);    // Beep through speaker
650       /* fall through */
651     case MB_OK: 
652       EventName = L"SystemDefault";
653       break;
654     case MB_ICONASTERISK:
655       EventName = L"SystemAsterisk";
656       break;
657     case MB_ICONEXCLAMATION:
658       EventName = L"SystemExclamation";
659       break;
660     case MB_ICONHAND:
661       EventName = L"SystemHand";
662       break;
663     case MB_ICONQUESTION:
664       EventName = L"SystemQuestion";
665       break;
666   }
667
668   return PlaySoundW((LPCWSTR)EventName, NULL, SND_ALIAS | SND_NOWAIT | SND_NOSTOP | SND_ASYNC);
669 #else
670   return Beep(500, 100);    // Beep through speaker
671 #endif
672 }
673
674 /* EOF */