branch update for HEAD-2003091401
[reactos.git] / lib / user32 / windows / messagebox.c
index 63a8663..3049094 100644 (file)
 /* $Id$
  *
  * PROJECT:         ReactOS user32.dll
- * FILE:            lib/user32/windows/input.c
+ * FILE:            lib/user32/windows/messagebox.c
  * PURPOSE:         Input
  * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
+ *                  Thomas Weidenmueller (w3seek@users.sourceforge.net)
  * UPDATE HISTORY:
+ *      2003/07/28  Added some NT features
+ *      2003/07/27  Code ported from wine
  *      09-05-2001  CSH  Created
  */
 
 /* INCLUDES ******************************************************************/
 
 #include <windows.h>
+#include <messages.h>
 #include <user32.h>
+#include <string.h>
+#include <ntos/rtl.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <debug.h>
 
+typedef UINT *LPUINT;
+#include <mmsystem.h>
+
+/* DEFINES *******************************************************************/
+
+#define MSGBOX_IDICON 1088
+#define MSGBOX_IDTEXT 100
+#define IDS_ERROR     2
+
+#define IDI_HANDA          MAKEINTRESOURCEA(32513)
+#define IDI_HANDW          MAKEINTRESOURCEW(32513)
+#define IDI_QUESTIONA      MAKEINTRESOURCEA(32514)
+#define IDI_QUESTIONW      MAKEINTRESOURCEW(32514)
+#define IDI_EXCLAMATIONA   MAKEINTRESOURCEA(32515)
+#define IDI_EXCLAMATIONW   MAKEINTRESOURCEW(32515)
+#define IDI_ASTERISKA      MAKEINTRESOURCEA(32516)
+#define IDI_ASTERISKW      MAKEINTRESOURCEW(32516)
+#define IDI_WINLOGOA       MAKEINTRESOURCEA(32517)
+#define IDI_WINLOGOW       MAKEINTRESOURCEW(32517)
+
+#ifndef MB_TYPEMASK
+#define MB_TYPEMASK             0x0000000F
+#endif
+#ifndef MB_ICONMASK
+#define MB_ICONMASK             0x000000F0
+#endif
+#ifndef MB_DEFMASK
+#define MB_DEFMASK              0x00000F00
+#endif
+
+#define DWL_INIT (12)
+
 /* FUNCTIONS *****************************************************************/
 
