3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
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.
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.
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.
21 * PROJECT: ReactOS user32.dll
22 * FILE: win32ss/user/user32/windows/messagebox.c
24 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Thomas Weidenmueller (w3seek@users.sourceforge.net)
27 * 2003/07/28 Added some NT features
28 * 2003/07/27 Code ported from wine
29 * 09-05-2001 CSH Created
34 WINE_DEFAULT_DEBUG_CHANNEL(user32
);
36 /* DEFINES *******************************************************************/
38 #define MSGBOX_IDICON (1088)
39 #define MSGBOX_IDTEXT (0xffff)
41 #define IDI_HANDW MAKEINTRESOURCEW(32513)
42 #define IDI_QUESTIONW MAKEINTRESOURCEW(32514)
43 #define IDI_EXCLAMATIONW MAKEINTRESOURCEW(32515)
44 #define IDI_ASTERISKW MAKEINTRESOURCEW(32516)
45 #define IDI_WINLOGOW MAKEINTRESOURCEW(32517)
48 /* MessageBox metrics */
53 #define MSGBOXEX_SPACING (16)
54 #define MSGBOXEX_BUTTONSPACING (6)
55 #define MSGBOXEX_MARGIN (12)
56 #define MSGBOXEX_MAXBTNSTR (32)
57 #define MSGBOXEX_MAXBTNS (4)
59 /* Rescale logical coordinates */
60 #define RESCALE_X(_x, _units) (((_x) * 4 + (_units).cx - 1) / (_units).cx)
61 #define RESCALE_Y(_y, _units) (((_y) * 8 + (_units).cy - 1) / (_units).cy)
64 /* MessageBox button helpers */
66 #define DECLARE_MB_1(_btn0) \
67 { 1, { ID##_btn0, 0, 0 }, { IDS_##_btn0, 0, 0 } }
69 #define DECLARE_MB_2(_btn0, _btn1) \
70 { 2, { ID##_btn0, ID##_btn1, 0 }, { IDS_##_btn0, IDS_##_btn1, 0 } }
72 #define DECLARE_MB_3(_btn0, _btn1, _btn2) \
73 { 3, { ID##_btn0, ID##_btn1, ID##_btn2 }, { IDS_##_btn0, IDS_##_btn1, IDS_##_btn2 } }
75 typedef struct _MSGBTNINFO
78 LONG btnIdx
[MSGBOXEX_MAXBTNS
];
79 UINT btnIds
[MSGBOXEX_MAXBTNS
];
80 } MSGBTNINFO
, *PMSGBTNINFO
;
82 /* Default MessageBox buttons */
83 static const MSGBTNINFO MsgBtnInfo
[] =
88 DECLARE_MB_2(OK
, CANCEL
),
89 /* MB_ABORTRETRYIGNORE (2) */
90 DECLARE_MB_3(ABORT
, RETRY
, IGNORE
),
91 /* MB_YESNOCANCEL (3) */
92 DECLARE_MB_3(YES
, NO
, CANCEL
),
94 DECLARE_MB_2(YES
, NO
),
95 /* MB_RETRYCANCEL (5) */
96 DECLARE_MB_2(RETRY
, CANCEL
),
97 /* MB_CANCELTRYCONTINUE (6) */
98 DECLARE_MB_3(CANCEL
, TRYAGAIN
, CONTINUE
)
101 typedef struct _MSGBOXINFO
103 MSGBOXPARAMSW
; // Wine passes this too.
110 } MSGBOXINFO
, *PMSGBOXINFO
;
112 /* INTERNAL FUNCTIONS ********************************************************/
114 static VOID
MessageBoxTextToClipboard(HWND DialogWindow
)
118 int cchTotal
, cchTitle
, cchText
, cchButton
, i
, n
, cchBuffer
;
119 LPWSTR pszBuffer
, pszBufferPos
, pMessageBoxText
, pszTitle
, pszText
, pszButton
;
120 WCHAR szButton
[MSGBOXEX_MAXBTNSTR
];
123 static const WCHAR szLine
[] = L
"---------------------------\r\n";
125 mbi
= (PMSGBOXINFO
)GetPropW(DialogWindow
, L
"ROS_MSGBOX");
126 hwndText
= GetDlgItem(DialogWindow
, MSGBOX_IDTEXT
);
127 cchTitle
= GetWindowTextLengthW(DialogWindow
) + 1;
128 cchText
= GetWindowTextLengthW(hwndText
) + 1;
133 pMessageBoxText
= (LPWSTR
)RtlAllocateHeap(GetProcessHeap(), 0, (cchTitle
+ cchText
) * sizeof(WCHAR
));
135 if (pMessageBoxText
== NULL
)
137 RtlFreeHeap(GetProcessHeap(), 0, pMessageBoxText
);
141 pszTitle
= pMessageBoxText
;
142 pszText
= pMessageBoxText
+ cchTitle
;
144 if (GetWindowTextW(DialogWindow
, pszTitle
, cchTitle
) == 0 ||
145 GetWindowTextW(hwndText
, pszText
, cchText
) == 0)
147 RtlFreeHeap(GetProcessHeap(), 0, pMessageBoxText
);
152 * Calculate the total buffer size.
154 cchTotal
= 6 + cchTitle
+ cchText
+ (lstrlenW(szLine
) * 4) + (mbi
->nButtons
* MSGBOXEX_MAXBTNSTR
+ 3);
156 hGlobal
= GlobalAlloc(GHND
, cchTotal
* sizeof(WCHAR
));
158 pszBuffer
= (LPWSTR
)GlobalLock(hGlobal
);
160 if (pszBuffer
== NULL
)
162 RtlFreeHeap(GetProcessHeap(), 0, pMessageBoxText
);
168 * First format title and text.
175 cchBuffer
= wsprintfW(pszBuffer
, L
"%s%s\r\n%s%s\r\n%s", szLine
, pszTitle
, szLine
, pszText
, szLine
);
176 pszBufferPos
= pszBuffer
+ cchBuffer
;
178 for (i
= 0; i
< mbi
->nButtons
; i
++)
180 GetDlgItemTextW(DialogWindow
, mbi
->Btns
[i
], szButton
, MSGBOXEX_MAXBTNSTR
);
182 cchButton
= strlenW(szButton
);
183 pszButton
= szButton
;
185 /* Skip '&' character. */
186 if (szButton
[0] == '&')
188 pszButton
= pszButton
+ 1;
189 cchButton
= cchButton
- 1;
192 for (n
= 0; n
< cchButton
; n
++)
193 *(pszBufferPos
++) = pszButton
[n
];
196 *(pszBufferPos
++) = L
' ';
197 *(pszBufferPos
++) = L
' ';
198 *(pszBufferPos
++) = L
' ';
201 wsprintfW(pszBufferPos
, L
"\r\n%s", szLine
);
203 GlobalUnlock(hGlobal
);
205 if (OpenClipboard(DialogWindow
))
208 SetClipboardData(CF_UNICODETEXT
, hGlobal
);
215 RtlFreeHeap(GetProcessHeap(), 0, pMessageBoxText
);
218 static INT_PTR CALLBACK
MessageBoxProc(
219 HWND hwnd
, UINT message
,
220 WPARAM wParam
, LPARAM lParam
)
231 mbi
= (PMSGBOXINFO
)lParam
;
233 SetWindowLongPtrW(hwnd
, GWLP_USERDATA
, (LONG_PTR
)mbi
);
234 NtUserxSetMessageBox(hwnd
);
236 if (!GetPropW(hwnd
, L
"ROS_MSGBOX"))
238 SetPropW(hwnd
, L
"ROS_MSGBOX", (HANDLE
)lParam
);
240 if (mbi
->dwContextHelpId
)
241 SetWindowContextHelpId(hwnd
, mbi
->dwContextHelpId
);
245 SendDlgItemMessageW(hwnd
, MSGBOX_IDICON
, STM_SETICON
, (WPARAM
)mbi
->Icon
, 0);
246 Alert
= ALERT_SYSTEM_WARNING
;
248 else // Setup the rest of the alerts.
250 switch (mbi
->dwStyle
& MB_ICONMASK
)
253 Alert
= ALERT_SYSTEM_WARNING
;
256 Alert
= ALERT_SYSTEM_ERROR
;
258 case MB_ICONQUESTION
:
259 Alert
= ALERT_SYSTEM_QUERY
;
262 Alert
= ALERT_SYSTEM_INFORMATIONAL
;
266 /* Send out the alert notifications. */
267 NotifyWinEvent(EVENT_SYSTEM_ALERT
, hwnd
, OBJID_ALERT
, Alert
);
269 switch (mbi
->dwStyle
& MB_TYPEMASK
)
271 case MB_ABORTRETRYIGNORE
:
273 RemoveMenu(GetSystemMenu(hwnd
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
276 SetFocus(GetDlgItem(hwnd
, mbi
->DefBtn
));
277 if (mbi
->Timeout
&& (mbi
->Timeout
!= (UINT
)-1))
278 SetTimer(hwnd
, 0, mbi
->Timeout
, NULL
);
284 switch (LOWORD(wParam
))
295 EndDialog(hwnd
, wParam
);
298 /* send WM_HELP message to messagebox window */
299 hi
.cbSize
= sizeof(HELPINFO
);
300 hi
.iContextType
= HELPINFO_WINDOW
;
301 hi
.iCtrlId
= LOWORD(wParam
);
302 hi
.hItemHandle
= (HANDLE
)lParam
;
304 GetCursorPos(&hi
.MousePos
);
305 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
311 MessageBoxTextToClipboard(hwnd
);
316 mbi
= (PMSGBOXINFO
)GetPropW(hwnd
, L
"ROS_MSGBOX");
319 memcpy(&hi
, (void *)lParam
, sizeof(hi
));
320 hi
.dwContextId
= GetWindowContextHelpId(hwnd
);
322 if (mbi
->lpfnMsgBoxCallback
)
323 mbi
->lpfnMsgBoxCallback(&hi
);
326 owner
= GetWindow(hwnd
, GW_OWNER
);
328 SendMessageW(GetWindow(hwnd
, GW_OWNER
), WM_HELP
, 0, (LPARAM
)&hi
);
335 mbi
= (PMSGBOXINFO
)GetPropW(hwnd
, L
"ROS_MSGBOX");
338 switch (mbi
->dwStyle
& MB_TYPEMASK
)
340 case MB_ABORTRETRYIGNORE
:
344 EndDialog(hwnd
, IDCANCEL
);
351 EndDialog(hwnd
, 32000);
359 MessageBoxTimeoutIndirectW(
360 CONST MSGBOXPARAMSW
*lpMsgBoxParams
, UINT Timeout
)
363 DLGITEMTEMPLATE
*iico
, *itxt
;
364 NONCLIENTMETRICSW nclm
;
367 LPCWSTR caption
, text
;
368 HFONT hFont
, hOldFont
;
373 int bufsize
, ret
, caplen
, textlen
, i
, btnleft
, btntop
, lmargin
;
375 LPCWSTR ButtonText
[MSGBOXEX_MAXBTNS
];
376 int ButtonLen
[MSGBOXEX_MAXBTNS
];
377 DLGITEMTEMPLATE
*ibtn
[MSGBOXEX_MAXBTNS
];
378 RECT btnrect
, txtrect
, rc
;
383 if (!lpMsgBoxParams
->lpszCaption
)
385 /* No caption, use the default one */
386 caplen
= LoadStringW(User32Instance
, IDS_ERROR
, (LPWSTR
)&caption
, 0);
388 else if (IS_INTRESOURCE(lpMsgBoxParams
->lpszCaption
))
390 /* User-defined resource string */
391 caplen
= LoadStringW(lpMsgBoxParams
->hInstance
, PtrToUlong(lpMsgBoxParams
->lpszCaption
), (LPWSTR
)&caption
, 0);
395 /* UNICODE string pointer */
396 caption
= lpMsgBoxParams
->lpszCaption
;
397 caplen
= strlenW(caption
);
400 if (!lpMsgBoxParams
->lpszText
)
402 /* No text, use blank */
406 else if (IS_INTRESOURCE(lpMsgBoxParams
->lpszText
))
408 /* User-defined resource string */
409 textlen
= LoadStringW(lpMsgBoxParams
->hInstance
, PtrToUlong(lpMsgBoxParams
->lpszText
), (LPWSTR
)&text
, 0);
413 /* UNICODE string pointer */
414 text
= lpMsgBoxParams
->lpszText
;
415 textlen
= strlenW(text
);
418 /* Create the selected buttons; unknown types will fall back to MB_OK */
419 i
= (lpMsgBoxParams
->dwStyle
& MB_TYPEMASK
);
420 if (i
>= ARRAYSIZE(MsgBtnInfo
))
423 /* Get buttons IDs */
424 Buttons
= MsgBtnInfo
[i
];
426 /* Add the Help button */
427 if (lpMsgBoxParams
->dwStyle
& MB_HELP
)
429 Buttons
.btnIdx
[Buttons
.btnCnt
] = IDHELP
;
430 Buttons
.btnIds
[Buttons
.btnCnt
] = IDS_HELP
;
434 switch (lpMsgBoxParams
->dwStyle
& MB_ICONMASK
)
436 case MB_ICONEXCLAMATION
:
437 Icon
= LoadIconW(0, IDI_EXCLAMATIONW
);
438 MessageBeep(MB_ICONEXCLAMATION
);
440 case MB_ICONQUESTION
:
441 Icon
= LoadIconW(0, IDI_QUESTIONW
);
442 MessageBeep(MB_ICONQUESTION
);
444 case MB_ICONASTERISK
:
445 Icon
= LoadIconW(0, IDI_ASTERISKW
);
446 MessageBeep(MB_ICONASTERISK
);
449 Icon
= LoadIconW(0, IDI_HANDW
);
450 MessageBeep(MB_ICONHAND
);
453 Icon
= LoadIconW(lpMsgBoxParams
->hInstance
, lpMsgBoxParams
->lpszIcon
);
457 /* By default, Windows 95/98/NT does not associate an icon to message boxes.
458 * So ReactOS should do the same.
466 bufsize
= sizeof(DLGTEMPLATE
) +
467 2 * sizeof(WORD
) + /* menu and class */
468 (caplen
+ 1) * sizeof(WCHAR
) + /* title */
469 sizeof(WORD
); /* font height */
474 bufsize
= (bufsize
+ 3) & ~3;
475 bufsize
+= sizeof(DLGITEMTEMPLATE
) +
481 bufsize
= (bufsize
+ 3) & ~3;
482 bufsize
+= sizeof(DLGITEMTEMPLATE
) +
484 (textlen
+ 1) * sizeof(WCHAR
);
486 for (i
= 0; i
< Buttons
.btnCnt
; i
++)
488 /* Get the default text of the buttons */
489 if (Buttons
.btnIds
[i
])
491 ButtonLen
[i
] = LoadStringW(User32Instance
, Buttons
.btnIds
[i
], (LPWSTR
)&ButtonText
[i
], 0);
499 /* Space for buttons */
500 bufsize
= (bufsize
+ 3) & ~3;
501 bufsize
+= sizeof(DLGITEMTEMPLATE
) +
503 (ButtonLen
[i
] + 1) * sizeof(WCHAR
);
506 buf
= RtlAllocateHeap(GetProcessHeap(), 0, bufsize
);
512 nclm
.cbSize
= sizeof(nclm
);
513 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(nclm
), &nclm
, 0);
514 hFont
= CreateFontIndirectW(&nclm
.lfMessageFont
);
517 ERR("Cannot retrieve nclm.lfMessageFont!\n");
521 tpl
= (DLGTEMPLATE
*)buf
;
523 tpl
->style
= WS_CAPTION
| WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_SYSMENU
| DS_CENTER
| DS_SETFONT
| DS_MODALFRAME
| DS_NOIDLEMSG
;
524 tpl
->dwExtendedStyle
= WS_EX_DLGMODALFRAME
| WS_EX_WINDOWEDGE
| WS_EX_CONTROLPARENT
;
525 if (lpMsgBoxParams
->dwStyle
& MB_TOPMOST
)
526 tpl
->dwExtendedStyle
|= WS_EX_TOPMOST
;
527 if (lpMsgBoxParams
->dwStyle
& MB_RIGHT
)
528 tpl
->dwExtendedStyle
|= WS_EX_RIGHT
;
531 tpl
->cdit
= Buttons
.btnCnt
+ ((Icon
!= (HICON
)0) ? 1 : 0) + 1;
533 dest
= (BYTE
*)(tpl
+ 1);
535 *(WORD
*)dest
= 0; /* no menu */
536 *(((WORD
*)dest
) + 1) = 0; /* use default window class */
537 dest
+= 2 * sizeof(WORD
);
538 memcpy(dest
, caption
, caplen
* sizeof(WCHAR
));
539 dest
+= caplen
* sizeof(WCHAR
);
540 *(WCHAR
*)dest
= L
'\0';
541 dest
+= sizeof(WCHAR
);
544 * A font point size (height) of 0x7FFF means that we use
545 * the message box font (NONCLIENTMETRICSW.lfMessageFont).
547 *(WORD
*)dest
= 0x7FFF;
548 dest
+= sizeof(WORD
);
553 dest
= (BYTE
*)(((ULONG_PTR
)dest
+ 3) & ~3);
554 iico
= (DLGITEMTEMPLATE
*)dest
;
555 iico
->style
= WS_CHILD
| WS_VISIBLE
| SS_ICON
;
556 iico
->dwExtendedStyle
= 0;
557 iico
->id
= MSGBOX_IDICON
;
559 dest
+= sizeof(DLGITEMTEMPLATE
);
560 *(WORD
*)dest
= 0xFFFF;
561 dest
+= sizeof(WORD
);
562 *(WORD
*)dest
= 0x0082; /* static control */
563 dest
+= sizeof(WORD
);
564 *(WORD
*)dest
= 0xFFFF;
565 dest
+= sizeof(WORD
);
567 dest
+= sizeof(WCHAR
);
569 dest
+= sizeof(WORD
);
572 /* create static for text */
573 dest
= (BYTE
*)(((UINT_PTR
)dest
+ 3) & ~3);
574 itxt
= (DLGITEMTEMPLATE
*)dest
;
575 itxt
->style
= WS_CHILD
| WS_VISIBLE
| SS_NOPREFIX
;
576 if (lpMsgBoxParams
->dwStyle
& MB_RIGHT
)
577 itxt
->style
|= SS_RIGHT
;
579 itxt
->style
|= SS_LEFT
;
580 itxt
->dwExtendedStyle
= 0;
581 itxt
->id
= MSGBOX_IDTEXT
;
582 dest
+= sizeof(DLGITEMTEMPLATE
);
583 *(WORD
*)dest
= 0xFFFF;
584 dest
+= sizeof(WORD
);
585 *(WORD
*)dest
= 0x0082; /* static control */
586 dest
+= sizeof(WORD
);
587 memcpy(dest
, text
, textlen
* sizeof(WCHAR
));
588 dest
+= textlen
* sizeof(WCHAR
);
590 dest
+= sizeof(WCHAR
);
592 dest
+= sizeof(WORD
);
595 hDC
= GetDCEx(hDCWnd
, NULL
, DCX_WINDOW
| DCX_CACHE
);
598 /* Retry with the DC of the owner window */
599 hDCWnd
= lpMsgBoxParams
->hwndOwner
;
600 hDC
= GetDCEx(hDCWnd
, NULL
, DCX_WINDOW
| DCX_CACHE
);
604 ERR("GetDCEx() failed, bail out!\n");
607 hOldFont
= SelectObject(hDC
, hFont
);
609 units
.cx
= GdiGetCharDimensions(hDC
, NULL
, &units
.cy
);
613 ERR("GdiGetCharDimensions() failed, falling back to default values!\n");
614 defUnits
= GetDialogBaseUnits();
615 units
.cx
= LOWORD(defUnits
);
616 units
.cy
= HIWORD(defUnits
);
622 btnrect
.left
= btnrect
.top
= 0;
624 for (i
= 0; i
< Buttons
.btnCnt
; i
++)
626 dest
= (BYTE
*)(((UINT_PTR
)dest
+ 3) & ~3);
627 ibtn
[i
] = (DLGITEMTEMPLATE
*)dest
;
628 ibtn
[i
]->style
= WS_CHILD
| WS_VISIBLE
| WS_TABSTOP
;
629 if (!defbtn
&& (i
== ((lpMsgBoxParams
->dwStyle
& MB_DEFMASK
) >> 8)))
631 ibtn
[i
]->style
|= BS_DEFPUSHBUTTON
;
632 mbi
.DefBtn
= Buttons
.btnIdx
[i
];
637 ibtn
[i
]->style
|= BS_PUSHBUTTON
;
639 ibtn
[i
]->dwExtendedStyle
= 0;
640 ibtn
[i
]->id
= Buttons
.btnIdx
[i
];
641 dest
+= sizeof(DLGITEMTEMPLATE
);
642 *(WORD
*)dest
= 0xFFFF;
643 dest
+= sizeof(WORD
);
644 *(WORD
*)dest
= 0x0080; /* button control */
645 dest
+= sizeof(WORD
);
646 memcpy(dest
, ButtonText
[i
], ButtonLen
[i
] * sizeof(WCHAR
));
647 dest
+= ButtonLen
[i
] * sizeof(WCHAR
);
649 dest
+= sizeof(WORD
);
651 dest
+= sizeof(WORD
);
653 // btnrect.right = btnrect.bottom = 0; // FIXME: Is it needed??
654 DrawTextW(hDC
, ButtonText
[i
], ButtonLen
[i
], &btnrect
, DT_LEFT
| DT_SINGLELINE
| DT_CALCRECT
);
655 btnsize
.cx
= max(btnsize
.cx
, btnrect
.right
);
656 btnsize
.cy
= max(btnsize
.cy
, btnrect
.bottom
);
659 /* make first button the default button if no other is */
662 ibtn
[0]->style
&= ~BS_PUSHBUTTON
;
663 ibtn
[0]->style
|= BS_DEFPUSHBUTTON
;
664 mbi
.DefBtn
= Buttons
.btnIdx
[0];
667 /* calculate position and size of controls */
668 txtrect
.right
= GetSystemMetrics(SM_CXSCREEN
) / 5 * 4;
670 txtrect
.right
-= GetSystemMetrics(SM_CXICON
) + MSGBOXEX_SPACING
;
671 txtrect
.top
= txtrect
.left
= txtrect
.bottom
= 0;
674 DrawTextW(hDC
, text
, textlen
, &txtrect
, DT_LEFT
| DT_NOPREFIX
| DT_WORDBREAK
| DT_EXPANDTABS
| DT_EXTERNALLEADING
| DT_EDITCONTROL
| DT_CALCRECT
);
678 txtrect
.right
= txtrect
.left
+ 1;
679 txtrect
.bottom
= txtrect
.top
+ 1;
684 SelectObject(hDC
, hOldFont
);
686 ReleaseDC(hDCWnd
, hDC
);
691 /* calculate position and size of the icon */
692 rc
.left
= rc
.bottom
= rc
.right
= 0;
697 rc
.right
= GetSystemMetrics(SM_CXICON
);
698 rc
.bottom
= GetSystemMetrics(SM_CYICON
);
699 #ifdef MSGBOX_ICONVCENTER
700 rc
.top
= MSGBOXEX_MARGIN
+ (max(txtrect
.bottom
, rc
.bottom
) / 2) - (GetSystemMetrics(SM_CYICON
) / 2);
701 rc
.top
= max(MSGBOXEX_SPACING
, rc
.top
);
703 rc
.top
= MSGBOXEX_MARGIN
;
705 btnleft
= (Buttons
.btnCnt
* (btnsize
.cx
+ MSGBOXEX_BUTTONSPACING
)) - MSGBOXEX_BUTTONSPACING
;
706 if (btnleft
> txtrect
.right
+ rc
.right
+ MSGBOXEX_SPACING
)
708 #ifdef MSGBOX_TEXTHCENTER
709 lmargin
= MSGBOXEX_MARGIN
+ ((btnleft
- txtrect
.right
- rc
.right
- MSGBOXEX_SPACING
) / 2);
711 lmargin
= MSGBOXEX_MARGIN
;
713 btnleft
= MSGBOXEX_MARGIN
;
717 lmargin
= MSGBOXEX_MARGIN
;
718 btnleft
= MSGBOXEX_MARGIN
+ ((txtrect
.right
+ rc
.right
+ MSGBOXEX_SPACING
) / 2) - (btnleft
/ 2);
721 iico
->x
= RESCALE_X(rc
.left
, units
);
722 iico
->y
= RESCALE_Y(rc
.top
, units
);
723 iico
->cx
= RESCALE_X(rc
.right
, units
);
724 iico
->cy
= RESCALE_Y(rc
.bottom
, units
);
725 btntop
= rc
.top
+ rc
.bottom
+ MSGBOXEX_SPACING
;
726 rc
.left
+= rc
.right
+ MSGBOXEX_SPACING
;
730 btnleft
= (Buttons
.btnCnt
* (btnsize
.cx
+ MSGBOXEX_BUTTONSPACING
)) - MSGBOXEX_BUTTONSPACING
;
731 if (btnleft
> txtrect
.right
)
733 #ifdef MSGBOX_TEXTHCENTER
734 lmargin
= MSGBOXEX_MARGIN
+ ((btnleft
- txtrect
.right
) / 2);
736 lmargin
= MSGBOXEX_MARGIN
;
738 btnleft
= MSGBOXEX_MARGIN
;
742 lmargin
= MSGBOXEX_MARGIN
;
743 btnleft
= MSGBOXEX_MARGIN
+ (txtrect
.right
/ 2) - (btnleft
/ 2);
747 /* calculate position of the text */
748 rc
.top
= MSGBOXEX_MARGIN
+ (rc
.bottom
/ 2) - (txtrect
.bottom
/ 2);
749 rc
.top
= max(rc
.top
, MSGBOXEX_MARGIN
);
750 /* calculate position of the buttons */
751 btntop
= max(rc
.top
+ txtrect
.bottom
+ MSGBOXEX_SPACING
, btntop
);
752 for (i
= 0; i
< Buttons
.btnCnt
; i
++)
754 ibtn
[i
]->x
= RESCALE_X(btnleft
, units
);
755 ibtn
[i
]->y
= RESCALE_Y(btntop
, units
);
756 ibtn
[i
]->cx
= RESCALE_X(btnsize
.cx
, units
);
757 ibtn
[i
]->cy
= RESCALE_Y(btnsize
.cy
, units
);
758 btnleft
+= btnsize
.cx
+ MSGBOXEX_BUTTONSPACING
;
760 /* calculate size and position of the messagebox window */
761 btnleft
= max(btnleft
- MSGBOXEX_BUTTONSPACING
, rc
.left
+ txtrect
.right
);
762 btnleft
+= MSGBOXEX_MARGIN
;
763 btntop
+= btnsize
.cy
+ MSGBOXEX_MARGIN
;
764 /* set size and position of the message static */
765 itxt
->x
= RESCALE_X(rc
.left
, units
);
766 itxt
->y
= RESCALE_Y(rc
.top
, units
);
767 itxt
->cx
= RESCALE_X(btnleft
- rc
.left
- MSGBOXEX_MARGIN
, units
);
768 itxt
->cy
= RESCALE_Y(txtrect
.bottom
, units
);
769 /* set size of the window */
770 tpl
->cx
= RESCALE_X(btnleft
, units
);
771 tpl
->cy
= RESCALE_Y(btntop
, units
);
773 /* finally show the messagebox */
775 mbi
.dwContextHelpId
= lpMsgBoxParams
->dwContextHelpId
;
776 mbi
.lpfnMsgBoxCallback
= lpMsgBoxParams
->lpfnMsgBoxCallback
;
777 mbi
.dwStyle
= lpMsgBoxParams
->dwStyle
;
778 mbi
.nButtons
= Buttons
.btnCnt
;
779 mbi
.Btns
= Buttons
.btnIdx
;
780 mbi
.Timeout
= Timeout
;
782 /* Pass on to Justin Case so he can peek the message? */
783 mbi
.cbSize
= lpMsgBoxParams
->cbSize
;
784 mbi
.hwndOwner
= lpMsgBoxParams
->hwndOwner
;
785 mbi
.hInstance
= lpMsgBoxParams
->hInstance
;
786 mbi
.lpszText
= lpMsgBoxParams
->lpszText
;
787 mbi
.lpszCaption
= lpMsgBoxParams
->lpszCaption
;
788 mbi
.lpszIcon
= lpMsgBoxParams
->lpszIcon
;
789 mbi
.dwLanguageId
= lpMsgBoxParams
->dwLanguageId
;
791 ret
= DialogBoxIndirectParamW(lpMsgBoxParams
->hInstance
, tpl
, lpMsgBoxParams
->hwndOwner
,
792 MessageBoxProc
, (LPARAM
)&mbi
);
795 RtlFreeHeap(GetProcessHeap(), 0, buf
);
799 /* FUNCTIONS *****************************************************************/
813 return MessageBoxExA(hWnd
, lpText
, lpCaption
, uType
, LANG_NEUTRAL
);
824 IN LPCWSTR lpCaption
,
827 return MessageBoxExW(hWnd
, lpText
, lpCaption
, uType
, LANG_NEUTRAL
);
843 MSGBOXPARAMSA msgbox
;
845 msgbox
.cbSize
= sizeof(msgbox
);
846 msgbox
.hwndOwner
= hWnd
;
847 msgbox
.hInstance
= 0;
848 msgbox
.lpszText
= lpText
;
849 msgbox
.lpszCaption
= lpCaption
;
850 msgbox
.dwStyle
= uType
;
851 msgbox
.lpszIcon
= NULL
;
852 msgbox
.dwContextHelpId
= 0;
853 msgbox
.lpfnMsgBoxCallback
= NULL
;
854 msgbox
.dwLanguageId
= wLanguageId
;
856 return MessageBoxIndirectA(&msgbox
);
867 IN LPCWSTR lpCaption
,
871 MSGBOXPARAMSW msgbox
;
873 msgbox
.cbSize
= sizeof(msgbox
);
874 msgbox
.hwndOwner
= hWnd
;
875 msgbox
.hInstance
= 0;
876 msgbox
.lpszText
= lpText
;
877 msgbox
.lpszCaption
= lpCaption
;
878 msgbox
.dwStyle
= uType
;
879 msgbox
.lpszIcon
= NULL
;
880 msgbox
.dwContextHelpId
= 0;
881 msgbox
.lpfnMsgBoxCallback
= NULL
;
882 msgbox
.dwLanguageId
= wLanguageId
;
884 return MessageBoxTimeoutIndirectW(&msgbox
, (UINT
)-1);
894 IN CONST MSGBOXPARAMSA
* lpMsgBoxParams
)
896 MSGBOXPARAMSW msgboxW
;
897 UNICODE_STRING textW
, captionW
, iconW
;
900 if (!IS_INTRESOURCE(lpMsgBoxParams
->lpszText
))
902 RtlCreateUnicodeStringFromAsciiz(&textW
, (PCSZ
)lpMsgBoxParams
->lpszText
);
904 * UNICODE_STRING objects are always allocated with an extra byte so you
905 * can null-term if you want
907 textW
.Buffer
[textW
.Length
/ sizeof(WCHAR
)] = L
'\0';
910 textW
.Buffer
= (LPWSTR
)lpMsgBoxParams
->lpszText
;
912 if (!IS_INTRESOURCE(lpMsgBoxParams
->lpszCaption
))
914 RtlCreateUnicodeStringFromAsciiz(&captionW
, (PCSZ
)lpMsgBoxParams
->lpszCaption
);
916 * UNICODE_STRING objects are always allocated with an extra byte so you
917 * can null-term if you want
919 captionW
.Buffer
[captionW
.Length
/ sizeof(WCHAR
)] = L
'\0';
922 captionW
.Buffer
= (LPWSTR
)lpMsgBoxParams
->lpszCaption
;
924 if (lpMsgBoxParams
->dwStyle
& MB_USERICON
)
926 if (!IS_INTRESOURCE(lpMsgBoxParams
->lpszIcon
))
928 RtlCreateUnicodeStringFromAsciiz(&iconW
, (PCSZ
)lpMsgBoxParams
->lpszIcon
);
930 * UNICODE_STRING objects are always allocated with an extra byte so you
931 * can null-term if you want
933 iconW
.Buffer
[iconW
.Length
/ sizeof(WCHAR
)] = L
'\0';
936 iconW
.Buffer
= (LPWSTR
)lpMsgBoxParams
->lpszIcon
;
941 msgboxW
.cbSize
= sizeof(msgboxW
);
942 msgboxW
.hwndOwner
= lpMsgBoxParams
->hwndOwner
;
943 msgboxW
.hInstance
= lpMsgBoxParams
->hInstance
;
944 msgboxW
.lpszText
= textW
.Buffer
;
945 msgboxW
.lpszCaption
= captionW
.Buffer
;
946 msgboxW
.dwStyle
= lpMsgBoxParams
->dwStyle
;
947 msgboxW
.lpszIcon
= iconW
.Buffer
;
948 msgboxW
.dwContextHelpId
= lpMsgBoxParams
->dwContextHelpId
;
949 msgboxW
.lpfnMsgBoxCallback
= lpMsgBoxParams
->lpfnMsgBoxCallback
;
950 msgboxW
.dwLanguageId
= lpMsgBoxParams
->dwLanguageId
;
952 ret
= MessageBoxTimeoutIndirectW(&msgboxW
, (UINT
)-1);
954 if (!IS_INTRESOURCE(lpMsgBoxParams
->lpszText
))
955 RtlFreeUnicodeString(&textW
);
957 if (!IS_INTRESOURCE(lpMsgBoxParams
->lpszCaption
))
958 RtlFreeUnicodeString(&captionW
);
960 if ((lpMsgBoxParams
->dwStyle
& MB_USERICON
) && !IS_INTRESOURCE(iconW
.Buffer
))
961 RtlFreeUnicodeString(&iconW
);
972 IN CONST MSGBOXPARAMSW
* lpMsgBoxParams
)
974 return MessageBoxTimeoutIndirectW(lpMsgBoxParams
, (UINT
)-1);
991 MSGBOXPARAMSW msgboxW
;
992 UNICODE_STRING textW
, captionW
;
995 if (!IS_INTRESOURCE(lpText
))
996 RtlCreateUnicodeStringFromAsciiz(&textW
, (PCSZ
)lpText
);
998 textW
.Buffer
= (LPWSTR
)lpText
;
1000 if (!IS_INTRESOURCE(lpCaption
))
1001 RtlCreateUnicodeStringFromAsciiz(&captionW
, (PCSZ
)lpCaption
);
1003 captionW
.Buffer
= (LPWSTR
)lpCaption
;
1005 msgboxW
.cbSize
= sizeof(msgboxW
);
1006 msgboxW
.hwndOwner
= hWnd
;
1007 msgboxW
.hInstance
= 0;
1008 msgboxW
.lpszText
= textW
.Buffer
;
1009 msgboxW
.lpszCaption
= captionW
.Buffer
;
1010 msgboxW
.dwStyle
= uType
;
1011 msgboxW
.lpszIcon
= NULL
;
1012 msgboxW
.dwContextHelpId
= 0;
1013 msgboxW
.lpfnMsgBoxCallback
= NULL
;
1014 msgboxW
.dwLanguageId
= wLanguageId
;
1016 ret
= MessageBoxTimeoutIndirectW(&msgboxW
, (UINT
)dwTimeout
);
1018 if (!IS_INTRESOURCE(textW
.Buffer
))
1019 RtlFreeUnicodeString(&textW
);
1021 if (!IS_INTRESOURCE(captionW
.Buffer
))
1022 RtlFreeUnicodeString(&captionW
);
1035 IN LPCWSTR lpCaption
,
1037 IN WORD wLanguageId
,
1040 MSGBOXPARAMSW msgbox
;
1042 msgbox
.cbSize
= sizeof(msgbox
);
1043 msgbox
.hwndOwner
= hWnd
;
1044 msgbox
.hInstance
= 0;
1045 msgbox
.lpszText
= lpText
;
1046 msgbox
.lpszCaption
= lpCaption
;
1047 msgbox
.dwStyle
= uType
;
1048 msgbox
.lpszIcon
= NULL
;
1049 msgbox
.dwContextHelpId
= 0;
1050 msgbox
.lpfnMsgBoxCallback
= NULL
;
1051 msgbox
.dwLanguageId
= wLanguageId
;
1053 return MessageBoxTimeoutIndirectW(&msgbox
, (UINT
)dwTimeout
);
1062 SoftModalMessageBox(DWORD Unknown0
)
1074 MessageBeep(IN UINT uType
)
1076 return NtUserxMessageBeep(uType
);
1083 * See: https://msdn.microsoft.com/en-us/library/windows/desktop/dn910915(v=vs.85).aspx
1084 * and: http://undoc.airesoft.co.uk/user32.dll/MB_GetString.php
1085 * for more information.
1089 MB_GetString(IN UINT wBtn
)
1091 LPCWSTR btnStr
= NULL
;
1094 * The allowable IDs are between "IDOK - 1" (0) and "IDCONTINUE - 1" (10) inclusive.
1095 * See psdk/winuser.h and user32/include/resource.h .
1097 if (wBtn
> IDCONTINUE
- 1)
1100 wBtn
+= 800; // See user32/include/resource.h
1101 LoadStringW(User32Instance
, wBtn
, (LPWSTR
)&btnStr
, 0);