7ea0b9016e24754d46c748f8bf7e8748e411df2f
[reactos.git] / reactos / dll / win32 / 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 <user32.h>
35
36 #include <wine/debug.h>
37
38 WINE_DEFAULT_DEBUG_CHANNEL(user32);
39
40 /* DEFINES *******************************************************************/
41
42 #define MSGBOX_IDICON (1088)
43 #define MSGBOX_IDTEXT (100)
44
45 #define IDI_HANDA MAKEINTRESOURCEA(32513)
46 #define IDI_HANDW MAKEINTRESOURCEW(32513)
47 #define IDI_QUESTIONA MAKEINTRESOURCEA(32514)
48 #define IDI_QUESTIONW MAKEINTRESOURCEW(32514)
49 #define IDI_EXCLAMATIONA MAKEINTRESOURCEA(32515)
50 #define IDI_EXCLAMATIONW MAKEINTRESOURCEW(32515)
51 #define IDI_ASTERISKA MAKEINTRESOURCEA(32516)
52 #define IDI_ASTERISKW MAKEINTRESOURCEW(32516)
53 #define IDI_WINLOGOA MAKEINTRESOURCEA(32517)
54 #define IDI_WINLOGOW MAKEINTRESOURCEW(32517)
55
56 #define BTN_CX (75)
57 #define BTN_CY (23)
58
59 #define MSGBOXEX_SPACING (16)
60 #define MSGBOXEX_BUTTONSPACING (6)
61 #define MSGBOXEX_MARGIN (12)
62 #define MSGBOXEX_MAXBTNSTR (32)
63 #define MSGBOXEX_MAXBTNS (4)
64
65 typedef struct _MSGBOXINFO {
66 HICON Icon;
67 HFONT Font;
68 DWORD ContextHelpId;
69 MSGBOXCALLBACK Callback;
70 DWORD Style;
71 int DefBtn;
72 int nButtons;
73 LONG *Btns;
74 UINT Timeout;
75 } MSGBOXINFO, *PMSGBOXINFO;
76
77 /* INTERNAL FUNCTIONS ********************************************************/
78
79 static INT_PTR CALLBACK MessageBoxProc( HWND hwnd, UINT message,
80 WPARAM wParam, LPARAM lParam )
81 {
82 int i;
83 PMSGBOXINFO mbi;
84 HELPINFO hi;
85 HWND owner;
86
87 switch(message) {
88 case WM_INITDIALOG:
89 mbi = (PMSGBOXINFO)lParam;
90 if(!GetPropW(hwnd, L"ROS_MSGBOX"))
91 {
92 SetPropW(hwnd, L"ROS_MSGBOX", (HANDLE)lParam);
93 if(mbi->Icon)
94 SendDlgItemMessageW(hwnd, MSGBOX_IDICON, STM_SETICON, (WPARAM)mbi->Icon, 0);
95 SetWindowContextHelpId(hwnd, mbi->ContextHelpId);
96
97 /* set control fonts */
98 SendDlgItemMessageW(hwnd, MSGBOX_IDTEXT, WM_SETFONT, (WPARAM)mbi->Font, 0);
99 for(i = 0; i < mbi->nButtons; i++)
100 {
101 SendDlgItemMessageW(hwnd, mbi->Btns[i], WM_SETFONT, (WPARAM)mbi->Font, 0);
102 }
103 switch(mbi->Style & MB_TYPEMASK)
104 {
105 case MB_ABORTRETRYIGNORE:
106 case MB_YESNO:
107 RemoveMenu(GetSystemMenu(hwnd, FALSE), SC_CLOSE, MF_BYCOMMAND);
108 break;
109 }
110 SetFocus(GetDlgItem(hwnd, mbi->DefBtn));
111 if(mbi->Timeout && (mbi->Timeout != (UINT)-1))
112 SetTimer(hwnd, 0, mbi->Timeout, NULL);
113 }
114 return 0;
115
116 case WM_COMMAND:
117 switch (LOWORD(wParam))
118 {
119 case IDOK:
120 case IDCANCEL:
121 case IDABORT:
122 case IDRETRY:
123 case IDIGNORE:
124 case IDYES:
125 case IDNO:
126 case IDTRYAGAIN:
127 case IDCONTINUE:
128 EndDialog(hwnd, wParam);
129 return 0;
130 case IDHELP:
131 /* send WM_HELP message to messagebox window */
132 hi.cbSize = sizeof(HELPINFO);
133 hi.iContextType = HELPINFO_WINDOW;
134 hi.iCtrlId = LOWORD(wParam);
135 hi.hItemHandle = (HANDLE)lParam;
136 hi.dwContextId = 0;
137 GetCursorPos(&hi.MousePos);
138 SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi);
139 return 0;
140 }
141 return 0;
142
143 case WM_HELP:
144 mbi = (PMSGBOXINFO)GetPropW(hwnd, L"ROS_MSGBOX");
145 if(!mbi)
146 return 0;
147 memcpy(&hi, (void *)lParam, sizeof(hi));
148 hi.dwContextId = GetWindowContextHelpId(hwnd);
149
150 if (mbi->Callback)
151 mbi->Callback(&hi);
152 else
153 {
154 owner = GetWindow(hwnd, GW_OWNER);
155 if(owner)
156 SendMessageW(GetWindow(hwnd, GW_OWNER), WM_HELP, 0, (LPARAM)&hi);
157 }
158 return 0;
159
160 case WM_CLOSE:
161 mbi = (PMSGBOXINFO)GetPropW(hwnd, L"ROS_MSGBOX");
162 if(!mbi)
163 return 0;
164 switch(mbi->Style & MB_TYPEMASK)
165 {
166 case MB_ABORTRETRYIGNORE:
167 case MB_YESNO:
168 return 1;
169 }
170 EndDialog(hwnd, IDCANCEL);
171 return 1;
172
173 case WM_TIMER:
174 if(wParam == 0)
175 {
176 EndDialog(hwnd, 32000);
177 }
178 return 0;
179 }
180 return 0;
181 }
182
183 static int
184 MessageBoxTimeoutIndirectW(
185 CONST MSGBOXPARAMSW *lpMsgBoxParams, UINT Timeout)
186 {
187 DLGTEMPLATE *tpl;
188 DLGITEMTEMPLATE *iico, *itxt;
189 NONCLIENTMETRICSW nclm;
190 WCHAR capbuf[32];
191 LPVOID buf;
192 BYTE *dest;
193 LPCWSTR caption, text;
194 HFONT hFont;
195 HICON Icon;
196 HDC hDC;
197 int bufsize, ret, caplen, textlen, btnlen, i, btnleft, btntop, lmargin, nButtons = 0;
198 LONG Buttons[MSGBOXEX_MAXBTNS];
199 WCHAR ButtonText[MSGBOXEX_MAXBTNS][MSGBOXEX_MAXBTNSTR];
200 DLGITEMTEMPLATE *ibtn[MSGBOXEX_MAXBTNS];
201 RECT btnrect, txtrect, rc;
202 SIZE btnsize;
203 MSGBOXINFO mbi;
204 BOOL defbtn = FALSE;
205 DWORD units = GetDialogBaseUnits();
206
207 if(!lpMsgBoxParams->lpszCaption || !HIWORD((LPWSTR)lpMsgBoxParams->lpszCaption))
208 {
209 LoadStringW(User32Instance, IDS_ERROR, &capbuf[0], 32);
210 caption = &capbuf[0];
211 }
212 else
213 caption = (LPWSTR)lpMsgBoxParams->lpszCaption;
214
215 if(!lpMsgBoxParams->lpszText || !HIWORD(lpMsgBoxParams->lpszText))
216 text = L"";
217 else
218 text = lpMsgBoxParams->lpszText;
219
220 caplen = strlenW(caption);
221 textlen = strlenW(text);
222
223 /* Create selected buttons */
224 switch(lpMsgBoxParams->dwStyle & MB_TYPEMASK)
225 {
226 case MB_OKCANCEL:
227 Buttons[0] = IDOK;
228 Buttons[1] = IDCANCEL;
229 nButtons = 2;
230 break;
231 case MB_CANCELTRYCONTINUE:
232 Buttons[0] = IDCANCEL;
233 Buttons[1] = IDTRYAGAIN;
234 Buttons[2] = IDCONTINUE;
235 nButtons = 3;
236 break;
237 case MB_ABORTRETRYIGNORE:
238 Buttons[0] = IDABORT;
239 Buttons[1] = IDRETRY;
240 Buttons[2] = IDIGNORE;
241 nButtons = 3;
242 break;
243 case MB_YESNO:
244 Buttons[0] = IDYES;
245 Buttons[1] = IDNO;
246 nButtons = 2;
247 break;
248 case MB_YESNOCANCEL:
249 Buttons[0] = IDYES;
250 Buttons[1] = IDNO;
251 Buttons[2] = IDCANCEL;
252 nButtons = 3;
253 break;
254 case MB_RETRYCANCEL:
255 Buttons[0] = IDRETRY;
256 Buttons[1] = IDCANCEL;
257 nButtons = 2;
258 break;
259 case MB_OK:
260 /* fall through */
261 default:
262 Buttons[0] = IDOK;
263 nButtons = 1;
264 break;
265 }
266 /* Create Help button */
267 if(lpMsgBoxParams->dwStyle & MB_HELP)
268 Buttons[nButtons++] = IDHELP;
269
270 switch(lpMsgBoxParams->dwStyle & MB_ICONMASK)
271 {
272 case MB_ICONEXCLAMATION:
273 Icon = LoadIconW(0, IDI_EXCLAMATIONW);
274 MessageBeep(MB_ICONEXCLAMATION);
275 break;
276 case MB_ICONQUESTION:
277 Icon = LoadIconW(0, IDI_QUESTIONW);
278 MessageBeep(MB_ICONQUESTION);
279 break;
280 case MB_ICONASTERISK:
281 Icon = LoadIconW(0, IDI_ASTERISKW);
282 MessageBeep(MB_ICONASTERISK);
283 break;
284 case MB_ICONHAND:
285 Icon = LoadIconW(0, IDI_HANDW);
286 MessageBeep(MB_ICONHAND);
287 break;
288 case MB_USERICON:
289 Icon = LoadIconW(lpMsgBoxParams->hInstance, lpMsgBoxParams->lpszIcon);
290 MessageBeep(MB_OK);
291 break;
292 default:
293 /* By default, Windows 95/98/NT does not associate an icon to message boxes.
294 * So ReactOS should do the same.
295 */
296 Icon = (HICON)0;
297 MessageBeep(MB_OK);
298 break;
299 }
300
301 /* Basic space */
302 bufsize = sizeof(DLGTEMPLATE) +
303 2 * sizeof(WORD) + /* menu and class */
304 (caplen + 1) * sizeof(WCHAR); /* title */
305
306 /* Space for icon */
307 if (NULL != Icon)
308 {
309 bufsize = (bufsize + 3) & ~3;
310 bufsize += sizeof(DLGITEMTEMPLATE) +
311 4 * sizeof(WORD) +
312 sizeof(WCHAR);
313 }
314
315 /* Space for text */
316 bufsize = (bufsize + 3) & ~3;
317 bufsize += sizeof(DLGITEMTEMPLATE) +
318 3 * sizeof(WORD) +
319 (textlen + 1) * sizeof(WCHAR);
320
321
322 for(i = 0; i < nButtons; i++)
323 {
324 switch(Buttons[i])
325 {
326 case IDOK:
327 LoadStringW(User32Instance, IDS_OK, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
328 break;
329 case IDCANCEL:
330 LoadStringW(User32Instance, IDS_CANCEL, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
331 break;
332 case IDYES:
333 LoadStringW(User32Instance, IDS_YES, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
334 break;
335 case IDNO:
336 LoadStringW(User32Instance, IDS_NO, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
337 break;
338 case IDTRYAGAIN:
339 LoadStringW(User32Instance, IDS_TRYAGAIN, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
340 break;
341 case IDCONTINUE:
342 LoadStringW(User32Instance, IDS_CONTINUE, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
343 break;
344 case IDABORT:
345 LoadStringW(User32Instance, IDS_ABORT, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
346 break;
347 case IDRETRY:
348 LoadStringW(User32Instance, IDS_RETRY, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
349 break;
350 case IDIGNORE:
351 LoadStringW(User32Instance, IDS_IGNORE, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
352 break;
353 case IDHELP:
354 LoadStringW(User32Instance, IDS_HELP, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
355 break;
356 default:
357 ButtonText[i][0] = (WCHAR)0;
358 break;
359 }
360
361 /* Space for buttons */
362 bufsize = (bufsize + 3) & ~3;
363 bufsize += sizeof(DLGITEMTEMPLATE) +
364 3 * sizeof(WORD) +
365 (wcslen(ButtonText[i]) + 1) * sizeof(WCHAR);
366 }
367
368 buf = RtlAllocateHeap(GetProcessHeap(), 0, bufsize);
369 if(!buf)
370 {
371 return 0;
372 }
373 iico = itxt = NULL;
374
375 hDC = CreateCompatibleDC(0);
376
377 nclm.cbSize = sizeof(nclm);
378 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0);
379 hFont = CreateFontIndirectW (&nclm.lfMessageFont);
380
381 tpl = (DLGTEMPLATE *)buf;
382
383 tpl->style = WS_CAPTION | WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SYSMENU | DS_CENTER | DS_MODALFRAME | DS_NOIDLEMSG;
384 tpl->dwExtendedStyle = WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
385 if(lpMsgBoxParams->dwStyle & MB_TOPMOST)
386 tpl->dwExtendedStyle |= WS_EX_TOPMOST;
387 if(lpMsgBoxParams->dwStyle & MB_RIGHT)
388 tpl->dwExtendedStyle |= WS_EX_RIGHT;
389 tpl->x = 100;
390 tpl->y = 100;
391 tpl->cdit = nButtons + ((Icon != (HICON)0) ? 1 : 0) + 1;
392
393 dest = (BYTE *)(tpl + 1);
394
395 *(WORD*)dest = 0; /* no menu */
396 *(((WORD*)dest) + 1) = 0; /* use default window class */
397 dest += 2 * sizeof(WORD);
398 memcpy(dest, caption, caplen * sizeof(WCHAR));
399 dest += caplen * sizeof(WCHAR);
400 *(WCHAR*)dest = L'\0';
401 dest += sizeof(WCHAR);
402
403 /* Create icon */
404 if(Icon)
405 {
406 dest = (BYTE*)(((ULONG_PTR)dest + 3) & ~3);
407 iico = (DLGITEMTEMPLATE *)dest;
408 iico->style = WS_CHILD | WS_VISIBLE | SS_ICON;
409 iico->dwExtendedStyle = 0;
410 iico->id = MSGBOX_IDICON;
411
412 dest += sizeof(DLGITEMTEMPLATE);
413 *(WORD*)dest = 0xFFFF;
414 dest += sizeof(WORD);
415 *(WORD*)dest = 0x0082; /* static control */
416 dest += sizeof(WORD);
417 *(WORD*)dest = 0xFFFF;
418 dest += sizeof(WORD);
419 *(WCHAR*)dest = 0;
420 dest += sizeof(WCHAR);
421 *(WORD*)dest = 0;
422 dest += sizeof(WORD);
423 }
424
425 /* create static for text */
426 dest = (BYTE*)(((UINT_PTR)dest + 3) & ~3);
427 itxt = (DLGITEMTEMPLATE *)dest;
428 itxt->style = WS_CHILD | WS_VISIBLE | SS_NOPREFIX;
429 if(lpMsgBoxParams->dwStyle & MB_RIGHT)
430 itxt->style |= SS_RIGHT;
431 else
432 itxt->style |= SS_LEFT;
433 itxt->dwExtendedStyle = 0;
434 itxt->id = MSGBOX_IDTEXT;
435 dest += sizeof(DLGITEMTEMPLATE);
436 *(WORD*)dest = 0xFFFF;
437 dest += sizeof(WORD);
438 *(WORD*)dest = 0x0082; /* static control */
439 dest += sizeof(WORD);
440 memcpy(dest, text, textlen * sizeof(WCHAR));
441 dest += textlen * sizeof(WCHAR);
442 *(WCHAR*)dest = 0;
443 dest += sizeof(WCHAR);
444 *(WORD*)dest = 0;
445 dest += sizeof(WORD);
446
447 /* create buttons */
448 btnsize.cx = BTN_CX;
449 btnsize.cy = BTN_CY;
450 btnrect.left = btnrect.top = 0;
451 for(i = 0; i < nButtons; i++)
452 {
453 dest = (BYTE*)(((UINT_PTR)dest + 3) & ~3);
454 ibtn[i] = (DLGITEMTEMPLATE *)dest;
455 ibtn[i]->style = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
456 if(!defbtn && (i == ((lpMsgBoxParams->dwStyle & MB_DEFMASK) >> 8)))
457 {
458 ibtn[i]->style |= BS_DEFPUSHBUTTON;
459 mbi.DefBtn = Buttons[i];
460 defbtn = TRUE;
461 }
462 else
463 ibtn[i]->style |= BS_PUSHBUTTON;
464 ibtn[i]->dwExtendedStyle = 0;
465 ibtn[i]->id = Buttons[i];
466 dest += sizeof(DLGITEMTEMPLATE);
467 *(WORD*)dest = 0xFFFF;
468 dest += sizeof(WORD);
469 *(WORD*)dest = 0x0080; /* button control */
470 dest += sizeof(WORD);
471 btnlen = strlenW(ButtonText[i]);
472 memcpy(dest, ButtonText[i], btnlen * sizeof(WCHAR));
473 dest += btnlen * sizeof(WCHAR);
474 *(WORD*)dest = 0;
475 dest += sizeof(WORD);
476 *(WORD*)dest = 0;
477 dest += sizeof(WORD);
478 SelectObject(hDC, hFont);
479 DrawTextW(hDC, ButtonText[i], btnlen, &btnrect, DT_LEFT | DT_SINGLELINE | DT_CALCRECT);
480 btnsize.cx = max(btnsize.cx, btnrect.right);
481 btnsize.cy = max(btnsize.cy, btnrect.bottom);
482 }
483
484 /* make first button the default button if no other is */
485 if(!defbtn)
486 {
487 ibtn[0]->style &= ~BS_PUSHBUTTON;
488 ibtn[0]->style |= BS_DEFPUSHBUTTON;
489 mbi.DefBtn = Buttons[0];
490 }
491
492 /* calculate position and size of controls */
493 txtrect.right = GetSystemMetrics(SM_CXSCREEN) / 5 * 4;
494 if(Icon)
495 txtrect.right -= GetSystemMetrics(SM_CXICON) + MSGBOXEX_SPACING;
496 txtrect.top = txtrect.left = txtrect.bottom = 0;
497 SelectObject(hDC, hFont);
498 if (textlen != 0)
499 {
500 DrawTextW(hDC, text, textlen, &txtrect, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
501 }
502 else
503 {
504 txtrect.right = txtrect.left + 1;
505 txtrect.bottom = txtrect.top + 1;
506 }
507 txtrect.right++;
508
509 /* calculate position and size of the icon */
510 rc.left = rc.bottom = rc.right = 0;
511 btntop = 0;
512
513 if(iico)
514 {
515 rc.right = GetSystemMetrics(SM_CXICON);
516 rc.bottom = GetSystemMetrics(SM_CYICON);
517 #ifdef MSGBOX_ICONVCENTER
518 rc.top = MSGBOXEX_MARGIN + (max(txtrect.bottom, rc.bottom) / 2) - (GetSystemMetrics(SM_CYICON) / 2);
519 rc.top = max(MSGBOXEX_SPACING, rc.top);
520 #else
521 rc.top = MSGBOXEX_MARGIN;
522 #endif
523 btnleft = (nButtons * (btnsize.cx + MSGBOXEX_BUTTONSPACING)) - MSGBOXEX_BUTTONSPACING;
524 if(btnleft > txtrect.right + rc.right + MSGBOXEX_SPACING)
525 {
526 #ifdef MSGBOX_TEXTHCENTER
527 lmargin = MSGBOXEX_MARGIN + ((btnleft - txtrect.right - rc.right - MSGBOXEX_SPACING) / 2);
528 #else
529 lmargin = MSGBOXEX_MARGIN;
530 #endif
531 btnleft = MSGBOXEX_MARGIN;
532 }
533 else
534 {
535 lmargin = MSGBOXEX_MARGIN;
536 btnleft = MSGBOXEX_MARGIN + ((txtrect.right + rc.right + MSGBOXEX_SPACING) / 2) - (btnleft / 2);
537 }
538 rc.left = lmargin;
539 iico->x = (rc.left * 4) / LOWORD(units);
540 iico->y = (rc.top * 8) / HIWORD(units);
541 iico->cx = (rc.right * 4) / LOWORD(units);
542 iico->cy = (rc.bottom * 8) / HIWORD(units);
543 btntop = rc.top + rc.bottom + MSGBOXEX_SPACING;
544 rc.left += rc.right + MSGBOXEX_SPACING;
545 }
546 else
547 {
548 btnleft = (nButtons * (btnsize.cx + MSGBOXEX_BUTTONSPACING)) - MSGBOXEX_BUTTONSPACING;
549 if(btnleft > txtrect.right)
550 {
551 #ifdef MSGBOX_TEXTHCENTER
552 lmargin = MSGBOXEX_MARGIN + ((btnleft - txtrect.right) / 2);
553 #else
554 lmargin = MSGBOXEX_MARGIN;
555 #endif
556 btnleft = MSGBOXEX_MARGIN;
557 }
558 else
559 {
560 lmargin = MSGBOXEX_MARGIN;
561 btnleft = MSGBOXEX_MARGIN + (txtrect.right / 2) - (btnleft / 2);
562 }
563 rc.left = lmargin;
564 }
565 /* calculate position of the text */
566 rc.top = MSGBOXEX_MARGIN + (rc.bottom / 2) - (txtrect.bottom / 2);
567 rc.top = max(rc.top, MSGBOXEX_MARGIN);
568 /* calculate position of the buttons */
569 btntop = max(rc.top + txtrect.bottom + MSGBOXEX_SPACING, btntop);
570 for(i = 0; i < nButtons; i++)
571 {
572 ibtn[i]->x = (btnleft * 4) / LOWORD(units);
573 ibtn[i]->y = (btntop * 8) / HIWORD(units);
574 ibtn[i]->cx = (btnsize.cx * 4) / LOWORD(units);
575 ibtn[i]->cy = (btnsize.cy * 8) / HIWORD(units);
576 btnleft += btnsize.cx + MSGBOXEX_BUTTONSPACING;
577 }
578 /* calculate size and position of the messagebox window */
579 btnleft = max(btnleft - MSGBOXEX_BUTTONSPACING, rc.left + txtrect.right);
580 btnleft += MSGBOXEX_MARGIN;
581 btntop += btnsize.cy + MSGBOXEX_MARGIN;
582 /* set size and position of the message static */
583 itxt->x = (rc.left * 4) / LOWORD(units);
584 itxt->y = (rc.top * 8) / HIWORD(units);
585 itxt->cx = (((btnleft - rc.left - MSGBOXEX_MARGIN) * 4) / LOWORD(units));
586 itxt->cy = ((txtrect.bottom * 8) / HIWORD(units));
587 /* set size of the window */
588 tpl->cx = (btnleft * 4) / LOWORD(units);
589 tpl->cy = (btntop * 8) / HIWORD(units);
590
591 /* finally show the messagebox */
592 mbi.Icon = Icon;
593 mbi.Font = hFont;
594 mbi.ContextHelpId = lpMsgBoxParams->dwContextHelpId;
595 mbi.Callback = lpMsgBoxParams->lpfnMsgBoxCallback;
596 mbi.Style = lpMsgBoxParams->dwStyle;
597 mbi.nButtons = nButtons;
598 mbi.Btns = &Buttons[0];
599 mbi.Timeout = Timeout;
600
601 if(hDC)
602 DeleteDC(hDC);
603
604 ret = DialogBoxIndirectParamW(lpMsgBoxParams->hInstance, tpl, lpMsgBoxParams->hwndOwner,
605 MessageBoxProc, (LPARAM)&mbi);
606
607 if(hFont)
608 DeleteObject(hFont);
609
610 RtlFreeHeap(GetProcessHeap(), 0, buf);
611 return ret;
612 }
613
614 /* FUNCTIONS *****************************************************************/
615
616
617 /*
618 * @implemented
619 */
620 int
621 WINAPI
622 MessageBoxA(
623 HWND hWnd,
624 LPCSTR lpText,
625 LPCSTR lpCaption,
626 UINT uType)
627 {
628 return MessageBoxExA(hWnd, lpText, lpCaption, uType, LANG_NEUTRAL);
629 }
630
631
632 /*
633 * @implemented
634 */
635 int
636 WINAPI
637 MessageBoxExA(
638 HWND hWnd,
639 LPCSTR lpText,
640 LPCSTR lpCaption,
641 UINT uType,
642 WORD wLanguageId)
643 {
644 MSGBOXPARAMSA msgbox;
645
646 msgbox.cbSize = sizeof(msgbox);
647 msgbox.hwndOwner = hWnd;
648 msgbox.hInstance = 0;
649 msgbox.lpszText = lpText;
650 msgbox.lpszCaption = lpCaption;
651 msgbox.dwStyle = uType;
652 msgbox.lpszIcon = NULL;
653 msgbox.dwContextHelpId = 0;
654 msgbox.lpfnMsgBoxCallback = NULL;
655 msgbox.dwLanguageId = wLanguageId;
656
657 return MessageBoxIndirectA(&msgbox);
658 }
659
660
661 /*
662 * @implemented
663 */
664 int
665 WINAPI
666 MessageBoxExW(
667 HWND hWnd,
668 LPCWSTR lpText,
669 LPCWSTR lpCaption,
670 UINT uType,
671 WORD wLanguageId)
672 {
673 MSGBOXPARAMSW msgbox;
674
675 msgbox.cbSize = sizeof(msgbox);
676 msgbox.hwndOwner = hWnd;
677 msgbox.hInstance = 0;
678 msgbox.lpszText = lpText;
679 msgbox.lpszCaption = lpCaption;
680 msgbox.dwStyle = uType;
681 msgbox.lpszIcon = NULL;
682 msgbox.dwContextHelpId = 0;
683 msgbox.lpfnMsgBoxCallback = NULL;
684 msgbox.dwLanguageId = wLanguageId;
685
686 return MessageBoxTimeoutIndirectW(&msgbox, (UINT)-1);
687 }
688
689
690 /*
691 * @implemented
692 */
693 int
694 WINAPI
695 MessageBoxIndirectA(
696 CONST MSGBOXPARAMSA *lpMsgBoxParams)
697 {
698 MSGBOXPARAMSW msgboxW;
699 UNICODE_STRING textW, captionW, iconW;
700 int ret;
701
702 if (HIWORD((UINT_PTR)lpMsgBoxParams->lpszText))
703 {
704 RtlCreateUnicodeStringFromAsciiz(&textW, (PCSZ)lpMsgBoxParams->lpszText);
705 /*
706 * UNICODE_STRING objects are always allocated with an extra byte so you
707 * can null-term if you want
708 */
709 textW.Buffer[textW.Length / sizeof(WCHAR)] = L'\0';
710 }
711 else
712 textW.Buffer = (LPWSTR)lpMsgBoxParams->lpszText;
713
714 if (HIWORD((UINT_PTR)lpMsgBoxParams->lpszCaption))
715 {
716 RtlCreateUnicodeStringFromAsciiz(&captionW, (PCSZ)lpMsgBoxParams->lpszCaption);
717 /*
718 * UNICODE_STRING objects are always allocated with an extra byte so you
719 * can null-term if you want
720 */
721 captionW.Buffer[captionW.Length / sizeof(WCHAR)] = L'\0';
722 }
723 else
724 captionW.Buffer = (LPWSTR)lpMsgBoxParams->lpszCaption;
725
726 if(lpMsgBoxParams->dwStyle & MB_USERICON)
727 {
728 if (HIWORD((UINT_PTR)lpMsgBoxParams->lpszIcon))
729 {
730 RtlCreateUnicodeStringFromAsciiz(&iconW, (PCSZ)lpMsgBoxParams->lpszIcon);
731 /*
732 * UNICODE_STRING objects are always allocated with an extra byte so you
733 * can null-term if you want
734 */
735 iconW.Buffer[iconW.Length / sizeof(WCHAR)] = L'\0';
736 }
737 else
738 iconW.Buffer = (LPWSTR)lpMsgBoxParams->lpszIcon;
739 }
740 else
741 iconW.Buffer = NULL;
742
743 msgboxW.cbSize = sizeof(msgboxW);
744 msgboxW.hwndOwner = lpMsgBoxParams->hwndOwner;
745 msgboxW.hInstance = lpMsgBoxParams->hInstance;
746 msgboxW.lpszText = textW.Buffer;
747 msgboxW.lpszCaption = captionW.Buffer;
748 msgboxW.dwStyle = lpMsgBoxParams->dwStyle;
749 msgboxW.lpszIcon = iconW.Buffer;
750 msgboxW.dwContextHelpId = lpMsgBoxParams->dwContextHelpId;
751 msgboxW.lpfnMsgBoxCallback = lpMsgBoxParams->lpfnMsgBoxCallback;
752 msgboxW.dwLanguageId = lpMsgBoxParams->dwLanguageId;
753
754 ret = MessageBoxTimeoutIndirectW(&msgboxW, (UINT)-1);
755
756 if (HIWORD((UINT_PTR)lpMsgBoxParams->lpszText))
757 RtlFreeUnicodeString(&textW);
758
759 if (HIWORD((UINT_PTR)lpMsgBoxParams->lpszCaption))
760 RtlFreeUnicodeString(&captionW);
761
762 if ((lpMsgBoxParams->dwStyle & MB_USERICON) && HIWORD((UINT_PTR)iconW.Buffer))
763 RtlFreeUnicodeString(&iconW);
764
765 return ret;
766 }
767
768
769 /*
770 * @implemented
771 */
772 int
773 WINAPI
774 MessageBoxIndirectW(
775 CONST MSGBOXPARAMSW *lpMsgBoxParams)
776 {
777 return MessageBoxTimeoutIndirectW(lpMsgBoxParams, (UINT)-1);
778 }
779
780
781 /*
782 * @implemented
783 */
784 int
785 WINAPI
786 MessageBoxW(
787 HWND hWnd,
788 LPCWSTR lpText,
789 LPCWSTR lpCaption,
790 UINT uType)
791 {
792 return MessageBoxExW(hWnd, lpText, lpCaption, uType, LANG_NEUTRAL);
793 }
794
795 /*
796 * @implemented
797 */
798 int
799 WINAPI
800 MessageBoxTimeoutA(
801 HWND hWnd,
802 LPCSTR lpText,
803 LPCSTR lpCaption,
804 UINT uType,
805 WORD wLanguageId,
806 DWORD dwTime)
807 {
808 MSGBOXPARAMSW msgboxW;
809 UNICODE_STRING textW, captionW;
810 int ret;
811
812 if (HIWORD((UINT_PTR)lpText))
813 RtlCreateUnicodeStringFromAsciiz(&textW, (PCSZ)lpText);
814 else
815 textW.Buffer = (LPWSTR)lpText;
816
817 if (HIWORD((UINT_PTR)lpCaption))
818 RtlCreateUnicodeStringFromAsciiz(&captionW, (PCSZ)lpCaption);
819 else
820 captionW.Buffer = (LPWSTR)lpCaption;
821
822 msgboxW.cbSize = sizeof(msgboxW);
823 msgboxW.hwndOwner = hWnd;
824 msgboxW.hInstance = 0;
825 msgboxW.lpszText = textW.Buffer;
826 msgboxW.lpszCaption = captionW.Buffer;
827 msgboxW.dwStyle = uType;
828 msgboxW.lpszIcon = NULL;
829 msgboxW.dwContextHelpId = 0;
830 msgboxW.lpfnMsgBoxCallback = NULL;
831 msgboxW.dwLanguageId = wLanguageId;
832
833 ret = MessageBoxTimeoutIndirectW(&msgboxW, (UINT)dwTime);
834
835 if (HIWORD(textW.Buffer))
836 RtlFreeUnicodeString(&textW);
837
838 if (HIWORD(captionW.Buffer))
839 RtlFreeUnicodeString(&captionW);
840
841 return ret;
842 }
843
844 /*
845 * @implemented
846 */
847 int
848 WINAPI
849 MessageBoxTimeoutW(
850 HWND hWnd,
851 LPCWSTR lpText,
852 LPCWSTR lpCaption,
853 UINT uType,
854 WORD wLanguageId,
855 DWORD dwTime)
856 {
857 MSGBOXPARAMSW msgbox;
858
859 msgbox.cbSize = sizeof(msgbox);
860 msgbox.hwndOwner = hWnd;
861 msgbox.hInstance = 0;
862 msgbox.lpszText = lpText;
863 msgbox.lpszCaption = lpCaption;
864 msgbox.dwStyle = uType;
865 msgbox.lpszIcon = NULL;
866 msgbox.dwContextHelpId = 0;
867 msgbox.lpfnMsgBoxCallback = NULL;
868 msgbox.dwLanguageId = wLanguageId;
869
870 return MessageBoxTimeoutIndirectW(&msgbox, (UINT)dwTime);
871 }
872
873
874 /*
875 * @unimplemented
876 */
877 DWORD
878 WINAPI
879 SoftModalMessageBox(DWORD Unknown0)
880 {
881 UNIMPLEMENTED;
882 return 0;
883 }
884
885
886 /*
887 * @implemented
888 */
889 BOOL
890 WINAPI
891 MessageBeep(UINT uType)
892 {
893 #if 0
894 LPWSTR EventName;
895
896 switch(uType)
897 {
898 case 0xFFFFFFFF:
899 if(waveOutGetNumDevs() == 0)
900 return Beep(500, 100); // Beep through speaker
901 /* fall through */
902 case MB_OK:
903 EventName = L"SystemDefault";
904 break;
905 case MB_ICONASTERISK:
906 EventName = L"SystemAsterisk";
907 break;
908 case MB_ICONEXCLAMATION:
909 EventName = L"SystemExclamation";
910 break;
911 case MB_ICONHAND:
912 EventName = L"SystemHand";
913 break;
914 case MB_ICONQUESTION:
915 EventName = L"SystemQuestion";
916 break;
917 }
918
919 return PlaySoundW((LPCWSTR)EventName, NULL, SND_ALIAS | SND_NOWAIT | SND_NOSTOP | SND_ASYNC);
920 #else
921 return Beep(500, 100); // Beep through speaker
922 #endif
923 }
924
925
926 /*
927 * @implemented
928 */
929 LPWSTR WINAPI MB_GetString(DWORD string)
930 {
931 UNIMPLEMENTED;
932 return NULL;
933 }
934
935 /* EOF */