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