+static HWND MSGBOX_CreateButton(HWND hwnd, LONG ID, LPWSTR Caption)
+{
+  return CreateWindowExW(0, L"BUTTON", Caption, WS_CHILD | WS_TABSTOP | WS_VISIBLE,
+                        0, 0, 10, 10, hwnd, (HMENU)ID, 0, NULL);
+}
+
+static HFONT MSGBOX_OnInit(HWND hwnd, LPMSGBOXPARAMS lpmb)
+{
+    HFONT hFont = 0, hPrevFont = 0;
+    RECT rect;
+    HWND hItem;
+    HDC hdc;
+    int i;
+    int bspace, bw, bh, theight, tleft, wwidth, wheight, bpos;
+    int borheight, borwidth, iheight, ileft, iwidth, twidth, tiheight;
+    BOOL sdefbtn = FALSE;
+    LPCWSTR lpszText;
+    WCHAR buf[256];
+    NONCLIENTMETRICSW nclm;
+    int nButtons = 0;
+    HWND Buttons[4];
+
+    nclm.cbSize = sizeof(nclm);
+    SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0);
+    hFont = CreateFontIndirectW (&nclm.lfMessageFont);
+    /* set button font */
+    for (i = 1; i < 10; i++)
+        SendDlgItemMessageW (hwnd, i, WM_SETFONT, (WPARAM)hFont, 0);
+    /* set text font */
+    SendDlgItemMessageW (hwnd, MSGBOX_IDTEXT, WM_SETFONT, (WPARAM)hFont, 0);
+
+    if (HIWORD(lpmb->lpszCaption))
+    {
+        SetWindowTextW(hwnd, (LPCWSTR)lpmb->lpszCaption);
+    }
+    else
+    {
+        UINT res_id = LOWORD((UINT)lpmb->lpszCaption); /* FIXME: (UINT) ??? */
+        if (res_id)
+        {
+            if (LoadStringW(lpmb->hInstance, res_id, buf, 256))
+                SetWindowTextW(hwnd, buf);
+        }
+        else
+        {
+            if (LoadStringW(GetModuleHandleA("user32.dll"), IDS_ERROR, buf, 256))
+                SetWindowTextW(hwnd, buf);
+        }
+    }
+    if (HIWORD(lpmb->lpszText))
+    {
+        lpszText = (LPCWSTR)lpmb->lpszText;
+    }
+    else
+    {
+       lpszText = buf;
+       if (!LoadStringW(lpmb->hInstance, LOWORD((UINT)lpmb->lpszText), buf, 256)) /* FIXME: (UINT) ??? */
+           *buf = 0;   /* FIXME ?? */
+    }
+
+    /* Create selected buttons */
+    switch(lpmb->dwStyle & MB_TYPEMASK)
+    {
+        case MB_OKCANCEL:
+            Buttons[0] = MSGBOX_CreateButton(hwnd, IDOK, L"OK");
+            Buttons[1] = MSGBOX_CreateButton(hwnd, IDCANCEL, L"Cancel");
+            nButtons = 2;
+            break;
+        case MB_CANCELTRYCONTINUE:
+            Buttons[0] = MSGBOX_CreateButton(hwnd, IDCANCEL, L"Cancel");
+            Buttons[1] = MSGBOX_CreateButton(hwnd, IDTRYAGAIN, L"Try Again");
+            Buttons[2] = MSGBOX_CreateButton(hwnd, IDCONTINUE, L"Continue");
+            nButtons = 3;
+            break;
+        case MB_ABORTRETRYIGNORE:
+            Buttons[0] = MSGBOX_CreateButton(hwnd, IDABORT, L"Abort");
+            Buttons[1] = MSGBOX_CreateButton(hwnd, IDRETRY, L"Retry");
+            Buttons[2] = MSGBOX_CreateButton(hwnd, IDIGNORE, L"Ignore");
+            nButtons = 3;
+            break;
+        case MB_YESNO:
+            Buttons[0] = MSGBOX_CreateButton(hwnd, IDYES, L"Yes");
+            Buttons[1] = MSGBOX_CreateButton(hwnd, IDNO, L"No");
+            nButtons = 2;
+            break;
+        case MB_YESNOCANCEL:
+            Buttons[0] = MSGBOX_CreateButton(hwnd, IDYES, L"Yes");
+            Buttons[1] = MSGBOX_CreateButton(hwnd, IDNO, L"No");
+            Buttons[2] = MSGBOX_CreateButton(hwnd, IDCANCEL, L"Cancel");
+            nButtons = 3;
+            break;
+        case MB_RETRYCANCEL:
+            Buttons[0] = MSGBOX_CreateButton(hwnd, IDRETRY, L"Retry");
+            Buttons[1] = MSGBOX_CreateButton(hwnd, IDCANCEL, L"Cancel");
+            nButtons = 2;
+            break;
+        case MB_OK:
+            /* fall through */
+        default:
+            Buttons[0] = MSGBOX_CreateButton(hwnd, IDOK, L"OK");
+            nButtons = 1;
+            break;
+    }
+    /* Create Help button */
+    if(lpmb->dwStyle & MB_HELP)
+      Buttons[nButtons++] = MSGBOX_CreateButton(hwnd, IDHELP, L"Help");
+
+    /* Set the icon */
+    switch(lpmb->dwStyle & MB_ICONMASK)
+    {
+        case MB_ICONEXCLAMATION:
+            SendDlgItemMessageW(hwnd, 0x0440, STM_SETICON,
+                (WPARAM)LoadIconW(0, IDI_EXCLAMATIONW), 0);
+            MessageBeep(MB_ICONEXCLAMATION);
+            break;
+        case MB_ICONQUESTION:
+            SendDlgItemMessageW(hwnd, 0x0440, STM_SETICON,
+                (WPARAM)LoadIconW(0, IDI_QUESTIONW), 0);
+            MessageBeep(MB_ICONQUESTION);
+            break;
+        case MB_ICONASTERISK:
+            SendDlgItemMessageW(hwnd, 0x0440, STM_SETICON,
+                (WPARAM)LoadIconW(0, IDI_ASTERISKW), 0);
+            MessageBeep(MB_ICONASTERISK);
+            break;
+        case MB_ICONHAND:
+            SendDlgItemMessageW(hwnd, 0x0440, STM_SETICON,
+                (WPARAM)LoadIconW(0, IDI_HANDW), 0);
+            MessageBeep(MB_ICONHAND);
+            break;
+        case MB_USERICON:
+            SendDlgItemMessageW(hwnd, 0x0440, STM_SETICON,
+                (WPARAM)LoadIconW(lpmb->hInstance, (LPCWSTR)lpmb->lpszIcon), 0);
+            MessageBeep(MB_OK);
+        break;
+        default:
+            /* By default, Windows 95/98/NT does not associate an icon to message boxes.
+             * So ReactOS should do the same.
+             */
+            MessageBeep(MB_OK);
+        break;
+    }
+
+    /* Position everything */
+    GetWindowRect(hwnd, &rect);
+    borheight = rect.bottom - rect.top;
+    borwidth  = rect.right - rect.left;
+    GetClientRect(hwnd, &rect);
+    borheight -= rect.bottom;
+    borwidth  -= rect.right;
+
+    /* Get the icon height */
+    GetWindowRect(GetDlgItem(hwnd, MSGBOX_IDICON), &rect);
+    if (!(lpmb->dwStyle & MB_ICONMASK))
+    {
+        rect.bottom = rect.top;
+        rect.right = rect.left;
+    }
+    iheight = rect.bottom - rect.top;
+    ileft = rect.left;
+    iwidth = rect.right - ileft;
+
+    hdc = GetDC(hwnd);
+    if (hFont)
+        hPrevFont = SelectObject(hdc, hFont);
+
+    /* Calculate the button's sizes */
+    bh = bw = 1; // Minimum button sizes 
+    for(i = 0; i <= nButtons; i++)
+    {
+      WCHAR buttonText[1024];
+      int w, h;
+      if (GetWindowTextW(Buttons[i], buttonText, 1024))
+      {
+        DrawTextW(hdc, buttonText, -1, &rect, DT_LEFT | DT_EXPANDTABS | DT_CALCRECT);
+        h = rect.bottom - rect.top;
+        w = rect.right - rect.left;
+        if (h > bh)
+          bh = h;
+        if (w > bw)
+          bw = w ;
+      }
+    }
+    
+    bw = max(bw, bh * 2);
+    /* Button white space */
+    bh = bh * 2 - 4;
+    bw = bw * 2;
+    bspace = 10; /* Fixed space between buttons */
+
+    /* Get the text size */
+    GetClientRect(GetDlgItem(hwnd, MSGBOX_IDTEXT), &rect);
+    rect.top = rect.left = rect.bottom = 0;
+    rect.right = (((GetSystemMetrics(SM_CXSCREEN) - borwidth) * 4) / 5);
+    DrawTextW( hdc, lpszText, -1, &rect,
+              DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_CALCRECT);
+
+    /* Min text width corresponds to space for the buttons */
+    tleft = ileft;
+    if (iwidth)
+        tleft += ileft + iwidth;
+    twidth = max((LONG) (((bw + bspace) * nButtons) + bspace - tleft), rect.right);
+    theight = rect.bottom;
+
+    if (hFont)
+        SelectObject(hdc, hPrevFont);
+    ReleaseDC(hItem, hdc);
+
+    tiheight = 16 + max(iheight, theight) + 16;
+    wwidth  = tleft + twidth + ileft + borwidth;
+    wheight = 8 + tiheight + bh + borheight;
+
+    /* Resize the window */
+    SetWindowPos(hwnd, 0, 0, 0, wwidth, wheight,
+                 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
+
+    /* Position the icon */
+    SetWindowPos(GetDlgItem(hwnd, MSGBOX_IDICON), 0, ileft, (tiheight - iheight) / 2, 0, 0,
+                 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
+
+    /* Position the text */
+    SetWindowPos(GetDlgItem(hwnd, MSGBOX_IDTEXT), 0, tleft, (tiheight - theight) / 2, twidth, theight,
+                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
+    SetWindowTextW(GetDlgItem(hwnd, MSGBOX_IDTEXT), lpszText);
+
+    /* Position the buttons */
+    bpos = (wwidth - ((bw + bspace) * nButtons) + bspace) / 2;
+    for(i = 0; i <= nButtons; i++)
+    {
+      if (i == ((lpmb->dwStyle & MB_DEFMASK) >> 8))
+      {
+        SetFocus(Buttons[i]);
+        SendMessageW(Buttons[i], BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE);
+        sdefbtn = TRUE;
+      }
+      SetWindowPos(Buttons[i], 0, bpos, tiheight, bw, bh,
+                   SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
+      bpos += bw + bspace;
+    }
+
+    /* if there's no (valid) default selection, select first button */
+    if(!sdefbtn)
+    {
+      SetFocus(Buttons[0]);
+      SendMessageW(Buttons[0], BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE);
+    }
+
+    if(lpmb->dwStyle & MB_RIGHT)
+    {
+        hItem = GetDlgItem(hwnd, MSGBOX_IDTEXT);
+        SetWindowLongW(hItem, GWL_STYLE, 
+                      GetWindowLongW(hItem, GWL_STYLE) | SS_RIGHT);
+    }
+
+    /* handle modal MessageBoxes */
+    if (lpmb->dwStyle & (MB_TASKMODAL|MB_SYSTEMMODAL))
+    {
+        DbgPrint("%s modal msgbox ! Not modal yet.\n",
+                 lpmb->dwStyle & MB_TASKMODAL ? "task" : "system");
+        /* Probably do EnumTaskWindows etc. here for TASKMODAL
+         * and work your way up to the top - I'm lazy (HWND_TOP) */
+        SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
+                     SWP_NOSIZE | SWP_NOMOVE);
+        if (lpmb->dwStyle & MB_TASKMODAL)
+            /* at least MB_TASKMODAL seems to imply a ShowWindow */
+            ShowWindow(hwnd, SW_SHOW);
+    }
+
+    if (lpmb->dwStyle & MB_APPLMODAL)
+        DbgPrint("app modal msgbox ! Not modal yet.\n");
+
+    return hFont;
+}
+
+
+/**************************************************************************
+ *           MSGBOX_DlgProc
+ *
+ * Dialog procedure for message boxes.
+ */
+static INT_PTR CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message,
+                                        WPARAM wParam, LPARAM lParam )
+{
+  HFONT hFont;
+  HELPINFO hi;
+
+  switch(message) {
+   case WM_INITDIALOG:
+   {
+       if(GetWindowLongA(hwnd, DWL_INIT))
+       {
+            LPMSGBOXPARAMS mbp = (LPMSGBOXPARAMS)lParam;
+            SetWindowLongA(hwnd, DWL_INIT, (LONG)mbp);
+            SetWindowContextHelpId(hwnd, mbp->dwContextHelpId);
+            hFont = MSGBOX_OnInit(hwnd, mbp);
+            SetPropA(hwnd, "ROS_MSGBOX_HFONT", (HANDLE)hFont);
+            SetPropA(hwnd, "ROS_MSGBOX_HELPCALLBACK", (HANDLE)mbp->lpfnMsgBoxCallback);
+            return 1;
+       }
+       return 0;
+   }
+
+   case WM_COMMAND:
+    switch (LOWORD(wParam))
+    {
+     case IDOK:
+     case IDCANCEL:
+     case IDABORT:
+     case IDRETRY:
+     case IDIGNORE:
+     case IDYES:
+     case IDNO:
+     case IDTRYAGAIN:
+     case IDCONTINUE:
+      hFont = GetPropA(hwnd, "ROS_MSGBOX_HFONT");
+      EndDialog(hwnd, wParam);
+      if (hFont)
+        DeleteObject(hFont);
+      return 0;
+    case IDHELP:
+      /* send WM_HELP message to messagebox window */
+      hi.cbSize = sizeof(HELPINFO);
+      hi.iContextType = HELPINFO_WINDOW;
+      hi.iCtrlId = LOWORD(wParam);
+      hi.hItemHandle = (HANDLE)lParam;
+      hi.dwContextId = 0;
+      GetCursorPos(&hi.MousePos);
+      SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi);
+      return 0;
+    }
+    return 0;
+
+    case WM_HELP:
+    {
+        MSGBOXCALLBACK callback = (MSGBOXCALLBACK)GetPropA(hwnd, "ROS_MSGBOX_HELPCALLBACK");
+
+        memcpy(&hi, (void *)lParam, sizeof(hi));
+        hi.dwContextId = GetWindowContextHelpId(hwnd);
+
+        if (callback)
+            callback(&hi);
+        else {
+            HWND owner = GetWindow(hwnd, GW_OWNER);
+            if(owner)
+            SendMessageW(GetWindow(hwnd, GW_OWNER), WM_HELP, 0, (LPARAM)&hi);
+            }
+        return 0;
+    }
+  }
+  return 0;
+}
+
+
+/*
+ * @implemented
+ */
 int
 STDCALL
 MessageBoxA(
@@ -42,9 +438,13 @@ MessageBoxA(
   LPCSTR lpCaption,
   UINT uType)
 {
-  return MessageBoxExA(hWnd, lpText, lpCaption, uType, 0);
+    return MessageBoxExA(hWnd, lpText, lpCaption, uType, LANG_NEUTRAL);
 }
 
+
+/*
+ * @implemented
+ */
 int
 STDCALL
 MessageBoxExA(
@@ -54,9 +454,26 @@ MessageBoxExA(
   UINT uType,
   WORD wLanguageId)
 {
-  return 0;
+    MSGBOXPARAMS msgbox;
+
+    msgbox.cbSize = sizeof(msgbox);
+    msgbox.hwndOwner = hWnd;
+    msgbox.hInstance = 0;
+    msgbox.lpszText = lpText;
+    msgbox.lpszCaption = lpCaption;
+    msgbox.dwStyle = uType;
+    msgbox.lpszIcon = NULL;
+    msgbox.dwContextHelpId = 0;
+    msgbox.lpfnMsgBoxCallback = NULL;
+    msgbox.dwLanguageId = wLanguageId;
+
+    return MessageBoxIndirectA(&msgbox);
 }
 
+
+/*
+ * @implemented
+ */
 int
 STDCALL
 MessageBoxExW(
@@ -66,25 +483,131 @@ MessageBoxExW(
   UINT uType,
   WORD wLanguageId)
 {
-  return 0;
+    MSGBOXPARAMS msgbox;
+
+    msgbox.cbSize = sizeof(msgbox);
+    msgbox.hwndOwner = hWnd;
+    msgbox.hInstance = 0;
+    msgbox.lpszText = (LPCSTR)lpText;
+    msgbox.lpszCaption =(LPCSTR) lpCaption;
+    msgbox.dwStyle = uType;
+    msgbox.lpszIcon = NULL;
+    msgbox.dwContextHelpId = 0;
+    msgbox.lpfnMsgBoxCallback = NULL;
+    msgbox.dwLanguageId = wLanguageId;
+
+    return MessageBoxIndirectW(&msgbox);
 }
 
+
+/*
+ * @implemented
+ */
 int
 STDCALL
 MessageBoxIndirectA(
   CONST LPMSGBOXPARAMS lpMsgBoxParams)
 {
-  return 0;
+    MSGBOXPARAMS msgboxW;
+    UNICODE_STRING textW, captionW, iconW;
+    int ret;
+
+    if (HIWORD((UINT)lpMsgBoxParams->lpszText))
+        RtlCreateUnicodeStringFromAsciiz(&textW, (PCSZ)lpMsgBoxParams->lpszText);
+    else
+        textW.Buffer = (LPWSTR)lpMsgBoxParams->lpszText;
+
+    if (HIWORD((UINT)lpMsgBoxParams->lpszCaption))
+        RtlCreateUnicodeStringFromAsciiz(&captionW, (PCSZ)lpMsgBoxParams->lpszCaption);
+    else
+        captionW.Buffer = (LPWSTR)lpMsgBoxParams->lpszCaption;
+
+    if (HIWORD((UINT)lpMsgBoxParams->lpszIcon))
+        RtlCreateUnicodeStringFromAsciiz(&iconW, (PCSZ)lpMsgBoxParams->lpszIcon);
+    else
+        iconW.Buffer = (LPWSTR)lpMsgBoxParams->lpszIcon;
+
+    msgboxW.cbSize = sizeof(msgboxW);
+    msgboxW.hwndOwner = lpMsgBoxParams->hwndOwner;
+    msgboxW.hInstance = lpMsgBoxParams->hInstance;
+    msgboxW.lpszText = (LPCSTR)textW.Buffer;
+    msgboxW.lpszCaption = (LPCSTR)captionW.Buffer;
+    msgboxW.dwStyle = lpMsgBoxParams->dwStyle;
+    msgboxW.lpszIcon = (LPCSTR)iconW.Buffer;
+    msgboxW.dwContextHelpId = lpMsgBoxParams->dwContextHelpId;
+    msgboxW.lpfnMsgBoxCallback = lpMsgBoxParams->lpfnMsgBoxCallback;
+    msgboxW.dwLanguageId = lpMsgBoxParams->dwLanguageId;
+
+    ret = MessageBoxIndirectW(&msgboxW);
+
+    if (HIWORD(textW.Buffer))
+        RtlFreeUnicodeString(&textW);
+
+    if (HIWORD(captionW.Buffer))
+        RtlFreeUnicodeString(&captionW);
+
+    if (HIWORD(iconW.Buffer))
+        RtlFreeUnicodeString(&iconW);
+
+    return ret;
 }
 
+
+/*
+ * @implemented
+ */
 int
 STDCALL
 MessageBoxIndirectW(
   CONST LPMSGBOXPARAMS lpMsgBoxParams)
 {
-  return 0;
+    LPVOID tmplate, ctmplate;
+    HRSRC hRes;
+    HMODULE hUser32;
+    DWORD ressize;
+    WORD *style;
+    WORD *exstyle;
+
+    hUser32 = GetModuleHandleW(L"user32.dll");
+    if (!(hRes = FindResourceExW(hUser32, RT_DIALOGW, L"MSGBOX", lpMsgBoxParams->dwLanguageId)))
+        return 0;
+
+    if (!(tmplate = (LPVOID)LoadResource(hUser32, hRes)))
+        return 0;
+
+    /* Copy template */
+    ressize = SizeofResource(hUser32, hRes);
+    ctmplate = RtlAllocateHeap(RtlGetProcessHeap(), 0, ressize);
+    RtlMoveMemory(ctmplate, tmplate, ressize);
+
+    /* change dialog's style in the template before 
+       passing it to DialogBoxIndirectParamW        */
+
+    style = (WORD *)ctmplate;
+    exstyle = style + 2;
+    if(*(DWORD*)style == 0xffff0001)   /* DIALOGEX resource */
+    {
+        /* skip help id */
+        exstyle = style + 4;
+        style = exstyle + 2;
+    }
+
+    /* change window style before creating it */
+    if(lpMsgBoxParams->dwStyle & MB_RIGHT)
+        *exstyle = (WORD)(*(DWORD*)exstyle | WS_EX_RIGHT);
+    if(lpMsgBoxParams->dwStyle & MB_TOPMOST)
+        *exstyle = (WORD)(*(DWORD*)exstyle | WS_EX_TOPMOST);
+
+    return DialogBoxIndirectParamW(lpMsgBoxParams->hInstance, ctmplate, lpMsgBoxParams->hwndOwner,
+                                   MSGBOX_DlgProc, (LPARAM)lpMsgBoxParams);
+
+    RtlFreeHeap(RtlGetProcessHeap(), 0, ctmplate);
 }
 
+
+/*
+ * @implemented
+ */
 int
 STDCALL
 MessageBoxW(
@@ -93,13 +616,59 @@ MessageBoxW(
   LPCWSTR lpCaption,
   UINT uType)
 {
-  return MessageBoxExW(hWnd, lpText, lpCaption, uType, 0);
+    return MessageBoxExW(hWnd, lpText, lpCaption, uType, LANG_NEUTRAL);
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD
 STDCALL
-SoftModalMessageBox (DWORD Unknown0)
+SoftModalMessageBox(DWORD Unknown0)
+{
+  UNIMPLEMENTED;
+  return 0;
+}
+
+
+/*
+ * @implemented
+ */
+WINBOOL
+STDCALL
+MessageBeep(UINT uType)
 {
-       return 0;
+#if 0
+  LPWSTR EventName;
+
+  switch(uType)
+  {
+    case 0xFFFFFFFF:
+      if(waveOutGetNumDevs() == 0)
+        return Beep(500, 100);    // Beep through speaker
+      /* fall through */
+    case MB_OK: 
+      EventName = L"SystemDefault";
+      break;
+    case MB_ICONASTERISK:
+      EventName = L"SystemAsterisk";
+      break;
+    case MB_ICONEXCLAMATION:
+      EventName = L"SystemExclamation";
+      break;
+    case MB_ICONHAND:
+      EventName = L"SystemHand";
+      break;
+    case MB_ICONQUESTION:
+      EventName = L"SystemQuestion";
+      break;
+  }
+
+  return PlaySoundW((LPCWSTR)EventName, NULL, SND_ALIAS | SND_NOWAIT | SND_NOSTOP | SND_ASYNC);
+#else
+  return Beep(500, 100);    // Beep through speaker
+#endif
 }
+
 /* EOF */