+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
+ */