winemac: Implement the Mac "Window" menu.
[wine] / dlls / user32 / msgbox.c
1 /*
2  * Message boxes
3  *
4  * Copyright 1995 Bernd Schmidt
5  * Copyright 2004 Ivan Leo Puoti, Juan Lang
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include <stdarg.h>
23 #include <string.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winternl.h"
29 #include "dlgs.h"
30 #include "user_private.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(dialog);
34 WINE_DECLARE_DEBUG_CHANNEL(msgbox);
35
36 #define MSGBOX_IDICON stc1
37 #define MSGBOX_IDTEXT 100
38 #define IDS_ERROR     2
39
40 struct ThreadWindows
41 {
42     UINT numHandles;
43     UINT numAllocs;
44     HWND *handles;
45 };
46
47 static BOOL CALLBACK MSGBOX_EnumProc(HWND hwnd, LPARAM lParam)
48 {
49     struct ThreadWindows *threadWindows = (struct ThreadWindows *)lParam;
50
51     if (!EnableWindow(hwnd, FALSE))
52     {
53         if(threadWindows->numHandles >= threadWindows->numAllocs)
54         {
55             threadWindows->handles = HeapReAlloc(GetProcessHeap(), 0, threadWindows->handles,
56                                                  (threadWindows->numAllocs*2)*sizeof(HWND));
57             threadWindows->numAllocs *= 2;
58         }
59         threadWindows->handles[threadWindows->numHandles++]=hwnd;
60     }
61    return TRUE;
62 }
63
64 static HFONT MSGBOX_OnInit(HWND hwnd, LPMSGBOXPARAMSW lpmb)
65 {
66     HFONT hFont = 0, hPrevFont = 0;
67     RECT rect;
68     HWND hItem;
69     HDC hdc;
70     int i, buttons;
71     int bspace, bw, bh, theight, tleft, wwidth, wheight, wleft, wtop, bpos;
72     int borheight, borwidth, iheight, ileft, iwidth, twidth, tiheight;
73     NONCLIENTMETRICSW nclm;
74     HMONITOR monitor = 0;
75     MONITORINFO mon_info;
76     LPCWSTR lpszText;
77     WCHAR *buffer = NULL;
78     const WCHAR *ptr;
79
80     /* Index the order the buttons need to appear to an ID* constant */
81     static const int buttonOrder[10] = { IDYES, IDNO, IDOK, IDABORT, IDRETRY,
82                                          IDCANCEL, IDIGNORE, IDTRYAGAIN,
83                                          IDCONTINUE, IDHELP };
84
85     nclm.cbSize = sizeof(nclm);
86     SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
87     hFont = CreateFontIndirectW (&nclm.lfMessageFont);
88     /* set button font */
89     for (i=1; i < 12; i++)
90         /* No button 8 (Close) */
91         if (i != 8) {
92             SendDlgItemMessageW (hwnd, i, WM_SETFONT, (WPARAM)hFont, 0);
93         }
94     /* set text font */
95     SendDlgItemMessageW (hwnd, MSGBOX_IDTEXT, WM_SETFONT, (WPARAM)hFont, 0);
96
97     if (!IS_INTRESOURCE(lpmb->lpszCaption)) {
98        SetWindowTextW(hwnd, lpmb->lpszCaption);
99     } else {
100         UINT len = LoadStringW( lpmb->hInstance, LOWORD(lpmb->lpszCaption), (LPWSTR)&ptr, 0 );
101         if (!len) len = LoadStringW( user32_module, IDS_ERROR, (LPWSTR)&ptr, 0 );
102         buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
103         if (buffer)
104         {
105             memcpy( buffer, ptr, len * sizeof(WCHAR) );
106             buffer[len] = 0;
107             SetWindowTextW( hwnd, buffer );
108             HeapFree( GetProcessHeap(), 0, buffer );
109             buffer = NULL;
110         }
111     }
112     if (IS_INTRESOURCE(lpmb->lpszText)) {
113         UINT len = LoadStringW( lpmb->hInstance, LOWORD(lpmb->lpszText), (LPWSTR)&ptr, 0 );
114         lpszText = buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
115         if (buffer)
116         {
117             memcpy( buffer, ptr, len * sizeof(WCHAR) );
118             buffer[len] = 0;
119         }
120     } else {
121        lpszText = lpmb->lpszText;
122     }
123
124     TRACE_(msgbox)("%s\n", debugstr_w(lpszText));
125     SetWindowTextW(GetDlgItem(hwnd, MSGBOX_IDTEXT), lpszText);
126
127     /* Remove not selected buttons */
128     switch(lpmb->dwStyle & MB_TYPEMASK) {
129     case MB_OK:
130         DestroyWindow(GetDlgItem(hwnd, IDCANCEL));
131         /* fall through */
132     case MB_OKCANCEL:
133         DestroyWindow(GetDlgItem(hwnd, IDABORT));
134         DestroyWindow(GetDlgItem(hwnd, IDRETRY));
135         DestroyWindow(GetDlgItem(hwnd, IDIGNORE));
136         DestroyWindow(GetDlgItem(hwnd, IDYES));
137         DestroyWindow(GetDlgItem(hwnd, IDNO));
138         DestroyWindow(GetDlgItem(hwnd, IDTRYAGAIN));
139         DestroyWindow(GetDlgItem(hwnd, IDCONTINUE));
140         break;
141     case MB_ABORTRETRYIGNORE:
142         DestroyWindow(GetDlgItem(hwnd, IDOK));
143         DestroyWindow(GetDlgItem(hwnd, IDCANCEL));
144         DestroyWindow(GetDlgItem(hwnd, IDYES));
145         DestroyWindow(GetDlgItem(hwnd, IDNO));
146         DestroyWindow(GetDlgItem(hwnd, IDCONTINUE));
147         DestroyWindow(GetDlgItem(hwnd, IDTRYAGAIN));
148         break;
149     case MB_YESNO:
150         DestroyWindow(GetDlgItem(hwnd, IDCANCEL));
151         /* fall through */
152     case MB_YESNOCANCEL:
153         DestroyWindow(GetDlgItem(hwnd, IDOK));
154         DestroyWindow(GetDlgItem(hwnd, IDABORT));
155         DestroyWindow(GetDlgItem(hwnd, IDRETRY));
156         DestroyWindow(GetDlgItem(hwnd, IDIGNORE));
157         DestroyWindow(GetDlgItem(hwnd, IDCONTINUE));
158         DestroyWindow(GetDlgItem(hwnd, IDTRYAGAIN));
159         break;
160     case MB_RETRYCANCEL:
161         DestroyWindow(GetDlgItem(hwnd, IDOK));
162         DestroyWindow(GetDlgItem(hwnd, IDABORT));
163         DestroyWindow(GetDlgItem(hwnd, IDIGNORE));
164         DestroyWindow(GetDlgItem(hwnd, IDYES));
165         DestroyWindow(GetDlgItem(hwnd, IDNO));
166         DestroyWindow(GetDlgItem(hwnd, IDCONTINUE));
167         DestroyWindow(GetDlgItem(hwnd, IDTRYAGAIN));
168         break;
169     case MB_CANCELTRYCONTINUE:
170         DestroyWindow(GetDlgItem(hwnd, IDOK));
171         DestroyWindow(GetDlgItem(hwnd, IDABORT));
172         DestroyWindow(GetDlgItem(hwnd, IDIGNORE));
173         DestroyWindow(GetDlgItem(hwnd, IDYES));
174         DestroyWindow(GetDlgItem(hwnd, IDNO));
175         DestroyWindow(GetDlgItem(hwnd, IDRETRY));
176     }
177     /* Set the icon */
178     switch(lpmb->dwStyle & MB_ICONMASK) {
179     case MB_ICONEXCLAMATION:
180         SendDlgItemMessageW(hwnd, MSGBOX_IDICON, STM_SETICON,
181                             (WPARAM)LoadIconW(0, (LPWSTR)IDI_EXCLAMATION), 0);
182         break;
183     case MB_ICONQUESTION:
184         SendDlgItemMessageW(hwnd, MSGBOX_IDICON, STM_SETICON,
185                             (WPARAM)LoadIconW(0, (LPWSTR)IDI_QUESTION), 0);
186         break;
187     case MB_ICONASTERISK:
188         SendDlgItemMessageW(hwnd, MSGBOX_IDICON, STM_SETICON,
189                             (WPARAM)LoadIconW(0, (LPWSTR)IDI_ASTERISK), 0);
190         break;
191     case MB_ICONHAND:
192       SendDlgItemMessageW(hwnd, MSGBOX_IDICON, STM_SETICON,
193                             (WPARAM)LoadIconW(0, (LPWSTR)IDI_HAND), 0);
194       break;
195     case MB_USERICON:
196       SendDlgItemMessageW(hwnd, MSGBOX_IDICON, STM_SETICON,
197                           (WPARAM)LoadIconW(lpmb->hInstance, lpmb->lpszIcon), 0);
198       break;
199     default:
200         /* By default, Windows 95/98/NT do not associate an icon to message boxes.
201          * So wine should do the same.
202          */
203         break;
204     }
205
206     /* Remove Help button unless MB_HELP supplied */
207     if (!(lpmb->dwStyle & MB_HELP)) {
208         DestroyWindow(GetDlgItem(hwnd, IDHELP));
209     }
210
211     /* Position everything */
212     GetWindowRect(hwnd, &rect);
213     borheight = rect.bottom - rect.top;
214     borwidth  = rect.right - rect.left;
215     GetClientRect(hwnd, &rect);
216     borheight -= rect.bottom - rect.top;
217     borwidth  -= rect.right - rect.left;
218
219     /* Get the icon height */
220     GetWindowRect(GetDlgItem(hwnd, MSGBOX_IDICON), &rect);
221     MapWindowPoints(0, hwnd, (LPPOINT)&rect, 2);
222     if (!(lpmb->dwStyle & MB_ICONMASK))
223     {
224         rect.bottom = rect.top;
225         rect.right = rect.left;
226     }
227     iheight = rect.bottom - rect.top;
228     ileft = rect.left;
229     iwidth = rect.right - ileft;
230
231     hdc = GetDC(hwnd);
232     if (hFont)
233         hPrevFont = SelectObject(hdc, hFont);
234
235     /* Get the number of visible buttons and their size */
236     bh = bw = 1; /* Minimum button sizes */
237     for (buttons = 0, i = 1; i < 12; i++)
238     {
239         if (i == 8) continue; /* No CLOSE button */
240         hItem = GetDlgItem(hwnd, i);
241         if (GetWindowLongW(hItem, GWL_STYLE) & WS_VISIBLE)
242         {
243             WCHAR buttonText[1024];
244             int w, h;
245             buttons++;
246             if (GetWindowTextW(hItem, buttonText, 1024))
247             {
248                 DrawTextW( hdc, buttonText, -1, &rect, DT_LEFT | DT_EXPANDTABS | DT_CALCRECT);
249                 h = rect.bottom - rect.top;
250                 w = rect.right - rect.left;
251                 if (h > bh) bh = h;
252                 if (w > bw)  bw = w ;
253             }
254         }
255     }
256     bw = max(bw, bh * 2);
257     /* Button white space */
258     bh = bh * 2;
259     bw = bw * 2;
260     bspace = bw/3; /* Space between buttons */
261
262     /* Get the text size */
263     GetClientRect(GetDlgItem(hwnd, MSGBOX_IDTEXT), &rect);
264     rect.top = rect.left = rect.bottom = 0;
265     DrawTextW( hdc, lpszText, -1, &rect,
266                DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_CALCRECT);
267     /* Min text width corresponds to space for the buttons */
268     tleft = ileft;
269     if (iwidth) tleft += ileft + iwidth;
270     twidth = max((bw + bspace) * buttons + bspace - tleft, rect.right);
271     theight = rect.bottom;
272
273     if (hFont)
274         SelectObject(hdc, hPrevFont);
275     ReleaseDC(hwnd, hdc);
276
277     tiheight = 16 + max(iheight, theight);
278     wwidth  = tleft + twidth + ileft + borwidth;
279     wheight = 8 + tiheight + bh + borheight;
280
281     /* Message boxes are always desktop centered, so query desktop size and center window */
282     monitor = MonitorFromWindow(lpmb->hwndOwner ? lpmb->hwndOwner : GetActiveWindow(), MONITOR_DEFAULTTOPRIMARY);
283     mon_info.cbSize = sizeof(mon_info);
284     GetMonitorInfoW(monitor, &mon_info);
285     wleft = (mon_info.rcWork.left + mon_info.rcWork.right - wwidth) / 2;
286     wtop = (mon_info.rcWork.top + mon_info.rcWork.bottom - wheight) / 2;
287
288     /* Resize and center the window */
289     SetWindowPos(hwnd, 0, wleft, wtop, wwidth, wheight,
290                  SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
291
292     /* Position the icon */
293     SetWindowPos(GetDlgItem(hwnd, MSGBOX_IDICON), 0, ileft, (tiheight - iheight) / 2, 0, 0,
294                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
295
296     /* Position the text */
297     SetWindowPos(GetDlgItem(hwnd, MSGBOX_IDTEXT), 0, tleft, (tiheight - theight) / 2, twidth, theight,
298                  SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
299
300     /* Position the buttons */
301     bpos = (wwidth - (bw + bspace) * buttons + bspace) / 2;
302     for (buttons = i = 0; i < (sizeof(buttonOrder) / sizeof(buttonOrder[0])); i++) {
303
304         /* Convert the button order to ID* value to order for the buttons */
305         hItem = GetDlgItem(hwnd, buttonOrder[i]);
306         if (GetWindowLongW(hItem, GWL_STYLE) & WS_VISIBLE) {
307             if (buttons++ == ((lpmb->dwStyle & MB_DEFMASK) >> 8)) {
308                 SetFocus(hItem);
309                 SendMessageW( hItem, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
310             }
311             SetWindowPos(hItem, 0, bpos, tiheight, bw, bh,
312                          SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREDRAW);
313             bpos += bw + bspace;
314         }
315     }
316
317     /*handle modal message boxes*/
318     if (((lpmb->dwStyle & MB_TASKMODAL) && (lpmb->hwndOwner==NULL)) || (lpmb->dwStyle & MB_SYSTEMMODAL))
319         SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
320
321     HeapFree( GetProcessHeap(), 0, buffer );
322     return hFont;
323 }
324
325
326 /**************************************************************************
327  *           MSGBOX_DlgProc
328  *
329  * Dialog procedure for message boxes.
330  */
331 static INT_PTR CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message,
332                                         WPARAM wParam, LPARAM lParam )
333 {
334   HFONT hFont;
335
336   switch(message) {
337    case WM_INITDIALOG:
338    {
339        LPMSGBOXPARAMSW mbp = (LPMSGBOXPARAMSW)lParam;
340        SetWindowContextHelpId(hwnd, mbp->dwContextHelpId);
341        hFont = MSGBOX_OnInit(hwnd, mbp);
342        SetPropA(hwnd, "WINE_MSGBOX_HFONT", hFont);
343        SetPropA(hwnd, "WINE_MSGBOX_HELPCALLBACK", mbp->lpfnMsgBoxCallback);
344        break;
345    }
346
347    case WM_COMMAND:
348     switch (LOWORD(wParam))
349     {
350      case IDOK:
351      case IDCANCEL:
352      case IDABORT:
353      case IDRETRY:
354      case IDIGNORE:
355      case IDYES:
356      case IDNO:
357      case IDTRYAGAIN:
358      case IDCONTINUE:
359       hFont = GetPropA(hwnd, "WINE_MSGBOX_HFONT");
360       EndDialog(hwnd, wParam);
361       if (hFont)
362           DeleteObject(hFont);
363       break;
364      case IDHELP:
365       FIXME("Help button not supported yet\n");
366       break;
367     }
368     break;
369
370     case WM_HELP:
371     {
372         MSGBOXCALLBACK callback = (MSGBOXCALLBACK)GetPropA(hwnd, "WINE_MSGBOX_HELPCALLBACK");
373         HELPINFO hi;
374
375         memcpy(&hi, (void *)lParam, sizeof(hi));
376         hi.dwContextId = GetWindowContextHelpId(hwnd);
377
378         if (callback)
379             callback(&hi);
380         else
381             SendMessageW(GetWindow(hwnd, GW_OWNER), WM_HELP, 0, (LPARAM)&hi);
382         break;
383    }
384
385    default:
386      /* Ok. Ignore all the other messages */
387      TRACE("Message number 0x%04x is being ignored.\n", message);
388     break;
389   }
390   return 0;
391 }
392
393
394 /**************************************************************************
395  *              MessageBoxA (USER32.@)
396  */
397 INT WINAPI MessageBoxA(HWND hWnd, LPCSTR text, LPCSTR title, UINT type)
398 {
399     return MessageBoxExA(hWnd, text, title, type, LANG_NEUTRAL);
400 }
401
402
403 /**************************************************************************
404  *              MessageBoxW (USER32.@)
405  */
406 INT WINAPI MessageBoxW( HWND hwnd, LPCWSTR text, LPCWSTR title, UINT type )
407 {
408     return MessageBoxExW(hwnd, text, title, type, LANG_NEUTRAL);
409 }
410
411
412 /**************************************************************************
413  *              MessageBoxExA (USER32.@)
414  */
415 INT WINAPI MessageBoxExA( HWND hWnd, LPCSTR text, LPCSTR title,
416                               UINT type, WORD langid )
417 {
418     MSGBOXPARAMSA msgbox;
419
420     msgbox.cbSize = sizeof(msgbox);
421     msgbox.hwndOwner = hWnd;
422     msgbox.hInstance = 0;
423     msgbox.lpszText = text;
424     msgbox.lpszCaption = title;
425     msgbox.dwStyle = type;
426     msgbox.lpszIcon = NULL;
427     msgbox.dwContextHelpId = 0;
428     msgbox.lpfnMsgBoxCallback = NULL;
429     msgbox.dwLanguageId = langid;
430
431     return MessageBoxIndirectA(&msgbox);
432 }
433
434 /**************************************************************************
435  *              MessageBoxExW (USER32.@)
436  */
437 INT WINAPI MessageBoxExW( HWND hWnd, LPCWSTR text, LPCWSTR title,
438                               UINT type, WORD langid )
439 {
440     MSGBOXPARAMSW msgbox;
441
442     msgbox.cbSize = sizeof(msgbox);
443     msgbox.hwndOwner = hWnd;
444     msgbox.hInstance = 0;
445     msgbox.lpszText = text;
446     msgbox.lpszCaption = title;
447     msgbox.dwStyle = type;
448     msgbox.lpszIcon = NULL;
449     msgbox.dwContextHelpId = 0;
450     msgbox.lpfnMsgBoxCallback = NULL;
451     msgbox.dwLanguageId = langid;
452
453     return MessageBoxIndirectW(&msgbox);
454 }
455
456 /**************************************************************************
457  *      MessageBoxTimeoutA (USER32.@)
458  */
459 INT WINAPI MessageBoxTimeoutA( HWND hWnd, LPCSTR text, LPCSTR title,
460                                UINT type, WORD langid, DWORD timeout )
461 {
462     FIXME("timeout not supported (%u)\n", timeout);
463     return MessageBoxExA( hWnd, text, title, type, langid );
464 }
465
466 /**************************************************************************
467  *      MessageBoxTimeoutW (USER32.@)
468  */
469 INT WINAPI MessageBoxTimeoutW( HWND hWnd, LPCWSTR text, LPCWSTR title,
470                                UINT type, WORD langid, DWORD timeout )
471 {
472     FIXME("timeout not supported (%u)\n", timeout);
473     return MessageBoxExW( hWnd, text, title, type, langid );
474 }
475
476 /**************************************************************************
477  *              MessageBoxIndirectA (USER32.@)
478  */
479 INT WINAPI MessageBoxIndirectA( LPMSGBOXPARAMSA msgbox )
480 {
481     MSGBOXPARAMSW msgboxW;
482     UNICODE_STRING textW, captionW, iconW;
483     int ret;
484
485     if (IS_INTRESOURCE(msgbox->lpszText))
486         textW.Buffer = (LPWSTR)msgbox->lpszText;
487     else
488         RtlCreateUnicodeStringFromAsciiz(&textW, msgbox->lpszText);
489     if (IS_INTRESOURCE(msgbox->lpszCaption))
490         captionW.Buffer = (LPWSTR)msgbox->lpszCaption;
491     else
492         RtlCreateUnicodeStringFromAsciiz(&captionW, msgbox->lpszCaption);
493
494     if (msgbox->dwStyle & MB_USERICON)
495     {
496         if (IS_INTRESOURCE(msgbox->lpszIcon))
497             iconW.Buffer = (LPWSTR)msgbox->lpszIcon;
498         else
499             RtlCreateUnicodeStringFromAsciiz(&iconW, msgbox->lpszIcon);
500     }
501     else
502         iconW.Buffer = NULL;
503
504     msgboxW.cbSize = sizeof(msgboxW);
505     msgboxW.hwndOwner = msgbox->hwndOwner;
506     msgboxW.hInstance = msgbox->hInstance;
507     msgboxW.lpszText = textW.Buffer;
508     msgboxW.lpszCaption = captionW.Buffer;
509     msgboxW.dwStyle = msgbox->dwStyle;
510     msgboxW.lpszIcon = iconW.Buffer;
511     msgboxW.dwContextHelpId = msgbox->dwContextHelpId;
512     msgboxW.lpfnMsgBoxCallback = msgbox->lpfnMsgBoxCallback;
513     msgboxW.dwLanguageId = msgbox->dwLanguageId;
514
515     ret = MessageBoxIndirectW(&msgboxW);
516
517     if (!IS_INTRESOURCE(textW.Buffer)) RtlFreeUnicodeString(&textW);
518     if (!IS_INTRESOURCE(captionW.Buffer)) RtlFreeUnicodeString(&captionW);
519     if (!IS_INTRESOURCE(iconW.Buffer)) RtlFreeUnicodeString(&iconW);
520     return ret;
521 }
522
523 /**************************************************************************
524  *              MessageBoxIndirectW (USER32.@)
525  */
526 INT WINAPI MessageBoxIndirectW( LPMSGBOXPARAMSW msgbox )
527 {
528     LPVOID tmplate;
529     HRSRC hRes;
530     int ret;
531     UINT i;
532     struct ThreadWindows threadWindows;
533     static const WCHAR msg_box_res_nameW[] = { 'M','S','G','B','O','X',0 };
534
535     if (!(hRes = FindResourceExW(user32_module, (LPWSTR)RT_DIALOG,
536                                  msg_box_res_nameW, msgbox->dwLanguageId)))
537     {
538         if (!msgbox->dwLanguageId ||
539             !(hRes = FindResourceExW(user32_module, (LPWSTR)RT_DIALOG, msg_box_res_nameW, LANG_NEUTRAL)))
540             return 0;
541     }
542     if (!(tmplate = LoadResource(user32_module, hRes)))
543         return 0;
544
545     if ((msgbox->dwStyle & MB_TASKMODAL) && (msgbox->hwndOwner==NULL))
546     {
547         threadWindows.numHandles = 0;
548         threadWindows.numAllocs = 10;
549         threadWindows.handles = HeapAlloc(GetProcessHeap(), 0, 10*sizeof(HWND));
550         EnumThreadWindows(GetCurrentThreadId(), MSGBOX_EnumProc, (LPARAM)&threadWindows);
551     }
552
553     ret=DialogBoxIndirectParamW(msgbox->hInstance, tmplate,
554                                 msgbox->hwndOwner, MSGBOX_DlgProc, (LPARAM)msgbox);
555
556     if ((msgbox->dwStyle & MB_TASKMODAL) && (msgbox->hwndOwner==NULL))
557     {
558         for (i = 0; i < threadWindows.numHandles; i++)
559             EnableWindow(threadWindows.handles[i], TRUE);
560         HeapFree(GetProcessHeap(), 0, threadWindows.handles);
561     }
562     return ret;
563 }