X-Git-Url: http://git.jankratochvil.net/?a=blobdiff_plain;ds=sidebyside;f=lib%2Fuser32%2Fwindows%2Fmessagebox.c;fp=lib%2Fuser32%2Fwindows%2Fmessagebox.c;h=3049094d5e8da0399169b8db707268d7cdc3f9e7;hb=7c0cf90e3b750f1f0dc83b2eec9e5c68a512c30f;hp=63a86632ea6a46d3d0cb1e1406ee611ad76868fe;hpb=ee8b63255465d8c28be3e7bd11628015708fc1ab;p=reactos.git diff --git a/lib/user32/windows/messagebox.c b/lib/user32/windows/messagebox.c index 63a8663..3049094 100644 --- a/lib/user32/windows/messagebox.c +++ b/lib/user32/windows/messagebox.c @@ -19,21 +19,417 @@ /* $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 +#include #include +#include +#include +#include +#include #include +typedef UINT *LPUINT; +#include + +/* 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 */