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