4 * Copyright 1995 Bernd Schmidt
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "wine/winbase16.h"
28 #include "wine/winuser16.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(dialog
);
37 #define MSGBOX_IDICON 1088
38 #define MSGBOX_IDTEXT 100
41 static HFONT
MSGBOX_OnInit(HWND hwnd
, LPMSGBOXPARAMSW lpmb
)
43 HFONT hFont
= 0, hPrevFont
= 0;
48 int bspace
, bw
, bh
, theight
, tleft
, wwidth
, wheight
, bpos
;
49 int borheight
, borwidth
, iheight
, ileft
, iwidth
, twidth
, tiheight
;
53 if (TWEAK_WineLook
>= WIN95_LOOK
) {
54 NONCLIENTMETRICSW nclm
;
55 nclm
.cbSize
= sizeof(nclm
);
56 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS
, 0, &nclm
, 0);
57 hFont
= CreateFontIndirectW (&nclm
.lfMessageFont
);
60 SendDlgItemMessageW (hwnd
, i
, WM_SETFONT
, (WPARAM
)hFont
, 0);
62 SendDlgItemMessageW (hwnd
, MSGBOX_IDTEXT
, WM_SETFONT
, (WPARAM
)hFont
, 0);
64 if (HIWORD(lpmb
->lpszCaption
)) {
65 SetWindowTextW(hwnd
, lpmb
->lpszCaption
);
67 UINT res_id
= LOWORD(lpmb
->lpszCaption
);
70 if (LoadStringW(lpmb
->hInstance
, res_id
, buf
, 256))
71 SetWindowTextW(hwnd
, buf
);
75 if (LoadStringW(GetModuleHandleA("user32.dll"), IDS_ERROR
, buf
, 256))
76 SetWindowTextW(hwnd
, buf
);
79 if (HIWORD(lpmb
->lpszText
)) {
80 lpszText
= lpmb
->lpszText
;
83 if (!LoadStringW(lpmb
->hInstance
, LOWORD(lpmb
->lpszText
), buf
, 256))
84 *buf
= 0; /* FIXME ?? */
86 SetWindowTextW(GetDlgItem(hwnd
, MSGBOX_IDTEXT
), lpszText
);
88 /* Hide not selected buttons */
89 switch(lpmb
->dwStyle
& MB_TYPEMASK
) {
91 ShowWindow(GetDlgItem(hwnd
, IDCANCEL
), SW_HIDE
);
94 ShowWindow(GetDlgItem(hwnd
, IDABORT
), SW_HIDE
);
95 ShowWindow(GetDlgItem(hwnd
, IDRETRY
), SW_HIDE
);
96 ShowWindow(GetDlgItem(hwnd
, IDIGNORE
), SW_HIDE
);
97 ShowWindow(GetDlgItem(hwnd
, IDYES
), SW_HIDE
);
98 ShowWindow(GetDlgItem(hwnd
, IDNO
), SW_HIDE
);
100 case MB_ABORTRETRYIGNORE
:
101 ShowWindow(GetDlgItem(hwnd
, IDOK
), SW_HIDE
);
102 ShowWindow(GetDlgItem(hwnd
, IDCANCEL
), SW_HIDE
);
103 ShowWindow(GetDlgItem(hwnd
, IDYES
), SW_HIDE
);
104 ShowWindow(GetDlgItem(hwnd
, IDNO
), SW_HIDE
);
107 ShowWindow(GetDlgItem(hwnd
, IDCANCEL
), SW_HIDE
);
110 ShowWindow(GetDlgItem(hwnd
, IDOK
), SW_HIDE
);
111 ShowWindow(GetDlgItem(hwnd
, IDABORT
), SW_HIDE
);
112 ShowWindow(GetDlgItem(hwnd
, IDRETRY
), SW_HIDE
);
113 ShowWindow(GetDlgItem(hwnd
, IDIGNORE
), SW_HIDE
);
116 ShowWindow(GetDlgItem(hwnd
, IDOK
), SW_HIDE
);
117 ShowWindow(GetDlgItem(hwnd
, IDABORT
), SW_HIDE
);
118 ShowWindow(GetDlgItem(hwnd
, IDIGNORE
), SW_HIDE
);
119 ShowWindow(GetDlgItem(hwnd
, IDYES
), SW_HIDE
);
120 ShowWindow(GetDlgItem(hwnd
, IDNO
), SW_HIDE
);
124 switch(lpmb
->dwStyle
& MB_ICONMASK
) {
125 case MB_ICONEXCLAMATION
:
126 SendDlgItemMessageW(hwnd
, stc1
, STM_SETICON
,
127 (WPARAM
)LoadIconW(0, (LPWSTR
)IDI_EXCLAMATION
), 0);
129 case MB_ICONQUESTION
:
130 SendDlgItemMessageW(hwnd
, stc1
, STM_SETICON
,
131 (WPARAM
)LoadIconW(0, (LPWSTR
)IDI_QUESTION
), 0);
133 case MB_ICONASTERISK
:
134 SendDlgItemMessageW(hwnd
, stc1
, STM_SETICON
,
135 (WPARAM
)LoadIconW(0, (LPWSTR
)IDI_ASTERISK
), 0);
138 SendDlgItemMessageW(hwnd
, stc1
, STM_SETICON
,
139 (WPARAM
)LoadIconW(0, (LPWSTR
)IDI_HAND
), 0);
142 SendDlgItemMessageW(hwnd
, stc1
, STM_SETICON
,
143 (WPARAM
)LoadIconW(lpmb
->hInstance
, lpmb
->lpszIcon
), 0);
146 /* By default, Windows 95/98/NT do not associate an icon to message boxes.
147 * So wine should do the same.
152 /* Position everything */
153 GetWindowRect(hwnd
, &rect
);
154 borheight
= rect
.bottom
- rect
.top
;
155 borwidth
= rect
.right
- rect
.left
;
156 GetClientRect(hwnd
, &rect
);
157 borheight
-= rect
.bottom
- rect
.top
;
158 borwidth
-= rect
.right
- rect
.left
;
160 /* Get the icon height */
161 GetWindowRect(GetDlgItem(hwnd
, MSGBOX_IDICON
), &rect
);
162 MapWindowPoints(0, hwnd
, (LPPOINT
)&rect
, 2);
163 if (!(lpmb
->dwStyle
& MB_ICONMASK
))
165 rect
.bottom
= rect
.top
;
166 rect
.right
= rect
.left
;
168 iheight
= rect
.bottom
- rect
.top
;
170 iwidth
= rect
.right
- ileft
;
174 hPrevFont
= SelectObject(hdc
, hFont
);
176 /* Get the number of visible buttons and their size */
177 bh
= bw
= 1; /* Minimum button sizes */
178 for (buttons
= 0, i
= 1; i
< 8; i
++)
180 hItem
= GetDlgItem(hwnd
, i
);
181 if (GetWindowLongW(hItem
, GWL_STYLE
) & WS_VISIBLE
)
183 WCHAR buttonText
[1024];
186 if (GetWindowTextW(hItem
, buttonText
, 1024))
188 DrawTextW( hdc
, buttonText
, -1, &rect
, DT_LEFT
| DT_EXPANDTABS
| DT_CALCRECT
);
189 h
= rect
.bottom
- rect
.top
;
190 w
= rect
.right
- rect
.left
;
196 bw
= max(bw
, bh
* 2);
197 /* Button white space */
200 bspace
= bw
/3; /* Space between buttons */
202 /* Get the text size */
203 GetClientRect(GetDlgItem(hwnd
, MSGBOX_IDTEXT
), &rect
);
204 rect
.top
= rect
.left
= rect
.bottom
= 0;
205 DrawTextW( hdc
, lpszText
, -1, &rect
,
206 DT_LEFT
| DT_EXPANDTABS
| DT_WORDBREAK
| DT_CALCRECT
);
207 /* Min text width corresponds to space for the buttons */
209 if (iwidth
) tleft
+= ileft
+ iwidth
;
210 twidth
= max((bw
+ bspace
) * buttons
+ bspace
- tleft
, rect
.right
);
211 theight
= rect
.bottom
;
214 SelectObject(hdc
, hPrevFont
);
215 ReleaseDC(hItem
, hdc
);
217 tiheight
= 16 + max(iheight
, theight
);
218 wwidth
= tleft
+ twidth
+ ileft
+ borwidth
;
219 wheight
= 8 + tiheight
+ bh
+ borheight
;
221 /* Resize the window */
222 SetWindowPos(hwnd
, 0, 0, 0, wwidth
, wheight
,
223 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
225 /* Position the icon */
226 SetWindowPos(GetDlgItem(hwnd
, MSGBOX_IDICON
), 0, ileft
, (tiheight
- iheight
) / 2, 0, 0,
227 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
229 /* Position the text */
230 SetWindowPos(GetDlgItem(hwnd
, MSGBOX_IDTEXT
), 0, tleft
, (tiheight
- theight
) / 2, twidth
, theight
,
231 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
233 /* Position the buttons */
234 bpos
= (wwidth
- (bw
+ bspace
) * buttons
+ bspace
) / 2;
235 for (buttons
= i
= 0; i
< 7; i
++) {
236 /* some arithmetic to get the right order for YesNoCancel windows */
237 hItem
= GetDlgItem(hwnd
, (i
+ 5) % 7 + 1);
238 if (GetWindowLongW(hItem
, GWL_STYLE
) & WS_VISIBLE
) {
239 if (buttons
++ == ((lpmb
->dwStyle
& MB_DEFMASK
) >> 8)) {
241 SendMessageW( hItem
, BM_SETSTYLE
, BS_DEFPUSHBUTTON
, TRUE
);
243 SetWindowPos(hItem
, 0, bpos
, tiheight
, bw
, bh
,
244 SWP_NOZORDER
|SWP_NOACTIVATE
|SWP_NOREDRAW
);
249 /* handle modal MessageBoxes */
250 if (lpmb
->dwStyle
& (MB_TASKMODAL
|MB_SYSTEMMODAL
))
252 FIXME("%s modal msgbox ! Not modal yet.\n",
253 lpmb
->dwStyle
& MB_TASKMODAL
? "task" : "system");
254 /* Probably do EnumTaskWindows etc. here for TASKMODAL
255 * and work your way up to the top - I'm lazy (HWND_TOP) */
256 SetWindowPos(hwnd
, HWND_TOP
, 0, 0, 0, 0,
257 SWP_NOSIZE
| SWP_NOMOVE
);
258 if (lpmb
->dwStyle
& MB_TASKMODAL
)
259 /* at least MB_TASKMODAL seems to imply a ShowWindow */
260 ShowWindow(hwnd
, SW_SHOW
);
262 if (lpmb
->dwStyle
& MB_APPLMODAL
)
263 FIXME("app modal msgbox ! Not modal yet.\n");
269 /**************************************************************************
272 * Dialog procedure for message boxes.
274 static INT_PTR CALLBACK
MSGBOX_DlgProc( HWND hwnd
, UINT message
,
275 WPARAM wParam
, LPARAM lParam
)
282 LPMSGBOXPARAMSW mbp
= (LPMSGBOXPARAMSW
)lParam
;
283 SetWindowContextHelpId(hwnd
, mbp
->dwContextHelpId
);
284 hFont
= MSGBOX_OnInit(hwnd
, mbp
);
285 SetPropA(hwnd
, "WINE_MSGBOX_HFONT", (HANDLE
)hFont
);
286 SetPropA(hwnd
, "WINE_MSGBOX_HELPCALLBACK", (HANDLE
)mbp
->lpfnMsgBoxCallback
);
291 switch (LOWORD(wParam
))
300 hFont
= GetPropA(hwnd
, "WINE_MSGBOX_HFONT");
301 EndDialog(hwnd
, wParam
);
310 MSGBOXCALLBACK callback
= (MSGBOXCALLBACK
)GetPropA(hwnd
, "WINE_MSGBOX_HELPCALLBACK");
313 memcpy(&hi
, (void *)lParam
, sizeof(hi
));
314 hi
.dwContextId
= GetWindowContextHelpId(hwnd
);
319 SendMessageW(GetWindow(hwnd
, GW_OWNER
), WM_HELP
, 0, (LPARAM
)&hi
);
324 /* Ok. Ignore all the other messages */
325 TRACE("Message number 0x%04x is being ignored.\n", message
);
332 /**************************************************************************
333 * MessageBoxA (USER32.@)
336 * The WARN is here to help debug erroneous MessageBoxes
337 * Use: -debugmsg warn+dialog,+relay
339 INT WINAPI
MessageBoxA(HWND hWnd
, LPCSTR text
, LPCSTR title
, UINT type
)
341 return MessageBoxExA(hWnd
, text
, title
, type
, LANG_NEUTRAL
);
345 /**************************************************************************
346 * MessageBoxW (USER32.@)
348 INT WINAPI
MessageBoxW( HWND hwnd
, LPCWSTR text
, LPCWSTR title
, UINT type
)
350 return MessageBoxExW(hwnd
, text
, title
, type
, LANG_NEUTRAL
);
354 /**************************************************************************
355 * MessageBoxExA (USER32.@)
357 INT WINAPI
MessageBoxExA( HWND hWnd
, LPCSTR text
, LPCSTR title
,
358 UINT type
, WORD langid
)
360 MSGBOXPARAMSA msgbox
;
362 msgbox
.cbSize
= sizeof(msgbox
);
363 msgbox
.hwndOwner
= hWnd
;
364 msgbox
.hInstance
= 0;
365 msgbox
.lpszText
= text
;
366 msgbox
.lpszCaption
= title
;
367 msgbox
.dwStyle
= type
;
368 msgbox
.lpszIcon
= NULL
;
369 msgbox
.dwContextHelpId
= 0;
370 msgbox
.lpfnMsgBoxCallback
= NULL
;
371 msgbox
.dwLanguageId
= langid
;
373 return MessageBoxIndirectA(&msgbox
);
376 /**************************************************************************
377 * MessageBoxExW (USER32.@)
379 INT WINAPI
MessageBoxExW( HWND hWnd
, LPCWSTR text
, LPCWSTR title
,
380 UINT type
, WORD langid
)
382 MSGBOXPARAMSW msgbox
;
384 msgbox
.cbSize
= sizeof(msgbox
);
385 msgbox
.hwndOwner
= hWnd
;
386 msgbox
.hInstance
= 0;
387 msgbox
.lpszText
= text
;
388 msgbox
.lpszCaption
= title
;
389 msgbox
.dwStyle
= type
;
390 msgbox
.lpszIcon
= NULL
;
391 msgbox
.dwContextHelpId
= 0;
392 msgbox
.lpfnMsgBoxCallback
= NULL
;
393 msgbox
.dwLanguageId
= langid
;
395 return MessageBoxIndirectW(&msgbox
);
398 /**************************************************************************
399 * MessageBoxIndirectA (USER32.@)
401 INT WINAPI
MessageBoxIndirectA( LPMSGBOXPARAMSA msgbox
)
403 MSGBOXPARAMSW msgboxW
;
404 UNICODE_STRING textW
, captionW
, iconW
;
407 if (HIWORD(msgbox
->lpszText
))
408 RtlCreateUnicodeStringFromAsciiz(&textW
, msgbox
->lpszText
);
410 textW
.Buffer
= (LPWSTR
)msgbox
->lpszText
;
411 if (HIWORD(msgbox
->lpszCaption
))
412 RtlCreateUnicodeStringFromAsciiz(&captionW
, msgbox
->lpszCaption
);
414 captionW
.Buffer
= (LPWSTR
)msgbox
->lpszCaption
;
415 if (HIWORD(msgbox
->lpszIcon
))
416 RtlCreateUnicodeStringFromAsciiz(&iconW
, msgbox
->lpszIcon
);
418 iconW
.Buffer
= (LPWSTR
)msgbox
->lpszIcon
;
420 msgboxW
.cbSize
= sizeof(msgboxW
);
421 msgboxW
.hwndOwner
= msgbox
->hwndOwner
;
422 msgboxW
.hInstance
= msgbox
->hInstance
;
423 msgboxW
.lpszText
= textW
.Buffer
;
424 msgboxW
.lpszCaption
= captionW
.Buffer
;
425 msgboxW
.dwStyle
= msgbox
->dwStyle
;
426 msgboxW
.lpszIcon
= iconW
.Buffer
;
427 msgboxW
.dwContextHelpId
= msgbox
->dwContextHelpId
;
428 msgboxW
.lpfnMsgBoxCallback
= msgbox
->lpfnMsgBoxCallback
;
429 msgboxW
.dwLanguageId
= msgbox
->dwLanguageId
;
431 ret
= MessageBoxIndirectW(&msgboxW
);
433 if (HIWORD(textW
.Buffer
)) RtlFreeUnicodeString(&textW
);
434 if (HIWORD(captionW
.Buffer
)) RtlFreeUnicodeString(&captionW
);
435 if (HIWORD(iconW
.Buffer
)) RtlFreeUnicodeString(&iconW
);
439 /**************************************************************************
440 * MessageBoxIndirectW (USER32.@)
442 INT WINAPI
MessageBoxIndirectW( LPMSGBOXPARAMSW msgbox
)
447 static const WCHAR user32_res_nameW
[] = { 'u','s','e','r','3','2','.','d','l','l',0 };
448 static const WCHAR msg_box_res_nameW
[] = { 'M','S','G','B','O','X',0 };
450 hUser32
= GetModuleHandleW(user32_res_nameW
);
451 if (!(hRes
= FindResourceExW(hUser32
, (LPWSTR
)RT_DIALOG
, msg_box_res_nameW
, msgbox
->dwLanguageId
)))
453 if (!(tmplate
= (LPVOID
)LoadResource(hUser32
, hRes
)))
456 return DialogBoxIndirectParamW(msgbox
->hInstance
, tmplate
, msgbox
->hwndOwner
,
457 MSGBOX_DlgProc
, (LPARAM
)msgbox
);