Fixed mismatches between the Wine headers and the Microsoft headers.
[wine/multimedia.git] / windows / msgbox.c
blob21a0eb5339b8f68a55bf4e1db367cd298be6f25a
1 /*
2 * Message boxes
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
21 #include <string.h>
23 #include "windef.h"
24 #include "wingdi.h"
25 #include "wine/winbase16.h"
26 #include "wine/winuser16.h"
27 #include "winternl.h"
28 #include "dlgs.h"
29 #include "heap.h"
30 #include "user.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dialog);
35 #define MSGBOX_IDICON 1088
36 #define MSGBOX_IDTEXT 100
37 #define IDS_ERROR 2
39 static HFONT MSGBOX_OnInit(HWND hwnd, LPMSGBOXPARAMSW lpmb)
41 HFONT hFont = 0, hPrevFont = 0;
42 RECT rect;
43 HWND hItem;
44 HDC hdc;
45 int i, buttons;
46 int bspace, bw, bh, theight, tleft, wwidth, wheight, bpos;
47 int borheight, borwidth, iheight, ileft, iwidth, twidth, tiheight;
48 LPCWSTR lpszText;
49 WCHAR buf[256];
51 if (TWEAK_WineLook >= WIN95_LOOK) {
52 NONCLIENTMETRICSW nclm;
53 nclm.cbSize = sizeof(nclm);
54 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
55 hFont = CreateFontIndirectW (&nclm.lfMessageFont);
56 /* set button font */
57 for (i=1; i < 8; i++)
58 SendDlgItemMessageW (hwnd, i, WM_SETFONT, (WPARAM)hFont, 0);
59 /* set text font */
60 SendDlgItemMessageW (hwnd, MSGBOX_IDTEXT, WM_SETFONT, (WPARAM)hFont, 0);
62 if (HIWORD(lpmb->lpszCaption)) {
63 SetWindowTextW(hwnd, lpmb->lpszCaption);
64 } else {
65 UINT res_id = LOWORD(lpmb->lpszCaption);
66 if (res_id)
68 if (LoadStringW(lpmb->hInstance, res_id, buf, 256))
69 SetWindowTextW(hwnd, buf);
71 else
73 if (LoadStringW(0, IDS_ERROR, buf, 256))
74 SetWindowTextW(hwnd, buf);
77 if (HIWORD(lpmb->lpszText)) {
78 lpszText = lpmb->lpszText;
79 } else {
80 lpszText = buf;
81 if (!LoadStringW(lpmb->hInstance, LOWORD(lpmb->lpszText), buf, 256))
82 *buf = 0; /* FIXME ?? */
84 SetWindowTextW(GetDlgItem(hwnd, MSGBOX_IDTEXT), lpszText);
86 /* Hide not selected buttons */
87 switch(lpmb->dwStyle & MB_TYPEMASK) {
88 case MB_OK:
89 ShowWindow(GetDlgItem(hwnd, IDCANCEL), SW_HIDE);
90 /* fall through */
91 case MB_OKCANCEL:
92 ShowWindow(GetDlgItem(hwnd, IDABORT), SW_HIDE);
93 ShowWindow(GetDlgItem(hwnd, IDRETRY), SW_HIDE);
94 ShowWindow(GetDlgItem(hwnd, IDIGNORE), SW_HIDE);
95 ShowWindow(GetDlgItem(hwnd, IDYES), SW_HIDE);
96 ShowWindow(GetDlgItem(hwnd, IDNO), SW_HIDE);
97 break;
98 case MB_ABORTRETRYIGNORE:
99 ShowWindow(GetDlgItem(hwnd, IDOK), SW_HIDE);
100 ShowWindow(GetDlgItem(hwnd, IDCANCEL), SW_HIDE);
101 ShowWindow(GetDlgItem(hwnd, IDYES), SW_HIDE);
102 ShowWindow(GetDlgItem(hwnd, IDNO), SW_HIDE);
103 break;
104 case MB_YESNO:
105 ShowWindow(GetDlgItem(hwnd, IDCANCEL), SW_HIDE);
106 /* fall through */
107 case MB_YESNOCANCEL:
108 ShowWindow(GetDlgItem(hwnd, IDOK), SW_HIDE);
109 ShowWindow(GetDlgItem(hwnd, IDABORT), SW_HIDE);
110 ShowWindow(GetDlgItem(hwnd, IDRETRY), SW_HIDE);
111 ShowWindow(GetDlgItem(hwnd, IDIGNORE), SW_HIDE);
112 break;
113 case MB_RETRYCANCEL:
114 ShowWindow(GetDlgItem(hwnd, IDOK), SW_HIDE);
115 ShowWindow(GetDlgItem(hwnd, IDABORT), SW_HIDE);
116 ShowWindow(GetDlgItem(hwnd, IDIGNORE), SW_HIDE);
117 ShowWindow(GetDlgItem(hwnd, IDYES), SW_HIDE);
118 ShowWindow(GetDlgItem(hwnd, IDNO), SW_HIDE);
119 break;
121 /* Set the icon */
122 switch(lpmb->dwStyle & MB_ICONMASK) {
123 case MB_ICONEXCLAMATION:
124 SendDlgItemMessageW(hwnd, stc1, STM_SETICON,
125 (WPARAM)LoadIconW(0, IDI_EXCLAMATIONW), 0);
126 break;
127 case MB_ICONQUESTION:
128 SendDlgItemMessageW(hwnd, stc1, STM_SETICON,
129 (WPARAM)LoadIconW(0, IDI_QUESTIONW), 0);
130 break;
131 case MB_ICONASTERISK:
132 SendDlgItemMessageW(hwnd, stc1, STM_SETICON,
133 (WPARAM)LoadIconW(0, IDI_ASTERISKW), 0);
134 break;
135 case MB_ICONHAND:
136 SendDlgItemMessageW(hwnd, stc1, STM_SETICON,
137 (WPARAM)LoadIconW(0, IDI_HANDW), 0);
138 break;
139 case MB_USERICON:
140 SendDlgItemMessageW(hwnd, stc1, STM_SETICON,
141 (WPARAM)LoadIconW(lpmb->hInstance, lpmb->lpszIcon), 0);
142 break;
143 default:
144 /* By default, Windows 95/98/NT do not associate an icon to message boxes.
145 * So wine should do the same.
147 break;
150 /* Position everything */
151 GetWindowRect(hwnd, &rect);
152 borheight = rect.bottom - rect.top;
153 borwidth = rect.right - rect.left;
154 GetClientRect(hwnd, &rect);
155 borheight -= rect.bottom - rect.top;
156 borwidth -= rect.right - rect.left;
158 /* Get the icon height */
159 GetWindowRect(GetDlgItem(hwnd, MSGBOX_IDICON), &rect);
160 MapWindowPoints(0, hwnd, (LPPOINT)&rect, 2);
161 iheight = rect.bottom - rect.top;
162 ileft = rect.left;
163 iwidth = rect.right - ileft;
165 hdc = GetDC(hwnd);
166 if (hFont)
167 hPrevFont = SelectObject(hdc, hFont);
169 /* Get the number of visible buttons and their size */
170 bh = bw = 1; /* Minimum button sizes */
171 for (buttons = 0, i = 1; i < 8; i++)
173 hItem = GetDlgItem(hwnd, i);
174 if (GetWindowLongW(hItem, GWL_STYLE) & WS_VISIBLE)
176 WCHAR buttonText[1024];
177 int w, h;
178 buttons++;
179 if (GetWindowTextW(hItem, buttonText, 1024))
181 DrawTextW( hdc, buttonText, -1, &rect, DT_LEFT | DT_EXPANDTABS | DT_CALCRECT);
182 h = rect.bottom - rect.top;
183 w = rect.right - rect.left;
184 if (h > bh) bh = h;
185 if (w > bw) bw = w ;
189 bw = max(bw, bh * 2);
190 /* Button white space */
191 bh = bh * 2;
192 bw = bw * 2;
193 bspace = bw/3; /* Space between buttons */
195 /* Get the text size */
196 GetClientRect(GetDlgItem(hwnd, MSGBOX_IDTEXT), &rect);
197 rect.top = rect.left = rect.bottom = 0;
198 DrawTextW( hdc, lpszText, -1, &rect,
199 DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_CALCRECT);
200 /* Min text width corresponds to space for the buttons */
201 tleft = 2 * ileft + iwidth;
202 twidth = max((bw + bspace) * buttons + bspace - tleft, rect.right);
203 theight = rect.bottom;
205 if (hFont)
206 SelectObject(hdc, hPrevFont);
207 ReleaseDC(hItem, hdc);
209 tiheight = 16 + max(iheight, theight);
210 wwidth = tleft + twidth + ileft + borwidth;
211 wheight = 8 + tiheight + bh + borheight;
213 /* Resize the window */
214 SetWindowPos(hwnd, 0, 0, 0, wwidth, wheight,
215 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
217 /* Position the icon */
218 SetWindowPos(GetDlgItem(hwnd, MSGBOX_IDICON), 0, ileft, (tiheight - iheight) / 2, 0, 0,
219 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
221 /* Position the text */
222 SetWindowPos(GetDlgItem(hwnd, MSGBOX_IDTEXT), 0, tleft, (tiheight - theight) / 2, twidth, theight,
223 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
225 /* Position the buttons */
226 bpos = (wwidth - (bw + bspace) * buttons + bspace) / 2;
227 for (buttons = i = 0; i < 7; i++) {
228 /* some arithmetic to get the right order for YesNoCancel windows */
229 hItem = GetDlgItem(hwnd, (i + 5) % 7 + 1);
230 if (GetWindowLongW(hItem, GWL_STYLE) & WS_VISIBLE) {
231 if (buttons++ == ((lpmb->dwStyle & MB_DEFMASK) >> 8)) {
232 SetFocus(hItem);
233 SendMessageW( hItem, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
235 SetWindowPos(hItem, 0, bpos, tiheight, bw, bh,
236 SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREDRAW);
237 bpos += bw + bspace;
241 /* handle modal MessageBoxes */
242 if (lpmb->dwStyle & (MB_TASKMODAL|MB_SYSTEMMODAL))
244 FIXME("%s modal msgbox ! Not modal yet.\n",
245 lpmb->dwStyle & MB_TASKMODAL ? "task" : "system");
246 /* Probably do EnumTaskWindows etc. here for TASKMODAL
247 * and work your way up to the top - I'm lazy (HWND_TOP) */
248 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
249 SWP_NOSIZE | SWP_NOMOVE);
250 if (lpmb->dwStyle & MB_TASKMODAL)
251 /* at least MB_TASKMODAL seems to imply a ShowWindow */
252 ShowWindow(hwnd, SW_SHOW);
254 if (lpmb->dwStyle & MB_APPLMODAL)
255 FIXME("app modal msgbox ! Not modal yet.\n");
257 return hFont;
261 /**************************************************************************
262 * MSGBOX_DlgProc
264 * Dialog procedure for message boxes.
266 static BOOL CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message,
267 WPARAM wParam, LPARAM lParam )
269 HFONT hFont;
271 switch(message) {
272 case WM_INITDIALOG:
274 LPMSGBOXPARAMSW mbp = (LPMSGBOXPARAMSW)lParam;
275 SetWindowContextHelpId(hwnd, mbp->dwContextHelpId);
276 hFont = MSGBOX_OnInit(hwnd, mbp);
277 SetPropA(hwnd, "WINE_MSGBOX_HFONT", (HANDLE)hFont);
278 SetPropA(hwnd, "WINE_MSGBOX_HELPCALLBACK", (HANDLE)mbp->lpfnMsgBoxCallback);
279 break;
282 case WM_COMMAND:
283 switch (wParam)
285 case IDOK:
286 case IDCANCEL:
287 case IDABORT:
288 case IDRETRY:
289 case IDIGNORE:
290 case IDYES:
291 case IDNO:
292 hFont = GetPropA(hwnd, "WINE_MSGBOX_HFONT");
293 EndDialog(hwnd, wParam);
294 if (hFont)
295 DeleteObject(hFont);
296 break;
299 case WM_HELP:
301 MSGBOXCALLBACK callback = (MSGBOXCALLBACK)GetPropA(hwnd, "WINE_MSGBOX_HELPCALLBACK");
302 HELPINFO hi;
304 memcpy(&hi, (void *)lParam, sizeof(hi));
305 hi.dwContextId = GetWindowContextHelpId(hwnd);
307 if (callback)
308 callback(&hi);
309 else
310 SendMessageW(GetWindow(hwnd, GW_OWNER), WM_HELP, 0, (LPARAM)&hi);
311 break;
314 default:
315 /* Ok. Ignore all the other messages */
316 TRACE("Message number 0x%04x is being ignored.\n", message);
317 break;
319 return 0;
323 /**************************************************************************
324 * MessageBoxA (USER32.@)
326 * NOTES
327 * The WARN is here to help debug erroneous MessageBoxes
328 * Use: -debugmsg warn+dialog,+relay
330 INT WINAPI MessageBoxA(HWND hWnd, LPCSTR text, LPCSTR title, UINT type)
332 return MessageBoxExA(hWnd, text, title, type, LANG_NEUTRAL);
336 /**************************************************************************
337 * MessageBoxW (USER32.@)
339 INT WINAPI MessageBoxW( HWND hwnd, LPCWSTR text, LPCWSTR title, UINT type )
341 return MessageBoxExW(hwnd, text, title, type, LANG_NEUTRAL);
345 /**************************************************************************
346 * MessageBoxExA (USER32.@)
348 INT WINAPI MessageBoxExA( HWND hWnd, LPCSTR text, LPCSTR title,
349 UINT type, WORD langid )
351 MSGBOXPARAMSA msgbox;
353 msgbox.cbSize = sizeof(msgbox);
354 msgbox.hwndOwner = hWnd;
355 msgbox.hInstance = 0;
356 msgbox.lpszText = text;
357 msgbox.lpszCaption = title;
358 msgbox.dwStyle = type;
359 msgbox.lpszIcon = NULL;
360 msgbox.dwContextHelpId = 0;
361 msgbox.lpfnMsgBoxCallback = NULL;
362 msgbox.dwLanguageId = langid;
364 return MessageBoxIndirectA(&msgbox);
367 /**************************************************************************
368 * MessageBoxExW (USER32.@)
370 INT WINAPI MessageBoxExW( HWND hWnd, LPCWSTR text, LPCWSTR title,
371 UINT type, WORD langid )
373 MSGBOXPARAMSW msgbox;
375 msgbox.cbSize = sizeof(msgbox);
376 msgbox.hwndOwner = hWnd;
377 msgbox.hInstance = 0;
378 msgbox.lpszText = text;
379 msgbox.lpszCaption = title;
380 msgbox.dwStyle = type;
381 msgbox.lpszIcon = NULL;
382 msgbox.dwContextHelpId = 0;
383 msgbox.lpfnMsgBoxCallback = NULL;
384 msgbox.dwLanguageId = langid;
386 return MessageBoxIndirectW(&msgbox);
389 /**************************************************************************
390 * MessageBoxIndirectA (USER32.@)
392 INT WINAPI MessageBoxIndirectA( LPMSGBOXPARAMSA msgbox )
394 MSGBOXPARAMSW msgboxW;
395 UNICODE_STRING textW, captionW, iconW;
396 int ret;
398 if (HIWORD(msgbox->lpszText))
399 RtlCreateUnicodeStringFromAsciiz(&textW, msgbox->lpszText);
400 else
401 textW.Buffer = (LPWSTR)msgbox->lpszText;
402 if (HIWORD(msgbox->lpszCaption))
403 RtlCreateUnicodeStringFromAsciiz(&captionW, msgbox->lpszCaption);
404 else
405 captionW.Buffer = (LPWSTR)msgbox->lpszCaption;
406 if (HIWORD(msgbox->lpszIcon))
407 RtlCreateUnicodeStringFromAsciiz(&iconW, msgbox->lpszIcon);
408 else
409 captionW.Buffer = (LPWSTR)msgbox->lpszIcon;
411 msgboxW.cbSize = sizeof(msgboxW);
412 msgboxW.hwndOwner = msgbox->hwndOwner;
413 msgboxW.hInstance = msgbox->hInstance;
414 msgboxW.lpszText = textW.Buffer;
415 msgboxW.lpszCaption = captionW.Buffer;
416 msgboxW.dwStyle = msgbox->dwStyle;
417 msgboxW.lpszIcon = iconW.Buffer;
418 msgboxW.dwContextHelpId = msgbox->dwContextHelpId;
419 msgboxW.lpfnMsgBoxCallback = msgbox->lpfnMsgBoxCallback;
420 msgboxW.dwLanguageId = msgbox->dwLanguageId;
422 ret = MessageBoxIndirectW(&msgboxW);
424 if (HIWORD(textW.Buffer)) RtlFreeUnicodeString(&textW);
425 if (HIWORD(captionW.Buffer)) RtlFreeUnicodeString(&captionW);
426 if (HIWORD(iconW.Buffer)) RtlFreeUnicodeString(&iconW);
427 return ret;
430 /**************************************************************************
431 * MessageBoxIndirectW (USER32.@)
433 INT WINAPI MessageBoxIndirectW( LPMSGBOXPARAMSW msgbox )
435 LPVOID tmplate;
436 HRSRC hRes;
437 HMODULE hUser32 = GetModuleHandleA("user32.dll");
438 static const WCHAR msg_box_res_nameW[] = { 'M','S','G','B','O','X',0 };
439 if (!(hRes = FindResourceExW(hUser32, RT_DIALOGW, msg_box_res_nameW, msgbox->dwLanguageId)))
440 return 0;
441 if (!(tmplate = (LPVOID)LoadResource(hUser32, hRes)))
442 return 0;
444 return DialogBoxIndirectParamW(msgbox->hInstance, tmplate, msgbox->hwndOwner,
445 MSGBOX_DlgProc, (LPARAM)msgbox);