4 * Copyright 1995 Bernd Schmidt
5 * Copyright 2004 Ivan Leo Puoti, Juan Lang
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/winbase16.h"
29 #include "wine/winuser16.h"
32 #include "user_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(dialog
);
36 WINE_DECLARE_DEBUG_CHANNEL(msgbox
);
38 #define MSGBOX_IDICON 1088
39 #define MSGBOX_IDTEXT 100
49 static BOOL CALLBACK
MSGBOX_EnumProc(HWND hwnd
, LPARAM lParam
)
51 struct ThreadWindows
*threadWindows
= (struct ThreadWindows
*)lParam
;
53 if (!EnableWindow(hwnd
, FALSE
))
55 if(threadWindows
->numHandles
>= threadWindows
->numAllocs
)
57 threadWindows
->handles
= HeapReAlloc(GetProcessHeap(), 0, threadWindows
->handles
,
58 (threadWindows
->numAllocs
*2)*sizeof(HWND
));
59 threadWindows
->numAllocs
*= 2;
61 threadWindows
->handles
[threadWindows
->numHandles
++]=hwnd
;
66 static HFONT
MSGBOX_OnInit(HWND hwnd
, LPMSGBOXPARAMSW lpmb
)
68 HFONT hFont
= 0, hPrevFont
= 0;
73 int bspace
, bw
, bh
, theight
, tleft
, wwidth
, wheight
, bpos
;
74 int borheight
, borwidth
, iheight
, ileft
, iwidth
, twidth
, tiheight
;
75 NONCLIENTMETRICSW nclm
;
79 nclm
.cbSize
= sizeof(nclm
);
80 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS
, 0, &nclm
, 0);
81 hFont
= CreateFontIndirectW (&nclm
.lfMessageFont
);
84 SendDlgItemMessageW (hwnd
, i
, WM_SETFONT
, (WPARAM
)hFont
, 0);
86 SendDlgItemMessageW (hwnd
, MSGBOX_IDTEXT
, WM_SETFONT
, (WPARAM
)hFont
, 0);
88 if (HIWORD(lpmb
->lpszCaption
)) {
89 SetWindowTextW(hwnd
, lpmb
->lpszCaption
);
91 UINT res_id
= LOWORD(lpmb
->lpszCaption
);
94 if (LoadStringW(lpmb
->hInstance
, res_id
, buf
, 256))
95 SetWindowTextW(hwnd
, buf
);
99 if (LoadStringW(user32_module
, IDS_ERROR
, buf
, 256))
100 SetWindowTextW(hwnd
, buf
);
103 if (HIWORD(lpmb
->lpszText
)) {
104 lpszText
= lpmb
->lpszText
;
107 if (!LoadStringW(lpmb
->hInstance
, LOWORD(lpmb
->lpszText
), buf
, 256))
108 *buf
= 0; /* FIXME ?? */
111 TRACE_(msgbox
)("%s\n", debugstr_w(lpszText
));
112 SetWindowTextW(GetDlgItem(hwnd
, MSGBOX_IDTEXT
), lpszText
);
114 /* Hide not selected buttons */
115 switch(lpmb
->dwStyle
& MB_TYPEMASK
) {
117 ShowWindow(GetDlgItem(hwnd
, IDCANCEL
), SW_HIDE
);
120 ShowWindow(GetDlgItem(hwnd
, IDABORT
), SW_HIDE
);
121 ShowWindow(GetDlgItem(hwnd
, IDRETRY
), SW_HIDE
);
122 ShowWindow(GetDlgItem(hwnd
, IDIGNORE
), SW_HIDE
);
123 ShowWindow(GetDlgItem(hwnd
, IDYES
), SW_HIDE
);
124 ShowWindow(GetDlgItem(hwnd
, IDNO
), SW_HIDE
);
126 case MB_ABORTRETRYIGNORE
:
127 ShowWindow(GetDlgItem(hwnd
, IDOK
), SW_HIDE
);
128 ShowWindow(GetDlgItem(hwnd
, IDCANCEL
), SW_HIDE
);
129 ShowWindow(GetDlgItem(hwnd
, IDYES
), SW_HIDE
);
130 ShowWindow(GetDlgItem(hwnd
, IDNO
), SW_HIDE
);
133 ShowWindow(GetDlgItem(hwnd
, IDCANCEL
), SW_HIDE
);
136 ShowWindow(GetDlgItem(hwnd
, IDOK
), SW_HIDE
);
137 ShowWindow(GetDlgItem(hwnd
, IDABORT
), SW_HIDE
);
138 ShowWindow(GetDlgItem(hwnd
, IDRETRY
), SW_HIDE
);
139 ShowWindow(GetDlgItem(hwnd
, IDIGNORE
), SW_HIDE
);
142 ShowWindow(GetDlgItem(hwnd
, IDOK
), SW_HIDE
);
143 ShowWindow(GetDlgItem(hwnd
, IDABORT
), SW_HIDE
);
144 ShowWindow(GetDlgItem(hwnd
, IDIGNORE
), SW_HIDE
);
145 ShowWindow(GetDlgItem(hwnd
, IDYES
), SW_HIDE
);
146 ShowWindow(GetDlgItem(hwnd
, IDNO
), SW_HIDE
);
150 switch(lpmb
->dwStyle
& MB_ICONMASK
) {
151 case MB_ICONEXCLAMATION
:
152 SendDlgItemMessageW(hwnd
, stc1
, STM_SETICON
,
153 (WPARAM
)LoadIconW(0, (LPWSTR
)IDI_EXCLAMATION
), 0);
155 case MB_ICONQUESTION
:
156 SendDlgItemMessageW(hwnd
, stc1
, STM_SETICON
,
157 (WPARAM
)LoadIconW(0, (LPWSTR
)IDI_QUESTION
), 0);
159 case MB_ICONASTERISK
:
160 SendDlgItemMessageW(hwnd
, stc1
, STM_SETICON
,
161 (WPARAM
)LoadIconW(0, (LPWSTR
)IDI_ASTERISK
), 0);
164 SendDlgItemMessageW(hwnd
, stc1
, STM_SETICON
,
165 (WPARAM
)LoadIconW(0, (LPWSTR
)IDI_HAND
), 0);
168 SendDlgItemMessageW(hwnd
, stc1
, STM_SETICON
,
169 (WPARAM
)LoadIconW(lpmb
->hInstance
, lpmb
->lpszIcon
), 0);
172 /* By default, Windows 95/98/NT do not associate an icon to message boxes.
173 * So wine should do the same.
178 /* Position everything */
179 GetWindowRect(hwnd
, &rect
);
180 borheight
= rect
.bottom
- rect
.top
;
181 borwidth
= rect
.right
- rect
.left
;
182 GetClientRect(hwnd
, &rect
);
183 borheight
-= rect
.bottom
- rect
.top
;
184 borwidth
-= rect
.right
- rect
.left
;
186 /* Get the icon height */
187 GetWindowRect(GetDlgItem(hwnd
, MSGBOX_IDICON
), &rect
);
188 MapWindowPoints(0, hwnd
, (LPPOINT
)&rect
, 2);
189 if (!(lpmb
->dwStyle
& MB_ICONMASK
))
191 rect
.bottom
= rect
.top
;
192 rect
.right
= rect
.left
;
194 iheight
= rect
.bottom
- rect
.top
;
196 iwidth
= rect
.right
- ileft
;
200 hPrevFont
= SelectObject(hdc
, hFont
);
202 /* Get the number of visible buttons and their size */
203 bh
= bw
= 1; /* Minimum button sizes */
204 for (buttons
= 0, i
= 1; i
< 8; i
++)
206 hItem
= GetDlgItem(hwnd
, i
);
207 if (GetWindowLongW(hItem
, GWL_STYLE
) & WS_VISIBLE
)
209 WCHAR buttonText
[1024];
212 if (GetWindowTextW(hItem
, buttonText
, 1024))
214 DrawTextW( hdc
, buttonText
, -1, &rect
, DT_LEFT
| DT_EXPANDTABS
| DT_CALCRECT
);
215 h
= rect
.bottom
- rect
.top
;
216 w
= rect
.right
- rect
.left
;
222 bw
= max(bw
, bh
* 2);
223 /* Button white space */
226 bspace
= bw
/3; /* Space between buttons */
228 /* Get the text size */
229 GetClientRect(GetDlgItem(hwnd
, MSGBOX_IDTEXT
), &rect
);
230 rect
.top
= rect
.left
= rect
.bottom
= 0;
231 DrawTextW( hdc
, lpszText
, -1, &rect
,
232 DT_LEFT
| DT_EXPANDTABS
| DT_WORDBREAK
| DT_CALCRECT
);
233 /* Min text width corresponds to space for the buttons */
235 if (iwidth
) tleft
+= ileft
+ iwidth
;
236 twidth
= max((bw
+ bspace
) * buttons
+ bspace
- tleft
, rect
.right
);
237 theight
= rect
.bottom
;
240 SelectObject(hdc
, hPrevFont
);
241 ReleaseDC(hwnd
, hdc
);
243 tiheight
= 16 + max(iheight
, theight
);
244 wwidth
= tleft
+ twidth
+ ileft
+ borwidth
;
245 wheight
= 8 + tiheight
+ bh
+ borheight
;
247 /* Resize the window */
248 SetWindowPos(hwnd
, 0, 0, 0, wwidth
, wheight
,
249 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
251 /* Position the icon */
252 SetWindowPos(GetDlgItem(hwnd
, MSGBOX_IDICON
), 0, ileft
, (tiheight
- iheight
) / 2, 0, 0,
253 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
255 /* Position the text */
256 SetWindowPos(GetDlgItem(hwnd
, MSGBOX_IDTEXT
), 0, tleft
, (tiheight
- theight
) / 2, twidth
, theight
,
257 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
259 /* Position the buttons */
260 bpos
= (wwidth
- (bw
+ bspace
) * buttons
+ bspace
) / 2;
261 for (buttons
= i
= 0; i
< 7; i
++) {
262 /* some arithmetic to get the right order for YesNoCancel windows */
263 hItem
= GetDlgItem(hwnd
, (i
+ 5) % 7 + 1);
264 if (GetWindowLongW(hItem
, GWL_STYLE
) & WS_VISIBLE
) {
265 if (buttons
++ == ((lpmb
->dwStyle
& MB_DEFMASK
) >> 8)) {
267 SendMessageW( hItem
, BM_SETSTYLE
, BS_DEFPUSHBUTTON
, TRUE
);
269 SetWindowPos(hItem
, 0, bpos
, tiheight
, bw
, bh
,
270 SWP_NOZORDER
|SWP_NOACTIVATE
|SWP_NOREDRAW
);
275 /*handle modal message boxes*/
276 if (((lpmb
->dwStyle
& MB_TASKMODAL
) && (lpmb
->hwndOwner
==NULL
)) || (lpmb
->dwStyle
& MB_SYSTEMMODAL
))
277 SetWindowPos(hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
);
283 /**************************************************************************
286 * Dialog procedure for message boxes.
288 static INT_PTR CALLBACK
MSGBOX_DlgProc( HWND hwnd
, UINT message
,
289 WPARAM wParam
, LPARAM lParam
)
296 LPMSGBOXPARAMSW mbp
= (LPMSGBOXPARAMSW
)lParam
;
297 SetWindowContextHelpId(hwnd
, mbp
->dwContextHelpId
);
298 hFont
= MSGBOX_OnInit(hwnd
, mbp
);
299 SetPropA(hwnd
, "WINE_MSGBOX_HFONT", (HANDLE
)hFont
);
300 SetPropA(hwnd
, "WINE_MSGBOX_HELPCALLBACK", (HANDLE
)mbp
->lpfnMsgBoxCallback
);
305 switch (LOWORD(wParam
))
314 hFont
= GetPropA(hwnd
, "WINE_MSGBOX_HFONT");
315 EndDialog(hwnd
, wParam
);
324 MSGBOXCALLBACK callback
= (MSGBOXCALLBACK
)GetPropA(hwnd
, "WINE_MSGBOX_HELPCALLBACK");
327 memcpy(&hi
, (void *)lParam
, sizeof(hi
));
328 hi
.dwContextId
= GetWindowContextHelpId(hwnd
);
333 SendMessageW(GetWindow(hwnd
, GW_OWNER
), WM_HELP
, 0, (LPARAM
)&hi
);
338 /* Ok. Ignore all the other messages */
339 TRACE("Message number 0x%04x is being ignored.\n", message
);
346 /**************************************************************************
347 * MessageBoxA (USER32.@)
349 INT WINAPI
MessageBoxA(HWND hWnd
, LPCSTR text
, LPCSTR title
, UINT type
)
351 return MessageBoxExA(hWnd
, text
, title
, type
, LANG_NEUTRAL
);
355 /**************************************************************************
356 * MessageBoxW (USER32.@)
358 INT WINAPI
MessageBoxW( HWND hwnd
, LPCWSTR text
, LPCWSTR title
, UINT type
)
360 return MessageBoxExW(hwnd
, text
, title
, type
, LANG_NEUTRAL
);
364 /**************************************************************************
365 * MessageBoxExA (USER32.@)
367 INT WINAPI
MessageBoxExA( HWND hWnd
, LPCSTR text
, LPCSTR title
,
368 UINT type
, WORD langid
)
370 MSGBOXPARAMSA msgbox
;
372 msgbox
.cbSize
= sizeof(msgbox
);
373 msgbox
.hwndOwner
= hWnd
;
374 msgbox
.hInstance
= 0;
375 msgbox
.lpszText
= text
;
376 msgbox
.lpszCaption
= title
;
377 msgbox
.dwStyle
= type
;
378 msgbox
.lpszIcon
= NULL
;
379 msgbox
.dwContextHelpId
= 0;
380 msgbox
.lpfnMsgBoxCallback
= NULL
;
381 msgbox
.dwLanguageId
= langid
;
383 return MessageBoxIndirectA(&msgbox
);
386 /**************************************************************************
387 * MessageBoxExW (USER32.@)
389 INT WINAPI
MessageBoxExW( HWND hWnd
, LPCWSTR text
, LPCWSTR title
,
390 UINT type
, WORD langid
)
392 MSGBOXPARAMSW msgbox
;
394 msgbox
.cbSize
= sizeof(msgbox
);
395 msgbox
.hwndOwner
= hWnd
;
396 msgbox
.hInstance
= 0;
397 msgbox
.lpszText
= text
;
398 msgbox
.lpszCaption
= title
;
399 msgbox
.dwStyle
= type
;
400 msgbox
.lpszIcon
= NULL
;
401 msgbox
.dwContextHelpId
= 0;
402 msgbox
.lpfnMsgBoxCallback
= NULL
;
403 msgbox
.dwLanguageId
= langid
;
405 return MessageBoxIndirectW(&msgbox
);
408 /**************************************************************************
409 * MessageBoxIndirectA (USER32.@)
411 INT WINAPI
MessageBoxIndirectA( LPMSGBOXPARAMSA msgbox
)
413 MSGBOXPARAMSW msgboxW
;
414 UNICODE_STRING textW
, captionW
, iconW
;
417 if (HIWORD(msgbox
->lpszText
))
418 RtlCreateUnicodeStringFromAsciiz(&textW
, msgbox
->lpszText
);
420 textW
.Buffer
= (LPWSTR
)msgbox
->lpszText
;
421 if (HIWORD(msgbox
->lpszCaption
))
422 RtlCreateUnicodeStringFromAsciiz(&captionW
, msgbox
->lpszCaption
);
424 captionW
.Buffer
= (LPWSTR
)msgbox
->lpszCaption
;
426 if (msgbox
->dwStyle
& MB_USERICON
)
428 if (HIWORD(msgbox
->lpszIcon
))
429 RtlCreateUnicodeStringFromAsciiz(&iconW
, msgbox
->lpszIcon
);
431 iconW
.Buffer
= (LPWSTR
)msgbox
->lpszIcon
;
436 msgboxW
.cbSize
= sizeof(msgboxW
);
437 msgboxW
.hwndOwner
= msgbox
->hwndOwner
;
438 msgboxW
.hInstance
= msgbox
->hInstance
;
439 msgboxW
.lpszText
= textW
.Buffer
;
440 msgboxW
.lpszCaption
= captionW
.Buffer
;
441 msgboxW
.dwStyle
= msgbox
->dwStyle
;
442 msgboxW
.lpszIcon
= iconW
.Buffer
;
443 msgboxW
.dwContextHelpId
= msgbox
->dwContextHelpId
;
444 msgboxW
.lpfnMsgBoxCallback
= msgbox
->lpfnMsgBoxCallback
;
445 msgboxW
.dwLanguageId
= msgbox
->dwLanguageId
;
447 ret
= MessageBoxIndirectW(&msgboxW
);
449 if (HIWORD(textW
.Buffer
)) RtlFreeUnicodeString(&textW
);
450 if (HIWORD(captionW
.Buffer
)) RtlFreeUnicodeString(&captionW
);
451 if (HIWORD(iconW
.Buffer
)) RtlFreeUnicodeString(&iconW
);
455 /**************************************************************************
456 * MessageBoxIndirectW (USER32.@)
458 INT WINAPI
MessageBoxIndirectW( LPMSGBOXPARAMSW msgbox
)
464 struct ThreadWindows threadWindows
;
465 static const WCHAR msg_box_res_nameW
[] = { 'M','S','G','B','O','X',0 };
467 if (!(hRes
= FindResourceExW(user32_module
, (LPWSTR
)RT_DIALOG
,
468 msg_box_res_nameW
, msgbox
->dwLanguageId
)))
470 if (!(tmplate
= (LPVOID
)LoadResource(user32_module
, hRes
)))
473 if ((msgbox
->dwStyle
& MB_TASKMODAL
) && (msgbox
->hwndOwner
==NULL
))
475 threadWindows
.numHandles
= 0;
476 threadWindows
.numAllocs
= 10;
477 threadWindows
.handles
= HeapAlloc(GetProcessHeap(), 0, 10*sizeof(HWND
));
478 EnumThreadWindows(GetCurrentThreadId(), MSGBOX_EnumProc
, (LPARAM
)&threadWindows
);
481 ret
=DialogBoxIndirectParamW(msgbox
->hInstance
, tmplate
,
482 msgbox
->hwndOwner
, MSGBOX_DlgProc
, (LPARAM
)msgbox
);
484 if ((msgbox
->dwStyle
& MB_TASKMODAL
) && (msgbox
->hwndOwner
==NULL
))
486 for (i
= 0; i
< threadWindows
.numHandles
; i
++)
487 EnableWindow(threadWindows
.handles
[i
], TRUE
);
488 HeapFree(GetProcessHeap(), 0, threadWindows
.handles
);