54795ff7e702622ec3212054c1b5c182ddc2f2ae
[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 LPVOID buf;
200 BYTE *dest;
201 LPCWSTR caption, text;
202 HFONT hFont;
203 HICON Icon;
204 HDC hDC;
205 int bufsize, ret, caplen, textlen, btnlen, i, btnleft, btntop, lmargin, nButtons = 0;
206 LONG Buttons[MSGBOXEX_MAXBTNS];
207 WCHAR ButtonText[MSGBOXEX_MAXBTNS][MSGBOXEX_MAXBTNSTR];
208 DLGITEMTEMPLATE *ibtn[MSGBOXEX_MAXBTNS];
209 RECT btnrect, txtrect, rc;
210 SIZE btnsize;
211 MSGBOXINFO mbi;
212 BOOL defbtn = FALSE;
213 DWORD units = GetDialogBaseUnits();
214
215 if(!lpMsgBoxParams->lpszCaption || !HIWORD((LPWSTR)lpMsgBoxParams->lpszCaption))
216 {
217 LoadStringW(User32Instance, IDS_ERROR, &capbuf[0], 32);
218 caption = &capbuf[0];
219 }
220 else
221 caption = (LPWSTR)lpMsgBoxParams->lpszCaption;
222
223 if(!lpMsgBoxParams->lpszText || !HIWORD(lpMsgBoxParams->lpszText))
224 text = L"";
225 else
226 text = lpMsgBoxParams->lpszText;
227
228 caplen = strlenW(caption);
229 textlen = strlenW(text);
230
231 /* Create selected buttons */
232 switch(lpMsgBoxParams->dwStyle & MB_TYPEMASK)
233 {
234 case MB_OKCANCEL:
235 Buttons[0] = IDOK;
236 Buttons[1] = IDCANCEL;
237 nButtons = 2;
238 break;
239 case MB_CANCELTRYCONTINUE:
240 Buttons[0] = IDCANCEL;
241 Buttons[1] = IDTRYAGAIN;
242 Buttons[2] = IDCONTINUE;
243 nButtons = 3;
244 break;
245 case MB_ABORTRETRYIGNORE:
246 Buttons[0] = IDABORT;
247 Buttons[1] = IDRETRY;
248 Buttons[2] = IDIGNORE;
249 nButtons = 3;
250 break;
251 case MB_YESNO:
252 Buttons[0] = IDYES;
253 Buttons[1] = IDNO;
254 nButtons = 2;
255 break;
256 case MB_YESNOCANCEL:
257 Buttons[0] = IDYES;
258 Buttons[1] = IDNO;
259 Buttons[2] = IDCANCEL;
260 nButtons = 3;
261 break;
262 case MB_RETRYCANCEL:
263 Buttons[0] = IDRETRY;
264 Buttons[1] = IDCANCEL;
265 nButtons = 2;
266 break;
267 case MB_OK:
268 /* fall through */
269 default:
270 Buttons[0] = IDOK;
271 nButtons = 1;
272 break;
273 }
274 /* Create Help button */
275 if(lpMsgBoxParams->dwStyle & MB_HELP)
276 Buttons[nButtons++] = IDHELP;
277
278 switch(lpMsgBoxParams->dwStyle & MB_ICONMASK)
279 {
280 case MB_ICONEXCLAMATION:
281 Icon = LoadIconW(0, IDI_EXCLAMATIONW);
282 MessageBeep(MB_ICONEXCLAMATION);
283 break;
284 case MB_ICONQUESTION:
285 Icon = LoadIconW(0, IDI_QUESTIONW);
286 MessageBeep(MB_ICONQUESTION);
287 break;
288 case MB_ICONASTERISK:
289 Icon = LoadIconW(0, IDI_ASTERISKW);
290 MessageBeep(MB_ICONASTERISK);
291 break;
292 case MB_ICONHAND:
293 Icon = LoadIconW(0, IDI_HANDW);
294 MessageBeep(MB_ICONHAND);
295 break;
296 case MB_USERICON:
297 Icon = LoadIconW(lpMsgBoxParams->hInstance, lpMsgBoxParams->lpszIcon);
298 MessageBeep(MB_OK);
299 break;
300 default:
301 /* By default, Windows 95/98/NT does not associate an icon to message boxes.
302 * So ReactOS should do the same.
303 */
304 Icon = (HICON)0;
305 MessageBeep(MB_OK);
306 break;
307 }
308
309 /* Basic space */
310 bufsize = sizeof(DLGTEMPLATE) +
311 2 * sizeof(WORD) + /* menu and class */
312 (caplen + 1) * sizeof(WCHAR); /* title */
313
314 /* Space for icon */
315 if (NULL != Icon)
316 {
317 bufsize = (bufsize + 3) & ~3;
318 bufsize += sizeof(DLGITEMTEMPLATE) +
319 4 * sizeof(WORD) +
320 sizeof(WCHAR);
321 }
322
323 /* Space for text */
324 bufsize = (bufsize + 3) & ~3;
325 bufsize += sizeof(DLGITEMTEMPLATE) +
326 3 * sizeof(WORD) +
327 (textlen + 1) * sizeof(WCHAR);
328
329
330 for(i = 0; i < nButtons; i++)
331 {
332 switch(Buttons[i])
333 {
334 case IDOK:
335 LoadStringW(User32Instance, IDS_OK, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
336 break;
337 case IDCANCEL:
338 LoadStringW(User32Instance, IDS_CANCEL, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
339 break;
340 case IDYES:
341 LoadStringW(User32Instance, IDS_YES, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
342 break;
343 case IDNO:
344 LoadStringW(User32Instance, IDS_NO, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
345 break;
346 case IDTRYAGAIN:
347 LoadStringW(User32Instance, IDS_TRYAGAIN, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
348 break;
349 case IDCONTINUE:
350 LoadStringW(User32Instance, IDS_CONTINUE, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
351 break;
352 case IDABORT:
353 LoadStringW(User32Instance, IDS_ABORT, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
354 break;
355 case IDRETRY:
356 LoadStringW(User32Instance, IDS_RETRY, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
357 break;
358 case IDIGNORE:
359 LoadStringW(User32Instance, IDS_IGNORE, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
360 break;
361 case IDHELP:
362 LoadStringW(User32Instance, IDS_HELP, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
363 break;
364 default:
365 ButtonText[i][0] = (WCHAR)0;
366 break;
367 }
368
369 /* Space for buttons */
370 bufsize = (bufsize + 3) & ~3;
371 bufsize += sizeof(DLGITEMTEMPLATE) +
372 3 * sizeof(WORD) +
373 (wcslen(ButtonText[i]) + 1) * sizeof(WCHAR);
374 }
375
376 buf = RtlAllocateHeap(GetProcessHeap(), 0, bufsize);
377 if(!buf)
378 {
379 return 0;
380 }
381 iico = itxt = NULL;
382
383 hDC = CreateCompatibleDC(0);
384
385 nclm.cbSize = sizeof(nclm);
386 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0);
387 hFont = CreateFontIndirectW (&nclm.lfMessageFont);
388
389 tpl = (DLGTEMPLATE *)buf;
390
391 tpl->style = WS_CAPTION | WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SYSMENU | DS_CENTER | DS_MODALFRAME | DS_NOIDLEMSG;
392 tpl->dwExtendedStyle = WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
393 if(lpMsgBoxParams->dwStyle & MB_TOPMOST)
394 tpl->dwExtendedStyle |= WS_EX_TOPMOST;
395 if(lpMsgBoxParams->dwStyle & MB_RIGHT)
396 tpl->dwExtendedStyle |= WS_EX_RIGHT;
397 tpl->x = 100;
398 tpl->y = 100;
399 tpl->cdit = nButtons + ((Icon != (HICON)0) ? 1 : 0) + 1;
400
401 dest = (BYTE *)(tpl + 1);
402
403 *(WORD*)dest = 0; /* no menu */
404 *(((WORD*)dest) + 1) = 0; /* use default window class */
405 dest += 2 * sizeof(WORD);
406 memcpy(dest, caption, caplen * sizeof(WCHAR));
407 dest += caplen * sizeof(WCHAR);
408 *(WCHAR*)dest = L'\0';
409 dest += sizeof(WCHAR);
410
411 /* Create icon */
412 if(Icon)
413 {
414 dest = (BYTE*)(((ULONG_PTR)dest + 3) & ~3);
415 iico = (DLGITEMTEMPLATE *)dest;
416 iico->style = WS_CHILD | WS_VISIBLE | SS_ICON;
417 iico->dwExtendedStyle = 0;
418 iico->id = MSGBOX_IDICON;
419
420 dest += sizeof(DLGITEMTEMPLATE);
421 *(WORD*)dest = 0xFFFF;
422 dest += sizeof(WORD);
423 *(WORD*)dest = 0x0082; /* static control */
424 dest += sizeof(WORD);
425 *(WORD*)dest = 0xFFFF;
426 dest += sizeof(WORD);
427 *(WCHAR*)dest = 0;
428 dest += sizeof(WCHAR);
429 *(WORD*)dest = 0;
430 dest += sizeof(WORD);
431 }
432
433 /* create static for text */
434 dest = (BYTE*)(((DWORD)dest + 3) & ~3);
435 itxt = (DLGITEMTEMPLATE *)dest;
436 itxt->style = WS_CHILD | WS_VISIBLE | SS_NOPREFIX;
437 if(lpMsgBoxParams->dwStyle & MB_RIGHT)
438 itxt->style |= SS_RIGHT;
439 else
440 itxt->style |= SS_LEFT;
441 itxt->dwExtendedStyle = 0;
442 itxt->id = MSGBOX_IDTEXT;
443 dest += sizeof(DLGITEMTEMPLATE);
444 *(WORD*)dest = 0xFFFF;
445 dest += sizeof(WORD);
446 *(WORD*)dest = 0x0082; /* static control */
447 dest += sizeof(WORD);
448 memcpy(dest, text, textlen * sizeof(WCHAR));
449 dest += textlen * sizeof(WCHAR);
450 *(WCHAR*)dest = 0;
451 dest += sizeof(WCHAR);
452 *(WORD*)dest = 0;
453 dest += sizeof(WORD);
454
455 /* create buttons */
456 btnsize.cx = BTN_CX;
457 btnsize.cy = BTN_CY;
458 btnrect.left = btnrect.top = 0;
459 for(i = 0; i < nButtons; i++)
460 {
461 dest = (BYTE*)(((DWORD)dest + 3) & ~3);
462 ibtn[i] = (DLGITEMTEMPLATE *)dest;
463 ibtn[i]->style = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
464 if(!defbtn && (i == ((lpMsgBoxParams->dwStyle & MB_DEFMASK) >> 8)))
465 {
466 ibtn[i]->style |= BS_DEFPUSHBUTTON;
467 mbi.DefBtn = Buttons[i];
468 defbtn = TRUE;
469 }
470 else
471 ibtn[i]->style |= BS_PUSHBUTTON;
472 ibtn[i]->dwExtendedStyle = 0;
473 ibtn[i]->id = Buttons[i];
474 dest += sizeof(DLGITEMTEMPLATE);
475 *(WORD*)dest = 0xFFFF;
476 dest += sizeof(WORD);
477 *(WORD*)dest = 0x0080; /* button control */
478 dest += sizeof(WORD);
479 btnlen = strlenW(ButtonText[i]);
480 memcpy(dest, ButtonText[i], btnlen * sizeof(WCHAR));
481 dest += btnlen * sizeof(WCHAR);
482 *(WORD*)dest = 0;
483 dest += sizeof(WORD);
484 *(WORD*)dest = 0;
485 dest += sizeof(WORD);
486 SelectObject(hDC, hFont);
487 DrawTextW(hDC, ButtonText[i], btnlen, &btnrect, DT_LEFT | DT_SINGLELINE | DT_CALCRECT);
488 btnsize.cx = max(btnsize.cx, btnrect.right);
489 btnsize.cy = max(btnsize.cy, btnrect.bottom);
490 }
491
492 /* make first button the default button if no other is */
493 if(!defbtn)
494 {
495 ibtn[0]->style &= ~BS_PUSHBUTTON;
496 ibtn[0]->style |= BS_DEFPUSHBUTTON;
497 mbi.DefBtn = Buttons[0];
498 }
499
500 /* calculate position and size of controls */
501 txtrect.right = GetSystemMetrics(SM_CXSCREEN) / 5 * 4;
502 if(Icon)
503 txtrect.right -= GetSystemMetrics(SM_CXICON) + MSGBOXEX_SPACING;
504 txtrect.top = txtrect.left = txtrect.bottom = 0;
505 SelectObject(hDC, hFont);
506 DrawTextW(hDC, text, textlen, &txtrect, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
695 MessageBoxIndirectA(
696 CONST MSGBOXPARAMSA *lpMsgBoxParams)
697 {
698 MSGBOXPARAMSW msgboxW;
699 UNICODE_STRING textW, captionW, iconW;
700 int ret;
701
702 if (HIWORD((UINT)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)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)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)lpMsgBoxParams->lpszText))
757 RtlFreeUnicodeString(&textW);
758
759 if (HIWORD((UINT)lpMsgBoxParams->lpszCaption))
760 RtlFreeUnicodeString(&captionW);
761
762 if ((lpMsgBoxParams->dwStyle & MB_USERICON) && HIWORD((UINT)iconW.Buffer))
763 RtlFreeUnicodeString(&iconW);
764
765 return ret;
766 }
767
768
769 /*
770 * @implemented
771 */
772 int
773 STDCALL
774 MessageBoxIndirectW(
775 CONST MSGBOXPARAMSW *lpMsgBoxParams)
776 {
777 return MessageBoxTimeoutIndirectW(lpMsgBoxParams, (UINT)-1);
778 }
779
780
781 /*
782 * @implemented
783 */
784 int
785 STDCALL
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 STDCALL
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)lpText))
813 RtlCreateUnicodeStringFromAsciiz(&textW, (PCSZ)lpText);
814 else
815 textW.Buffer = (LPWSTR)lpText;
816
817 if (HIWORD((UINT)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 STDCALL
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 STDCALL
879 SoftModalMessageBox(DWORD Unknown0)
880 {
881 UNIMPLEMENTED;
882 return 0;
883 }
884
885
886 /*
887 * @implemented
888 */
889 BOOL
890 STDCALL
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 /* EOF */