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