Fixed occasional loss of SendMessage() return value.
[wine] / windows / msgbox.c
1 /*
2  * Message boxes
3  *
4  * Copyright 1995 Bernd Schmidt
5  */
6
7 #include <string.h>
8 #include "wine/winuser16.h"
9 #include "dlgs.h"
10 #include "heap.h"
11 #include "module.h"
12 #include "win.h"
13 #include "resource.h"
14 #include "task.h"
15 #include "debug.h"
16 #include "debugstr.h"
17 #include "tweak.h"
18
19 /**************************************************************************
20  *           MSGBOX_DlgProc
21  *
22  * Dialog procedure for message boxes.
23  */
24 static LRESULT CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message,
25                                         WPARAM wParam, LPARAM lParam )
26 {
27   static HFONT hFont = 0;
28   LPMSGBOXPARAMSA lpmb;
29
30   RECT rect, textrect;
31   HWND hItem;
32   HDC hdc;
33   LRESULT lRet;
34   int i, buttons, bwidth, bheight, theight, wwidth, bpos;
35   int borheight, iheight, tiheight;
36   
37   switch(message) {
38    case WM_INITDIALOG:
39     lpmb = (LPMSGBOXPARAMSA)lParam;
40     if (TWEAK_WineLook >= WIN95_LOOK) {
41         NONCLIENTMETRICSA nclm;
42         INT i;
43         nclm.cbSize = sizeof(NONCLIENTMETRICSA);
44         SystemParametersInfoA (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
45         hFont = CreateFontIndirectA (&nclm.lfMessageFont);
46         /* set button font */
47         for (i=1; i < 8; i++)
48             SendDlgItemMessageA (hwnd, i, WM_SETFONT, (WPARAM)hFont, 0);
49         /* set text font */
50         SendDlgItemMessageA (hwnd, 100, WM_SETFONT, (WPARAM)hFont, 0);
51     }
52     if (lpmb->lpszCaption) SetWindowTextA(hwnd, lpmb->lpszCaption);
53     SetWindowTextA(GetDlgItem(hwnd, 100), lpmb->lpszText);
54     /* Hide not selected buttons */
55     switch(lpmb->dwStyle & MB_TYPEMASK) {
56      case MB_OK:
57       ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE);
58       /* fall through */
59      case MB_OKCANCEL:
60       ShowWindow(GetDlgItem(hwnd, 3), SW_HIDE);
61       ShowWindow(GetDlgItem(hwnd, 4), SW_HIDE);
62       ShowWindow(GetDlgItem(hwnd, 5), SW_HIDE);
63       ShowWindow(GetDlgItem(hwnd, 6), SW_HIDE);
64       ShowWindow(GetDlgItem(hwnd, 7), SW_HIDE);
65       break;
66      case MB_ABORTRETRYIGNORE:
67       ShowWindow(GetDlgItem(hwnd, 1), SW_HIDE);
68       ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE);
69       ShowWindow(GetDlgItem(hwnd, 6), SW_HIDE);
70       ShowWindow(GetDlgItem(hwnd, 7), SW_HIDE);
71       break;
72      case MB_YESNO:
73       ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE);
74       /* fall through */
75      case MB_YESNOCANCEL:
76       ShowWindow(GetDlgItem(hwnd, 1), SW_HIDE);
77       ShowWindow(GetDlgItem(hwnd, 3), SW_HIDE);
78       ShowWindow(GetDlgItem(hwnd, 4), SW_HIDE);
79       ShowWindow(GetDlgItem(hwnd, 5), SW_HIDE);
80       break;
81     }
82     /* Set the icon */
83     switch(lpmb->dwStyle & MB_ICONMASK) {
84      case MB_ICONEXCLAMATION:
85       SendDlgItemMessage16(hwnd, stc1, STM_SETICON16,
86                            (WPARAM16)LoadIcon16(0, IDI_EXCLAMATION16), 0);
87       break;
88      case MB_ICONQUESTION:
89       SendDlgItemMessage16(hwnd, stc1, STM_SETICON16,
90                            (WPARAM16)LoadIcon16(0, IDI_QUESTION16), 0);
91       break;
92      case MB_ICONASTERISK:
93       SendDlgItemMessage16(hwnd, stc1, STM_SETICON16,
94                            (WPARAM16)LoadIcon16(0, IDI_ASTERISK16), 0);
95       break;
96      case MB_ICONHAND:
97      default:
98       SendDlgItemMessage16(hwnd, stc1, STM_SETICON16,
99                            (WPARAM16)LoadIcon16(0, IDI_HAND16), 0);
100       break;
101     }
102     
103     /* Position everything */
104     GetWindowRect(hwnd, &rect);
105     borheight = rect.bottom - rect.top;
106     wwidth = rect.right - rect.left;
107     GetClientRect(hwnd, &rect);
108     borheight -= rect.bottom - rect.top;
109
110     /* Get the icon height */
111     GetWindowRect(GetDlgItem(hwnd, 1088), &rect);
112     iheight = rect.bottom - rect.top;
113     
114     /* Get the number of visible buttons and their width */
115     GetWindowRect(GetDlgItem(hwnd, 2), &rect);
116     bheight = rect.bottom - rect.top;
117     bwidth = rect.left;
118     GetWindowRect(GetDlgItem(hwnd, 1), &rect);
119     bwidth -= rect.left;
120     for (buttons = 0, i = 1; i < 8; i++)
121     {
122       hItem = GetDlgItem(hwnd, i);
123       if (GetWindowLongA(hItem, GWL_STYLE) & WS_VISIBLE) buttons++;
124     }
125     
126     /* Get the text size */
127     hItem = GetDlgItem(hwnd, 100);
128     GetWindowRect(hItem, &textrect);
129     MapWindowPoints(0, hwnd, (LPPOINT)&textrect, 2);
130     
131     GetClientRect(hItem, &rect);
132     hdc = GetDC(hItem);
133     lRet = DrawTextA( hdc, lpmb->lpszText, -1, &rect,
134                         DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_CALCRECT);
135     theight = rect.bottom  - rect.top;
136     tiheight = 16 + MAX(iheight, theight);
137     ReleaseDC(hItem, hdc);
138     
139     /* Position the text */
140     SetWindowPos(hItem, 0, textrect.left, (tiheight - theight) / 2, 
141                    rect.right - rect.left, theight,
142                    SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
143     
144     /* Position the icon */
145     hItem = GetDlgItem(hwnd, 1088);
146     GetWindowRect(hItem, &rect);
147     MapWindowPoints(0, hwnd, (LPPOINT)&rect, 2);
148     SetWindowPos(hItem, 0, rect.left, (tiheight - iheight) / 2, 0, 0,
149                    SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
150     
151     /* Resize the window */
152     SetWindowPos(hwnd, 0, 0, 0, wwidth, 8 + tiheight + bheight + borheight,
153                    SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
154     
155     /* Position the buttons */
156     bpos = (wwidth - bwidth * buttons) / 2;
157     GetWindowRect(GetDlgItem(hwnd, 1), &rect);
158     for (buttons = i = 0; i < 7; i++) {
159       /* some arithmetic to get the right order for YesNoCancel windows */
160       hItem = GetDlgItem(hwnd, (i + 5) % 7 + 1);
161       if (GetWindowLongA(hItem, GWL_STYLE) & WS_VISIBLE) {
162         if (buttons++ == ((lpmb->dwStyle & MB_DEFMASK) >> 8)) {
163           SetFocus(hItem);
164           SendMessageA( hItem, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
165         }
166         SetWindowPos(hItem, 0, bpos, tiheight, 0, 0,
167                        SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREDRAW);
168         bpos += bwidth;
169       }
170     }
171     return 0;
172     break;
173     
174    case WM_COMMAND:
175     switch (wParam)
176     {
177      case IDOK:
178      case IDCANCEL:
179      case IDABORT:
180      case IDRETRY:
181      case IDIGNORE:
182      case IDYES:
183      case IDNO:
184       if ((TWEAK_WineLook > WIN31_LOOK) && hFont)
185         DeleteObject (hFont);
186       EndDialog(hwnd, wParam);
187       break;
188     }
189
190    default:
191      /* Ok. Ignore all the other messages */
192      TRACE (dialog, "Message number %i is being ignored.\n", message);
193     break;
194   }
195   return 0;
196 }
197
198
199 /**************************************************************************
200  *           MessageBox16   (USER.1)
201  */
202 INT16 WINAPI MessageBox16( HWND16 hwnd, LPCSTR text, LPCSTR title, UINT16 type)
203 {
204     WARN(dialog,"Messagebox\n");
205     return MessageBoxA( hwnd, text, title, type );
206 }
207
208
209 /**************************************************************************
210  *           MessageBox32A   (USER32.391)
211  *
212  * NOTES
213  *   The WARN is here to help debug erroneous MessageBoxes
214  *   Use: -debugmsg warn+dialog,+relay
215  */
216 INT WINAPI MessageBoxA(HWND hWnd, LPCSTR text, LPCSTR title, UINT type)
217 {
218     MSGBOXPARAMSA mbox;
219     WARN(dialog,"Messagebox\n");
220     if (!text) text="<WINE-NULL>";
221     if (!title)
222       title="Error";
223     mbox.lpszCaption = title;
224     mbox.lpszText  = text;
225     mbox.dwStyle  = type;
226     return DialogBoxIndirectParamA( WIN_GetWindowInstance(hWnd),
227                                       SYSRES_GetResPtr( SYSRES_DIALOG_MSGBOX ),
228                                       hWnd, (DLGPROC)MSGBOX_DlgProc, (LPARAM)&mbox );
229 }
230
231
232 /**************************************************************************
233  *           MessageBox32W   (USER32.396)
234  */
235 INT WINAPI MessageBoxW( HWND hwnd, LPCWSTR text, LPCWSTR title,
236                             UINT type )
237 {
238     LPSTR titleA = HEAP_strdupWtoA( GetProcessHeap(), 0, title );
239     LPSTR textA  = HEAP_strdupWtoA( GetProcessHeap(), 0, text );
240     INT ret;
241     
242     WARN(dialog,"Messagebox\n");
243
244     ret = MessageBoxA( hwnd, textA, titleA, type );
245     HeapFree( GetProcessHeap(), 0, titleA );
246     HeapFree( GetProcessHeap(), 0, textA );
247     return ret;
248 }
249
250
251 /**************************************************************************
252  *           MessageBoxEx32A   (USER32.392)
253  */
254 INT WINAPI MessageBoxExA( HWND hWnd, LPCSTR text, LPCSTR title,
255                               UINT type, WORD langid )
256 {
257     WARN(dialog,"Messagebox\n");
258     /* ignore language id for now */
259     return MessageBoxA(hWnd,text,title,type);
260 }
261
262 /**************************************************************************
263  *           MessageBoxEx32W   (USER32.393)
264  */
265 INT WINAPI MessageBoxExW( HWND hWnd, LPCWSTR text, LPCWSTR title,
266                               UINT type, WORD langid )
267 {
268     WARN(dialog,"Messagebox\n");
269     /* ignore language id for now */
270     return MessageBoxW(hWnd,text,title,type);
271 }
272
273 /**************************************************************************
274  *           MessageBoxIndirect16   (USER.827)
275  */
276 INT16 WINAPI MessageBoxIndirect16( LPMSGBOXPARAMS16 msgbox )
277 {
278     MSGBOXPARAMSA msgbox32;
279     WARN(dialog,"Messagebox\n");    
280     
281     msgbox32.cbSize             = msgbox->cbSize;
282     msgbox32.hwndOwner          = msgbox->hwndOwner;
283     msgbox32.hInstance          = msgbox->hInstance;
284     msgbox32.lpszText           = PTR_SEG_TO_LIN(msgbox->lpszText);
285     msgbox32.lpszCaption        = PTR_SEG_TO_LIN(msgbox->lpszCaption);
286     msgbox32.dwStyle            = msgbox->dwStyle;
287     msgbox32.lpszIcon           = PTR_SEG_TO_LIN(msgbox->lpszIcon);
288     msgbox32.dwContextHelpId    = msgbox->dwContextHelpId;
289     msgbox32.lpfnMsgBoxCallback = msgbox->lpfnMsgBoxCallback;
290     msgbox32.dwLanguageId       = msgbox->dwLanguageId;
291
292     return DialogBoxIndirectParamA( msgbox32.hInstance,
293                                       SYSRES_GetResPtr( SYSRES_DIALOG_MSGBOX ),
294                                       msgbox32.hwndOwner, (DLGPROC)MSGBOX_DlgProc,
295                                       (LPARAM)&msgbox32 );
296 }
297
298 /**************************************************************************
299  *           MessageBoxIndirect32A   (USER32.394)
300  */
301 INT WINAPI MessageBoxIndirectA( LPMSGBOXPARAMSA msgbox )
302 {
303     WARN(dialog,"Messagebox\n");
304     return DialogBoxIndirectParamA( msgbox->hInstance,
305                                       SYSRES_GetResPtr( SYSRES_DIALOG_MSGBOX ),
306                                       msgbox->hwndOwner, (DLGPROC)MSGBOX_DlgProc,
307                                       (LPARAM)msgbox );
308 }
309
310 /**************************************************************************
311  *           MessageBoxIndirect32W   (USER32.395)
312  */
313 INT WINAPI MessageBoxIndirectW( LPMSGBOXPARAMSW msgbox )
314 {
315     MSGBOXPARAMSA       msgboxa;
316     WARN(dialog,"Messagebox\n");
317
318     memcpy(&msgboxa,msgbox,sizeof(msgboxa));
319     if (msgbox->lpszCaption)    
320       lstrcpyWtoA((LPSTR)msgboxa.lpszCaption,msgbox->lpszCaption);
321     if (msgbox->lpszText)       
322       lstrcpyWtoA((LPSTR)msgboxa.lpszText,msgbox->lpszText);
323
324     return MessageBoxIndirectA(&msgboxa);
325 }
326
327
328 /**************************************************************************
329  *           FatalAppExit16   (KERNEL.137)
330  */
331 void WINAPI FatalAppExit16( UINT16 action, LPCSTR str )
332 {
333     WARN(dialog,"AppExit\n");
334     FatalAppExitA( action, str );
335 }
336
337
338 /**************************************************************************
339  *           FatalAppExit32A   (KERNEL32.108)
340  */
341 void WINAPI FatalAppExitA( UINT action, LPCSTR str )
342 {
343     WARN(dialog,"AppExit\n");
344     MessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
345     ExitProcess(0);
346 }
347
348
349 /**************************************************************************
350  *           FatalAppExit32W   (KERNEL32.109)
351  */
352 void WINAPI FatalAppExitW( UINT action, LPCWSTR str )
353 {
354     WARN(dialog,"AppExit\n");
355     MessageBoxW( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
356     ExitProcess(0);
357 }
358
359