- Fix some indentation.
[wine] / windows / dialog.c
1 /*
2  * Dialog functions
3  *
4  * Copyright 1993, 1994, 1996 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <ctype.h>
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "windef.h"
32 #include "winnls.h"
33 #include "winbase.h"
34 #include "wingdi.h"
35 #include "winuser.h"
36 #include "wine/winuser16.h"
37 #include "wine/unicode.h"
38 #include "controls.h"
39 #include "heap.h"
40 #include "win.h"
41 #include "user.h"
42 #include "wine/debug.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(dialog);
45
46
47   /* Dialog control information */
48 typedef struct
49 {
50     DWORD      style;
51     DWORD      exStyle;
52     DWORD      helpId;
53     INT16      x;
54     INT16      y;
55     INT16      cx;
56     INT16      cy;
57     UINT       id;
58     LPCWSTR    className;
59     LPCWSTR    windowName;
60     LPCVOID    data;
61 } DLG_CONTROL_INFO;
62
63   /* Dialog template */
64 typedef struct
65 {
66     DWORD      style;
67     DWORD      exStyle;
68     DWORD      helpId;
69     UINT16     nbItems;
70     INT16      x;
71     INT16      y;
72     INT16      cx;
73     INT16      cy;
74     LPCWSTR    menuName;
75     LPCWSTR    className;
76     LPCWSTR    caption;
77     WORD       pointSize;
78     WORD       weight;
79     BOOL       italic;
80     LPCWSTR    faceName;
81     BOOL       dialogEx;
82 } DLG_TEMPLATE;
83
84   /* Radio button group */
85 typedef struct
86 {
87     UINT firstID;
88     UINT lastID;
89     UINT checkID;
90 } RADIOGROUP;
91
92   /* Dialog base units */
93 static WORD xBaseUnit = 0, yBaseUnit = 0;
94
95
96 /*********************************************************************
97  * dialog class descriptor
98  */
99 const struct builtin_class_descr DIALOG_builtin_class =
100 {
101     DIALOG_CLASS_ATOMA,  /* name */
102     CS_GLOBALCLASS | CS_SAVEBITS | CS_DBLCLKS, /* style  */
103     DefDlgProcA,        /* procA */
104     DefDlgProcW,        /* procW */
105     DLGWINDOWEXTRA,     /* extra */
106     IDC_ARROWA,         /* cursor */
107     0                   /* brush */
108 };
109
110
111 /***********************************************************************
112  *           DIALOG_EnableOwner
113  *
114  * Helper function for modal dialogs to enable again the
115  * owner of the dialog box.
116  */
117 void DIALOG_EnableOwner( HWND hOwner )
118 {
119     /* Owner must be a top-level window */
120     if (hOwner)
121         hOwner = GetAncestor( hOwner, GA_ROOT );
122     if (!hOwner) return;
123     EnableWindow( hOwner, TRUE );
124 }
125
126
127 /***********************************************************************
128  *           DIALOG_DisableOwner
129  *
130  * Helper function for modal dialogs to disable the
131  * owner of the dialog box. Returns TRUE if owner was enabled.
132  */
133 BOOL DIALOG_DisableOwner( HWND hOwner )
134 {
135     /* Owner must be a top-level window */
136     if (hOwner)
137         hOwner = GetAncestor( hOwner, GA_ROOT );
138     if (!hOwner) return FALSE;
139     if (IsWindowEnabled( hOwner ))
140     {
141         EnableWindow( hOwner, FALSE );
142         return TRUE;
143     }
144     else
145         return FALSE;
146 }
147
148 /***********************************************************************
149  *           DIALOG_GetCharSizeFromDC
150  *
151  * Despite most of MSDN insisting that the horizontal base unit is
152  * tmAveCharWidth it isn't.  Knowledge base article Q145994
153  * "HOWTO: Calculate Dialog Units When Not Using the System Font",
154  * says that we should take the average of the 52 English upper and lower
155  * case characters.
156  */
157 static BOOL DIALOG_GetCharSizeFromDC( HDC hDC, HFONT hFont, SIZE * pSize )
158 {
159     HFONT hFontPrev = 0;
160     char *alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
161     SIZE sz;
162     TEXTMETRICA tm;
163
164     pSize->cx = xBaseUnit;
165     pSize->cy = yBaseUnit;
166
167     if(!hDC) return FALSE;
168
169     if(hFont) hFontPrev = SelectObject(hDC, hFont);
170     if(!GetTextMetricsA(hDC, &tm)) return FALSE;
171     if(!GetTextExtentPointA(hDC, alphabet, 52, &sz)) return FALSE;
172
173     pSize->cy = tm.tmHeight;
174     pSize->cx = (sz.cx / 26 + 1) / 2;
175
176     if (hFontPrev) SelectObject(hDC, hFontPrev);
177
178     TRACE("dlg base units: %ld x %ld\n", pSize->cx, pSize->cy);
179     return TRUE;
180 }
181
182 /***********************************************************************
183  *           DIALOG_GetCharSize
184  *
185  *  A convenient variant of DIALOG_GetCharSizeFromDC.
186  */
187 BOOL DIALOG_GetCharSize( HFONT hFont, SIZE * pSize )
188 {
189     HDC  hDC = GetDC(0);
190     BOOL Success = DIALOG_GetCharSizeFromDC( hDC, hFont, pSize );
191     ReleaseDC(0, hDC);
192     return Success;
193 }
194
195 /***********************************************************************
196  *           DIALOG_Init
197  *
198  * Initialisation of the dialog manager.
199  */
200 BOOL DIALOG_Init(void)
201 {
202     HDC hdc;
203     SIZE size;
204
205       /* Calculate the dialog base units */
206
207     if (!(hdc = CreateDCA( "DISPLAY", NULL, NULL, NULL )))
208     {
209         ERR("Could not create Display DC\n");
210         return FALSE;
211     }
212
213     if (!DIALOG_GetCharSizeFromDC( hdc, 0, &size ))
214     {
215         DeleteDC( hdc );
216         ERR("Could not initialize base dialog units\n");
217         return FALSE;
218     }
219
220     DeleteDC( hdc );
221     xBaseUnit = size.cx;
222     yBaseUnit = size.cy;
223
224     TRACE("base units = %d,%d\n", xBaseUnit, yBaseUnit );
225     return TRUE;
226 }
227
228
229 /***********************************************************************
230  *           DIALOG_GetControl32
231  *
232  * Return the class and text of the control pointed to by ptr,
233  * fill the header structure and return a pointer to the next control.
234  */
235 static const WORD *DIALOG_GetControl32( const WORD *p, DLG_CONTROL_INFO *info,
236                                         BOOL dialogEx )
237 {
238     if (dialogEx)
239     {
240         info->helpId  = GET_DWORD(p); p += 2;
241         info->exStyle = GET_DWORD(p); p += 2;
242         info->style   = GET_DWORD(p); p += 2;
243     }
244     else
245     {
246         info->helpId  = 0;
247         info->style   = GET_DWORD(p); p += 2;
248         info->exStyle = GET_DWORD(p); p += 2;
249     }
250     info->x       = GET_WORD(p); p++;
251     info->y       = GET_WORD(p); p++;
252     info->cx      = GET_WORD(p); p++;
253     info->cy      = GET_WORD(p); p++;
254
255     if (dialogEx)
256     {
257         /* id is a DWORD for DIALOGEX */
258         info->id = GET_DWORD(p);
259         p += 2;
260     }
261     else
262     {
263         info->id = GET_WORD(p);
264         p++;
265     }
266
267     if (GET_WORD(p) == 0xffff)
268     {
269         static const WCHAR class_names[6][10] =
270         {
271             { 'B','u','t','t','o','n', },             /* 0x80 */
272             { 'E','d','i','t', },                     /* 0x81 */
273             { 'S','t','a','t','i','c', },             /* 0x82 */
274             { 'L','i','s','t','B','o','x', },         /* 0x83 */
275             { 'S','c','r','o','l','l','B','a','r', }, /* 0x84 */
276             { 'C','o','m','b','o','B','o','x', }      /* 0x85 */
277         };
278         WORD id = GET_WORD(p+1);
279         if ((id >= 0x80) && (id <= 0x85))
280             info->className = class_names[id - 0x80];
281         else
282         {
283             info->className = NULL;
284             ERR("Unknown built-in class id %04x\n", id );
285         }
286         p += 2;
287     }
288     else
289     {
290         info->className = (LPCWSTR)p;
291         p += strlenW( info->className ) + 1;
292     }
293
294     if (GET_WORD(p) == 0xffff)  /* Is it an integer id? */
295     {
296         info->windowName = (LPCWSTR)(UINT)GET_WORD(p + 1);
297         p += 2;
298     }
299     else
300     {
301         info->windowName = (LPCWSTR)p;
302         p += strlenW( info->windowName ) + 1;
303     }
304
305     TRACE("    %s %s %d, %d, %d, %d, %d, %08lx, %08lx, %08lx\n",
306           debugstr_w( info->className ), debugstr_w( info->windowName ),
307           info->id, info->x, info->y, info->cx, info->cy,
308           info->style, info->exStyle, info->helpId );
309
310     if (GET_WORD(p))
311     {
312         if (TRACE_ON(dialog))
313         {
314             WORD i, count = GET_WORD(p) / sizeof(WORD);
315             TRACE("  BEGIN\n");
316             TRACE("    ");
317             for (i = 0; i < count; i++) TRACE( "%04x,", GET_WORD(p+i+1) );
318             TRACE("\n");
319             TRACE("  END\n" );
320         }
321         info->data = p + 1;
322         p += GET_WORD(p) / sizeof(WORD);
323     }
324     else info->data = NULL;
325     p++;
326
327     /* Next control is on dword boundary */
328     return (const WORD *)((((int)p) + 3) & ~3);
329 }
330
331
332 /***********************************************************************
333  *           DIALOG_CreateControls32
334  *
335  * Create the control windows for a dialog.
336  */
337 static BOOL DIALOG_CreateControls32( HWND hwnd, LPCSTR template, const DLG_TEMPLATE *dlgTemplate,
338                                      HINSTANCE hInst, BOOL unicode )
339 {
340     DIALOGINFO *dlgInfo = DIALOG_get_info( hwnd );
341     DLG_CONTROL_INFO info;
342     HWND hwndCtrl, hwndDefButton = 0;
343     INT items = dlgTemplate->nbItems;
344
345     TRACE(" BEGIN\n" );
346     while (items--)
347     {
348         template = (LPCSTR)DIALOG_GetControl32( (WORD *)template, &info,
349                                                 dlgTemplate->dialogEx );
350         /* Is this it? */
351         if (info.style & WS_BORDER)
352         {
353             info.style &= ~WS_BORDER;
354             info.exStyle |= WS_EX_CLIENTEDGE;
355         }
356         if (unicode)
357         {
358             hwndCtrl = CreateWindowExW( info.exStyle | WS_EX_NOPARENTNOTIFY,
359                                         info.className, info.windowName,
360                                         info.style | WS_CHILD,
361                                         MulDiv(info.x, dlgInfo->xBaseUnit, 4),
362                                         MulDiv(info.y, dlgInfo->yBaseUnit, 8),
363                                         MulDiv(info.cx, dlgInfo->xBaseUnit, 4),
364                                         MulDiv(info.cy, dlgInfo->yBaseUnit, 8),
365                                         hwnd, (HMENU)info.id,
366                                         hInst, (LPVOID)info.data );
367         }
368         else
369         {
370             LPSTR class = (LPSTR)info.className;
371             LPSTR caption = (LPSTR)info.windowName;
372
373             if (HIWORD(class))
374             {
375                 DWORD len = WideCharToMultiByte( CP_ACP, 0, info.className, -1, NULL, 0, NULL, NULL );
376                 class = HeapAlloc( GetProcessHeap(), 0, len );
377                 WideCharToMultiByte( CP_ACP, 0, info.className, -1, class, len, NULL, NULL );
378             }
379             if (HIWORD(caption))
380             {
381                 DWORD len = WideCharToMultiByte( CP_ACP, 0, info.windowName, -1, NULL, 0, NULL, NULL );
382                 caption = HeapAlloc( GetProcessHeap(), 0, len );
383                 WideCharToMultiByte( CP_ACP, 0, info.windowName, -1, caption, len, NULL, NULL );
384             }
385             hwndCtrl = CreateWindowExA( info.exStyle | WS_EX_NOPARENTNOTIFY,
386                                         class, caption, info.style | WS_CHILD,
387                                         MulDiv(info.x, dlgInfo->xBaseUnit, 4),
388                                         MulDiv(info.y, dlgInfo->yBaseUnit, 8),
389                                         MulDiv(info.cx, dlgInfo->xBaseUnit, 4),
390                                         MulDiv(info.cy, dlgInfo->yBaseUnit, 8),
391                                         hwnd, (HMENU)info.id,
392                                         hInst, (LPVOID)info.data );
393             if (HIWORD(class)) HeapFree( GetProcessHeap(), 0, class );
394             if (HIWORD(caption)) HeapFree( GetProcessHeap(), 0, caption );
395         }
396         if (!hwndCtrl)
397         {
398             if (dlgTemplate->style & DS_NOFAILCREATE) continue;
399             return FALSE;
400         }
401
402             /* Send initialisation messages to the control */
403         if (dlgInfo->hUserFont) SendMessageA( hwndCtrl, WM_SETFONT,
404                                              (WPARAM)dlgInfo->hUserFont, 0 );
405         if (SendMessageA(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
406         {
407               /* If there's already a default push-button, set it back */
408               /* to normal and use this one instead. */
409             if (hwndDefButton)
410                 SendMessageA( hwndDefButton, BM_SETSTYLE, BS_PUSHBUTTON, FALSE );
411             hwndDefButton = hwndCtrl;
412             dlgInfo->idResult = GetWindowLongA( hwndCtrl, GWL_ID );
413         }
414     }
415     TRACE(" END\n" );
416     return TRUE;
417 }
418
419
420 /***********************************************************************
421  *           DIALOG_ParseTemplate32
422  *
423  * Fill a DLG_TEMPLATE structure from the dialog template, and return
424  * a pointer to the first control.
425  */
426 static LPCSTR DIALOG_ParseTemplate32( LPCSTR template, DLG_TEMPLATE * result )
427 {
428     const WORD *p = (const WORD *)template;
429
430     result->style = GET_DWORD(p); p += 2;
431     if (result->style == 0xffff0001)  /* DIALOGEX resource */
432     {
433         result->dialogEx = TRUE;
434         result->helpId   = GET_DWORD(p); p += 2;
435         result->exStyle  = GET_DWORD(p); p += 2;
436         result->style    = GET_DWORD(p); p += 2;
437     }
438     else
439     {
440         result->dialogEx = FALSE;
441         result->helpId   = 0;
442         result->exStyle  = GET_DWORD(p); p += 2;
443     }
444     result->nbItems = GET_WORD(p); p++;
445     result->x       = GET_WORD(p); p++;
446     result->y       = GET_WORD(p); p++;
447     result->cx      = GET_WORD(p); p++;
448     result->cy      = GET_WORD(p); p++;
449     TRACE("DIALOG%s %d, %d, %d, %d, %ld\n",
450            result->dialogEx ? "EX" : "", result->x, result->y,
451            result->cx, result->cy, result->helpId );
452     TRACE(" STYLE 0x%08lx\n", result->style );
453     TRACE(" EXSTYLE 0x%08lx\n", result->exStyle );
454
455     /* Get the menu name */
456
457     switch(GET_WORD(p))
458     {
459     case 0x0000:
460         result->menuName = NULL;
461         p++;
462         break;
463     case 0xffff:
464         result->menuName = (LPCWSTR)(UINT)GET_WORD( p + 1 );
465         p += 2;
466         TRACE(" MENU %04x\n", LOWORD(result->menuName) );
467         break;
468     default:
469         result->menuName = (LPCWSTR)p;
470         TRACE(" MENU %s\n", debugstr_w(result->menuName) );
471         p += strlenW( result->menuName ) + 1;
472         break;
473     }
474
475     /* Get the class name */
476
477     switch(GET_WORD(p))
478     {
479     case 0x0000:
480         result->className = DIALOG_CLASS_ATOMW;
481         p++;
482         break;
483     case 0xffff:
484         result->className = (LPCWSTR)(UINT)GET_WORD( p + 1 );
485         p += 2;
486         TRACE(" CLASS %04x\n", LOWORD(result->className) );
487         break;
488     default:
489         result->className = (LPCWSTR)p;
490         TRACE(" CLASS %s\n", debugstr_w( result->className ));
491         p += strlenW( result->className ) + 1;
492         break;
493     }
494
495     /* Get the window caption */
496
497     result->caption = (LPCWSTR)p;
498     p += strlenW( result->caption ) + 1;
499     TRACE(" CAPTION %s\n", debugstr_w( result->caption ) );
500
501     /* Get the font name */
502
503     if (result->style & DS_SETFONT)
504     {
505         result->pointSize = GET_WORD(p);
506         p++;
507         if (result->dialogEx)
508         {
509             result->weight = GET_WORD(p); p++;
510             result->italic = LOBYTE(GET_WORD(p)); p++;
511         }
512         else
513         {
514             result->weight = FW_DONTCARE;
515             result->italic = FALSE;
516         }
517         result->faceName = (LPCWSTR)p;
518         p += strlenW( result->faceName ) + 1;
519         TRACE(" FONT %d, %s, %d, %s\n",
520               result->pointSize, debugstr_w( result->faceName ),
521               result->weight, result->italic ? "TRUE" : "FALSE" );
522     }
523
524     /* First control is on dword boundary */
525     return (LPCSTR)((((int)p) + 3) & ~3);
526 }
527
528
529 /***********************************************************************
530  *           DIALOG_CreateIndirect
531  *       Creates a dialog box window
532  *
533  *       modal = TRUE if we are called from a modal dialog box.
534  *       (it's more compatible to do it here, as under Windows the owner
535  *       is never disabled if the dialog fails because of an invalid template)
536  */
537 static HWND DIALOG_CreateIndirect( HINSTANCE hInst, LPCVOID dlgTemplate,
538                                    HWND owner, DLGPROC dlgProc, LPARAM param,
539                                    BOOL unicode, BOOL modal )
540 {
541     HWND hwnd;
542     RECT rect;
543     WND * wndPtr;
544     DLG_TEMPLATE template;
545     DIALOGINFO * dlgInfo;
546     BOOL ownerEnabled = TRUE;
547
548       /* Parse dialog template */
549
550     if (!dlgTemplate) return 0;
551     dlgTemplate = DIALOG_ParseTemplate32( dlgTemplate, &template );
552
553       /* Initialise dialog extra data */
554
555     if (!(dlgInfo = HeapAlloc( GetProcessHeap(), 0, sizeof(*dlgInfo) ))) return 0;
556     dlgInfo->hwndFocus   = 0;
557     dlgInfo->hUserFont   = 0;
558     dlgInfo->hMenu       = 0;
559     dlgInfo->xBaseUnit   = xBaseUnit;
560     dlgInfo->yBaseUnit   = yBaseUnit;
561     dlgInfo->idResult    = 0;
562     dlgInfo->flags       = 0;
563     dlgInfo->hDialogHeap = 0;
564
565       /* Load menu */
566
567     if (template.menuName) dlgInfo->hMenu = LoadMenuW( hInst, template.menuName );
568
569       /* Create custom font if needed */
570
571     if (template.style & DS_SETFONT)
572     {
573           /* We convert the size to pixels and then make it -ve.  This works
574            * for both +ve and -ve template.pointSize */
575         HDC dc;
576         int pixels;
577         dc = GetDC(0);
578         pixels = MulDiv(template.pointSize, GetDeviceCaps(dc , LOGPIXELSY), 72);
579         ReleaseDC(0, dc);
580         dlgInfo->hUserFont = CreateFontW( -pixels, 0, 0, 0, template.weight,
581                                           template.italic, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
582                                           PROOF_QUALITY, FF_DONTCARE,
583                                           template.faceName );
584         if (dlgInfo->hUserFont)
585         {
586             SIZE charSize;
587             if (DIALOG_GetCharSize( dlgInfo->hUserFont, &charSize ))
588             {
589                 dlgInfo->xBaseUnit = charSize.cx;
590                 dlgInfo->yBaseUnit = charSize.cy;
591             }
592         }
593         TRACE("units = %d,%d\n", dlgInfo->xBaseUnit, dlgInfo->yBaseUnit );
594     }
595
596     /* Create dialog main window */
597
598     rect.left = rect.top = 0;
599     rect.right = MulDiv(template.cx, dlgInfo->xBaseUnit, 4);
600     rect.bottom =  MulDiv(template.cy, dlgInfo->yBaseUnit, 8);
601     if (template.style & DS_MODALFRAME)
602         template.exStyle |= WS_EX_DLGMODALFRAME;
603     AdjustWindowRectEx( &rect, template.style, (dlgInfo->hMenu != 0), template.exStyle );
604     rect.right -= rect.left;
605     rect.bottom -= rect.top;
606
607     if (template.x == CW_USEDEFAULT16)
608     {
609         rect.left = rect.top = CW_USEDEFAULT;
610     }
611     else
612     {
613         if (template.style & DS_CENTER)
614         {
615             rect.left = (GetSystemMetrics(SM_CXSCREEN) - rect.right) / 2;
616             rect.top = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom) / 2;
617         }
618         else
619         {
620             rect.left += MulDiv(template.x, dlgInfo->xBaseUnit, 4);
621             rect.top += MulDiv(template.y, dlgInfo->yBaseUnit, 8);
622         }
623         if ( !(template.style & WS_CHILD) )
624         {
625             INT dX, dY;
626
627             if( !(template.style & DS_ABSALIGN) )
628                 ClientToScreen( owner, (POINT *)&rect );
629
630             /* try to fit it into the desktop */
631
632             if( (dX = rect.left + rect.right + GetSystemMetrics(SM_CXDLGFRAME)
633                  - GetSystemMetrics(SM_CXSCREEN)) > 0 ) rect.left -= dX;
634             if( (dY = rect.top + rect.bottom + GetSystemMetrics(SM_CYDLGFRAME)
635                  - GetSystemMetrics(SM_CYSCREEN)) > 0 ) rect.top -= dY;
636             if( rect.left < 0 ) rect.left = 0;
637             if( rect.top < 0 ) rect.top = 0;
638         }
639     }
640
641     if (modal)
642     {
643         ownerEnabled = DIALOG_DisableOwner( owner );
644         if (ownerEnabled) dlgInfo->flags |= DF_OWNERENABLED;
645     }
646
647     if (unicode)
648     {
649         hwnd = CreateWindowExW(template.exStyle, template.className, template.caption,
650                                template.style & ~WS_VISIBLE,
651                                rect.left, rect.top, rect.right, rect.bottom,
652                                owner, dlgInfo->hMenu, hInst, NULL );
653     }
654     else
655     {
656         LPSTR class = (LPSTR)template.className;
657         LPSTR caption = (LPSTR)template.caption;
658
659         if (HIWORD(class))
660         {
661             DWORD len = WideCharToMultiByte( CP_ACP, 0, template.className, -1, NULL, 0, NULL, NULL );
662             class = HeapAlloc( GetProcessHeap(), 0, len );
663             WideCharToMultiByte( CP_ACP, 0, template.className, -1, class, len, NULL, NULL );
664         }
665         if (HIWORD(caption))
666         {
667             DWORD len = WideCharToMultiByte( CP_ACP, 0, template.caption, -1, NULL, 0, NULL, NULL );
668             caption = HeapAlloc( GetProcessHeap(), 0, len );
669             WideCharToMultiByte( CP_ACP, 0, template.caption, -1, caption, len, NULL, NULL );
670         }
671         hwnd = CreateWindowExA(template.exStyle, class, caption,
672                                template.style & ~WS_VISIBLE,
673                                rect.left, rect.top, rect.right, rect.bottom,
674                                owner, dlgInfo->hMenu, hInst, NULL );
675         if (HIWORD(class)) HeapFree( GetProcessHeap(), 0, class );
676         if (HIWORD(caption)) HeapFree( GetProcessHeap(), 0, caption );
677     }
678
679     if (!hwnd)
680     {
681         if (dlgInfo->hUserFont) DeleteObject( dlgInfo->hUserFont );
682         if (dlgInfo->hMenu) DestroyMenu( dlgInfo->hMenu );
683         if (modal && (dlgInfo->flags & DF_OWNERENABLED)) DIALOG_EnableOwner(owner);
684         HeapFree( GetProcessHeap(), 0, dlgInfo );
685         return 0;
686     }
687     wndPtr = WIN_GetPtr( hwnd );
688     wndPtr->flags |= WIN_ISDIALOG;
689     WIN_ReleasePtr( wndPtr );
690
691     if (template.helpId) SetWindowContextHelpId( hwnd, template.helpId );
692     SetWindowLongW( hwnd, DWL_WINE_DIALOGINFO, (LONG)dlgInfo );
693
694     if (unicode) SetWindowLongW( hwnd, DWL_DLGPROC, (LONG)dlgProc );
695     else SetWindowLongA( hwnd, DWL_DLGPROC, (LONG)dlgProc );
696
697     if (dlgInfo->hUserFont)
698         SendMessageA( hwnd, WM_SETFONT, (WPARAM)dlgInfo->hUserFont, 0 );
699
700     /* Create controls */
701
702     if (DIALOG_CreateControls32( hwnd, dlgTemplate, &template, hInst, unicode ))
703     {
704         HWND hwndPreInitFocus;
705
706         /* Send initialisation messages and set focus */
707
708         dlgInfo->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE );
709
710         hwndPreInitFocus = GetFocus();
711         if (SendMessageA( hwnd, WM_INITDIALOG, (WPARAM)dlgInfo->hwndFocus, param ))
712         {
713             /* check where the focus is again,
714              * some controls status might have changed in WM_INITDIALOG */
715             dlgInfo->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE);
716             if( dlgInfo->hwndFocus )
717                 SetFocus( dlgInfo->hwndFocus );
718         }
719         else
720         {
721             /* If the dlgproc has returned FALSE (indicating handling of keyboard focus)
722                but the focus has not changed, set the focus where we expect it. */
723             if ((GetFocus() == hwndPreInitFocus) &&
724                 (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
725             {
726                 dlgInfo->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE);
727                 if( dlgInfo->hwndFocus )
728                     SetFocus( dlgInfo->hwndFocus );
729             }
730         }
731
732         if (template.style & WS_VISIBLE && !(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
733         {
734            ShowWindow( hwnd, SW_SHOWNORMAL );   /* SW_SHOW doesn't always work */
735         }
736         return hwnd;
737     }
738     if( IsWindow(hwnd) ) DestroyWindow( hwnd );
739     if (modal && ownerEnabled) DIALOG_EnableOwner(owner);
740     return 0;
741 }
742
743
744 /***********************************************************************
745  *              CreateDialogParamA (USER32.@)
746  */
747 HWND WINAPI CreateDialogParamA( HINSTANCE hInst, LPCSTR name, HWND owner,
748                                 DLGPROC dlgProc, LPARAM param )
749 {
750     HRSRC hrsrc;
751     LPCDLGTEMPLATEA ptr;
752
753     if (!(hrsrc = FindResourceA( hInst, name, RT_DIALOGA ))) return 0;
754     if (!(ptr = (LPCDLGTEMPLATEA)LoadResource(hInst, hrsrc))) return 0;
755     return CreateDialogIndirectParamA( hInst, ptr, owner, dlgProc, param );
756 }
757
758
759 /***********************************************************************
760  *              CreateDialogParamW (USER32.@)
761  */
762 HWND WINAPI CreateDialogParamW( HINSTANCE hInst, LPCWSTR name, HWND owner,
763                                 DLGPROC dlgProc, LPARAM param )
764 {
765     HRSRC hrsrc;
766     LPCDLGTEMPLATEA ptr;
767
768     if (!(hrsrc = FindResourceW( hInst, name, RT_DIALOGW ))) return 0;
769     if (!(ptr = (LPCDLGTEMPLATEW)LoadResource(hInst, hrsrc))) return 0;
770     return CreateDialogIndirectParamW( hInst, ptr, owner, dlgProc, param );
771 }
772
773
774 /***********************************************************************
775  *              CreateDialogIndirectParamAorW (USER32.@)
776  */
777 HWND WINAPI CreateDialogIndirectParamAorW( HINSTANCE hInst, LPCVOID dlgTemplate,
778                                            HWND owner, DLGPROC dlgProc, LPARAM param,
779                                            DWORD flags )
780 {
781     return DIALOG_CreateIndirect( hInst, dlgTemplate, owner, dlgProc, param, !flags, FALSE );
782 }
783
784 /***********************************************************************
785  *              CreateDialogIndirectParamA (USER32.@)
786  */
787 HWND WINAPI CreateDialogIndirectParamA( HINSTANCE hInst, LPCDLGTEMPLATEA dlgTemplate,
788                                         HWND owner, DLGPROC dlgProc, LPARAM param )
789 {
790     return CreateDialogIndirectParamAorW( hInst, dlgTemplate, owner, dlgProc, param, 2 );
791 }
792
793 /***********************************************************************
794  *              CreateDialogIndirectParamW (USER32.@)
795  */
796 HWND WINAPI CreateDialogIndirectParamW( HINSTANCE hInst, LPCDLGTEMPLATEW dlgTemplate,
797                                         HWND owner, DLGPROC dlgProc, LPARAM param )
798 {
799     return CreateDialogIndirectParamAorW( hInst, dlgTemplate, owner, dlgProc, param, 0 );
800 }
801
802
803 /***********************************************************************
804  *           DIALOG_DoDialogBox
805  */
806 INT DIALOG_DoDialogBox( HWND hwnd, HWND owner )
807 {
808     DIALOGINFO * dlgInfo;
809     MSG msg;
810     INT retval;
811     HWND ownerMsg = GetAncestor( owner, GA_ROOT );
812
813     if (!(dlgInfo = DIALOG_get_info( hwnd ))) return -1;
814
815     if (!(dlgInfo->flags & DF_END)) /* was EndDialog called in WM_INITDIALOG ? */
816     {
817         ShowWindow( hwnd, SW_SHOW );
818         for (;;)
819         {
820             if (!(GetWindowLongW( hwnd, GWL_STYLE ) & DS_NOIDLEMSG))
821             {
822                 if (!PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ))
823                 {
824                     /* No message present -> send ENTERIDLE and wait */
825                     SendMessageW( ownerMsg, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)hwnd );
826                     if (!GetMessageW( &msg, 0, 0, 0 )) break;
827                 }
828             }
829             else if (!GetMessageW( &msg, 0, 0, 0 )) break;
830
831             if (!IsWindow( hwnd )) return -1;
832             if (!(dlgInfo->flags & DF_END) && !IsDialogMessageW( hwnd, &msg))
833             {
834                 TranslateMessage( &msg );
835                 DispatchMessageW( &msg );
836             }
837             if (dlgInfo->flags & DF_END) break;
838         }
839     }
840     if (dlgInfo->flags & DF_OWNERENABLED) DIALOG_EnableOwner( owner );
841     retval = dlgInfo->idResult;
842     DestroyWindow( hwnd );
843     return retval;
844 }
845
846
847 /***********************************************************************
848  *              DialogBoxParamA (USER32.@)
849  */
850 INT_PTR WINAPI DialogBoxParamA( HINSTANCE hInst, LPCSTR name,
851                                 HWND owner, DLGPROC dlgProc, LPARAM param )
852 {
853     HWND hwnd;
854     HRSRC hrsrc;
855     LPCDLGTEMPLATEA ptr;
856
857     if (!(hrsrc = FindResourceA( hInst, name, RT_DIALOGA ))) return 0;
858     if (!(ptr = (LPCDLGTEMPLATEA)LoadResource(hInst, hrsrc))) return 0;
859     hwnd = DIALOG_CreateIndirect( hInst, ptr, owner, dlgProc, param, FALSE, TRUE );
860     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
861     return -1;
862 }
863
864
865 /***********************************************************************
866  *              DialogBoxParamW (USER32.@)
867  */
868 INT_PTR WINAPI DialogBoxParamW( HINSTANCE hInst, LPCWSTR name,
869                                 HWND owner, DLGPROC dlgProc, LPARAM param )
870 {
871     HWND hwnd;
872     HRSRC hrsrc;
873     LPCDLGTEMPLATEW ptr;
874
875     if (!(hrsrc = FindResourceW( hInst, name, RT_DIALOGW ))) return 0;
876     if (!(ptr = (LPCDLGTEMPLATEW)LoadResource(hInst, hrsrc))) return 0;
877     hwnd = DIALOG_CreateIndirect( hInst, ptr, owner, dlgProc, param, TRUE, TRUE );
878     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
879     return -1;
880 }
881
882
883 /***********************************************************************
884  *              DialogBoxIndirectParamAorW (USER32.@)
885  */
886 INT_PTR WINAPI DialogBoxIndirectParamAorW( HINSTANCE hInstance, LPCVOID template,
887                                            HWND owner, DLGPROC dlgProc,
888                                            LPARAM param, DWORD flags )
889 {
890     HWND hwnd = DIALOG_CreateIndirect( hInstance, template, owner, dlgProc, param, !flags, TRUE );
891     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
892     return -1;
893 }
894
895 /***********************************************************************
896  *              DialogBoxIndirectParamA (USER32.@)
897  */
898 INT_PTR WINAPI DialogBoxIndirectParamA(HINSTANCE hInstance, LPCDLGTEMPLATEA template,
899                                        HWND owner, DLGPROC dlgProc, LPARAM param )
900 {
901     return DialogBoxIndirectParamAorW( hInstance, template, owner, dlgProc, param, 2 );
902 }
903
904
905 /***********************************************************************
906  *              DialogBoxIndirectParamW (USER32.@)
907  */
908 INT_PTR WINAPI DialogBoxIndirectParamW(HINSTANCE hInstance, LPCDLGTEMPLATEW template,
909                                        HWND owner, DLGPROC dlgProc, LPARAM param )
910 {
911     return DialogBoxIndirectParamAorW( hInstance, template, owner, dlgProc, param, 0 );
912 }
913
914 /***********************************************************************
915  *              EndDialog (USER32.@)
916  */
917 BOOL WINAPI EndDialog( HWND hwnd, INT_PTR retval )
918 {
919     BOOL wasEnabled = TRUE;
920     DIALOGINFO * dlgInfo;
921     HWND owner;
922
923     TRACE("%p %d\n", hwnd, retval );
924
925     if (!(dlgInfo = DIALOG_get_info( hwnd )))
926     {
927         ERR("got invalid window handle (%p); buggy app !?\n", hwnd);
928         return FALSE;
929     }
930     dlgInfo->idResult = retval;
931     dlgInfo->flags |= DF_END;
932     wasEnabled = (dlgInfo->flags & DF_OWNERENABLED);
933
934     if (wasEnabled && (owner = GetWindow( hwnd, GW_OWNER )))
935         DIALOG_EnableOwner( owner );
936
937     /* Windows sets the focus to the dialog itself in EndDialog */
938
939     if (IsChild(hwnd, GetFocus()))
940        SetFocus( hwnd );
941
942     /* Don't have to send a ShowWindow(SW_HIDE), just do
943        SetWindowPos with SWP_HIDEWINDOW as done in Windows */
944
945     SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE
946                  | SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW);
947
948     /* unblock dialog loop */
949     PostMessageA(hwnd, WM_NULL, 0, 0);
950     return TRUE;
951 }
952
953
954 /***********************************************************************
955  *           DIALOG_IsAccelerator
956  */
957 static BOOL DIALOG_IsAccelerator( HWND hwnd, HWND hwndDlg, WPARAM wParam )
958 {
959     HWND hwndControl = hwnd;
960     HWND hwndNext;
961     INT dlgCode;
962     WCHAR buffer[128];
963
964     do
965     {
966         DWORD style = GetWindowLongW( hwndControl, GWL_STYLE );
967         if ((style & (WS_VISIBLE | WS_DISABLED)) == WS_VISIBLE)
968         {
969             dlgCode = SendMessageA( hwndControl, WM_GETDLGCODE, 0, 0 );
970             if ( (dlgCode & (DLGC_BUTTON | DLGC_STATIC)) &&
971                  GetWindowTextW( hwndControl, buffer, sizeof(buffer)/sizeof(WCHAR) ))
972             {
973                 /* find the accelerator key */
974                 LPWSTR p = buffer - 2;
975
976                 do
977                 {
978                     p = strchrW( p + 2, '&' );
979                 }
980                 while (p != NULL && p[1] == '&');
981
982                 /* and check if it's the one we're looking for */
983                 if (p != NULL && toupperW( p[1] ) == toupperW( wParam ) )
984                 {
985                     if ((dlgCode & DLGC_STATIC) || (style & 0x0f) == BS_GROUPBOX )
986                     {
987                         /* set focus to the control */
988                         SendMessageA( hwndDlg, WM_NEXTDLGCTL, (WPARAM)hwndControl, 1);
989                         /* and bump it on to next */
990                         SendMessageA( hwndDlg, WM_NEXTDLGCTL, 0, 0);
991                     }
992                     else if (dlgCode & DLGC_BUTTON)
993                     {
994                         /* send BM_CLICK message to the control */
995                         SendMessageA( hwndControl, BM_CLICK, 0, 0 );
996                     }
997                     return TRUE;
998                 }
999             }
1000             hwndNext = GetWindow( hwndControl, GW_CHILD );
1001         }
1002         else hwndNext = 0;
1003
1004         if (!hwndNext) hwndNext = GetWindow( hwndControl, GW_HWNDNEXT );
1005
1006         while (!hwndNext && hwndControl)
1007         {
1008             hwndControl = GetParent( hwndControl );
1009             if (hwndControl == hwndDlg)
1010             {
1011                 if(hwnd==hwndDlg)   /* prevent endless loop */
1012                 {
1013                     hwndNext=hwnd;
1014                     break;
1015                 }
1016                 hwndNext = GetWindow( hwndDlg, GW_CHILD );
1017             }
1018             else
1019                 hwndNext = GetWindow( hwndControl, GW_HWNDNEXT );
1020         }
1021         hwndControl = hwndNext;
1022     }
1023     while (hwndControl && (hwndControl != hwnd));
1024
1025     return FALSE;
1026 }
1027
1028 /***********************************************************************
1029  *           DIALOG_FindMsgDestination
1030  *
1031  * The messages that IsDialogMessage sends may not go to the dialog
1032  * calling IsDialogMessage if that dialog is a child, and it has the
1033  * DS_CONTROL style set.
1034  * We propagate up until we hit one that does not have DS_CONTROL, or
1035  * whose parent is not a dialog.
1036  *
1037  * This is undocumented behaviour.
1038  */
1039 static HWND DIALOG_FindMsgDestination( HWND hwndDlg )
1040 {
1041     while (GetWindowLongA(hwndDlg, GWL_STYLE) & DS_CONTROL)
1042     {
1043         WND *pParent;
1044         HWND hParent = GetParent(hwndDlg);
1045         if (!hParent) break;
1046
1047         pParent = WIN_FindWndPtr(hParent);
1048         if (!pParent) break;
1049
1050         if (!(pParent->flags & WIN_ISDIALOG))
1051         {
1052             WIN_ReleaseWndPtr(pParent);
1053             break;
1054         }
1055         WIN_ReleaseWndPtr(pParent);
1056
1057         hwndDlg = hParent;
1058     }
1059
1060     return hwndDlg;
1061 }
1062
1063 /***********************************************************************
1064  *              IsDialogMessageW (USER32.@)
1065  */
1066 BOOL WINAPI IsDialogMessageW( HWND hwndDlg, LPMSG msg )
1067 {
1068     INT dlgCode = 0;
1069
1070     if (CallMsgFilterW( msg, MSGF_DIALOGBOX )) return TRUE;
1071
1072     hwndDlg = WIN_GetFullHandle( hwndDlg );
1073     if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd )) return FALSE;
1074
1075     hwndDlg = DIALOG_FindMsgDestination(hwndDlg);
1076
1077     switch(msg->message)
1078     {
1079     case WM_KEYDOWN:
1080         dlgCode = SendMessageW( msg->hwnd, WM_GETDLGCODE, msg->wParam, (LPARAM)msg );
1081         if (dlgCode & DLGC_WANTMESSAGE) break;
1082
1083         switch(msg->wParam)
1084         {
1085         case VK_TAB:
1086             if (!(dlgCode & DLGC_WANTTAB))
1087             {
1088                 SendMessageW( hwndDlg, WM_NEXTDLGCTL, (GetKeyState(VK_SHIFT) & 0x8000), 0 );
1089                 return TRUE;
1090             }
1091             break;
1092
1093         case VK_RIGHT:
1094         case VK_DOWN:
1095         case VK_LEFT:
1096         case VK_UP:
1097             if (!(dlgCode & DLGC_WANTARROWS))
1098             {
1099                 BOOL fPrevious = (msg->wParam == VK_LEFT || msg->wParam == VK_UP);
1100                 HWND hwndNext = GetNextDlgGroupItem (hwndDlg, GetFocus(), fPrevious );
1101                 SendMessageW( hwndDlg, WM_NEXTDLGCTL, (WPARAM)hwndNext, 1 );
1102                 return TRUE;
1103             }
1104             break;
1105
1106         case VK_CANCEL:
1107         case VK_ESCAPE:
1108             SendMessageW( hwndDlg, WM_COMMAND, IDCANCEL, (LPARAM)GetDlgItem( hwndDlg, IDCANCEL ) );
1109             return TRUE;
1110
1111         case VK_EXECUTE:
1112         case VK_RETURN:
1113             {
1114                 DWORD dw = SendMessageW( hwndDlg, DM_GETDEFID, 0, 0 );
1115                 if (HIWORD(dw) == DC_HASDEFID)
1116                 {
1117                     SendMessageW( hwndDlg, WM_COMMAND, MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
1118                                     (LPARAM)GetDlgItem(hwndDlg, LOWORD(dw)));
1119                 }
1120                 else
1121                 {
1122                     SendMessageW( hwndDlg, WM_COMMAND, IDOK, (LPARAM)GetDlgItem( hwndDlg, IDOK ) );
1123
1124                 }
1125             }
1126             return TRUE;
1127         }
1128         break;
1129
1130     case WM_CHAR:
1131         dlgCode = SendMessageW( msg->hwnd, WM_GETDLGCODE, msg->wParam, (LPARAM)msg );
1132         if (dlgCode & (DLGC_WANTCHARS|DLGC_WANTMESSAGE)) break;
1133         if (msg->wParam == '\t' && (dlgCode & DLGC_WANTTAB)) break;
1134         /* drop through */
1135
1136     case WM_SYSCHAR:
1137         if (DIALOG_IsAccelerator( WIN_GetFullHandle(msg->hwnd), hwndDlg, msg->wParam ))
1138         {
1139             /* don't translate or dispatch */
1140             return TRUE;
1141         }
1142         break;
1143     }
1144
1145     TranslateMessage( msg );
1146     DispatchMessageW( msg );
1147     return TRUE;
1148 }
1149
1150
1151 /***********************************************************************
1152  *              GetDlgCtrlID (USER32.@)
1153  */
1154 INT WINAPI GetDlgCtrlID( HWND hwnd )
1155 {
1156     return GetWindowLongW( hwnd, GWL_ID );
1157 }
1158
1159
1160 /***********************************************************************
1161  *              GetDlgItem (USER32.@)
1162  */
1163 HWND WINAPI GetDlgItem( HWND hwndDlg, INT id )
1164 {
1165     int i;
1166     HWND *list = WIN_ListChildren( hwndDlg );
1167     HWND ret = 0;
1168
1169     if (!list) return 0;
1170
1171     for (i = 0; list[i]; i++) if (GetWindowLongW( list[i], GWL_ID ) == id) break;
1172     ret = list[i];
1173     HeapFree( GetProcessHeap(), 0, list );
1174     return ret;
1175 }
1176
1177
1178 /*******************************************************************
1179  *              SendDlgItemMessageA (USER32.@)
1180  */
1181 LRESULT WINAPI SendDlgItemMessageA( HWND hwnd, INT id, UINT msg,
1182                                       WPARAM wParam, LPARAM lParam )
1183 {
1184     HWND hwndCtrl = GetDlgItem( hwnd, id );
1185     if (hwndCtrl) return SendMessageA( hwndCtrl, msg, wParam, lParam );
1186     else return 0;
1187 }
1188
1189
1190 /*******************************************************************
1191  *              SendDlgItemMessageW (USER32.@)
1192  */
1193 LRESULT WINAPI SendDlgItemMessageW( HWND hwnd, INT id, UINT msg,
1194                                       WPARAM wParam, LPARAM lParam )
1195 {
1196     HWND hwndCtrl = GetDlgItem( hwnd, id );
1197     if (hwndCtrl) return SendMessageW( hwndCtrl, msg, wParam, lParam );
1198     else return 0;
1199 }
1200
1201
1202 /*******************************************************************
1203  *              SetDlgItemTextA (USER32.@)
1204  */
1205 BOOL WINAPI SetDlgItemTextA( HWND hwnd, INT id, LPCSTR lpString )
1206 {
1207     return SendDlgItemMessageA( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1208 }
1209
1210
1211 /*******************************************************************
1212  *              SetDlgItemTextW (USER32.@)
1213  */
1214 BOOL WINAPI SetDlgItemTextW( HWND hwnd, INT id, LPCWSTR lpString )
1215 {
1216     return SendDlgItemMessageW( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1217 }
1218
1219
1220 /***********************************************************************
1221  *              GetDlgItemTextA (USER32.@)
1222  */
1223 INT WINAPI GetDlgItemTextA( HWND hwnd, INT id, LPSTR str, UINT len )
1224 {
1225     return (INT)SendDlgItemMessageA( hwnd, id, WM_GETTEXT,
1226                                          len, (LPARAM)str );
1227 }
1228
1229
1230 /***********************************************************************
1231  *              GetDlgItemTextW (USER32.@)
1232  */
1233 INT WINAPI GetDlgItemTextW( HWND hwnd, INT id, LPWSTR str, UINT len )
1234 {
1235     return (INT)SendDlgItemMessageW( hwnd, id, WM_GETTEXT,
1236                                          len, (LPARAM)str );
1237 }
1238
1239
1240 /*******************************************************************
1241  *              SetDlgItemInt (USER32.@)
1242  */
1243 BOOL WINAPI SetDlgItemInt( HWND hwnd, INT id, UINT value,
1244                              BOOL fSigned )
1245 {
1246     char str[20];
1247
1248     if (fSigned) sprintf( str, "%d", (INT)value );
1249     else sprintf( str, "%u", value );
1250     SendDlgItemMessageA( hwnd, id, WM_SETTEXT, 0, (LPARAM)str );
1251     return TRUE;
1252 }
1253
1254
1255 /***********************************************************************
1256  *              GetDlgItemInt (USER32.@)
1257  */
1258 UINT WINAPI GetDlgItemInt( HWND hwnd, INT id, BOOL *translated,
1259                                BOOL fSigned )
1260 {
1261     char str[30];
1262     char * endptr;
1263     long result = 0;
1264
1265     if (translated) *translated = FALSE;
1266     if (!SendDlgItemMessageA(hwnd, id, WM_GETTEXT, sizeof(str), (LPARAM)str))
1267         return 0;
1268     if (fSigned)
1269     {
1270         result = strtol( str, &endptr, 10 );
1271         if (!endptr || (endptr == str))  /* Conversion was unsuccessful */
1272             return 0;
1273         if (((result == LONG_MIN) || (result == LONG_MAX)) && (errno==ERANGE))
1274             return 0;
1275     }
1276     else
1277     {
1278         result = strtoul( str, &endptr, 10 );
1279         if (!endptr || (endptr == str))  /* Conversion was unsuccessful */
1280             return 0;
1281         if ((result == ULONG_MAX) && (errno == ERANGE)) return 0;
1282     }
1283     if (translated) *translated = TRUE;
1284     return (UINT)result;
1285 }
1286
1287
1288 /***********************************************************************
1289  *              CheckDlgButton (USER32.@)
1290  */
1291 BOOL WINAPI CheckDlgButton( HWND hwnd, INT id, UINT check )
1292 {
1293     SendDlgItemMessageA( hwnd, id, BM_SETCHECK, check, 0 );
1294     return TRUE;
1295 }
1296
1297
1298 /***********************************************************************
1299  *              IsDlgButtonChecked (USER32.@)
1300  */
1301 UINT WINAPI IsDlgButtonChecked( HWND hwnd, UINT id )
1302 {
1303     return (UINT)SendDlgItemMessageA( hwnd, id, BM_GETCHECK, 0, 0 );
1304 }
1305
1306
1307 /***********************************************************************
1308  *           CheckRB
1309  *
1310  * Callback function used to check/uncheck radio buttons that fall
1311  * within a specific range of IDs.
1312  */
1313 static BOOL CALLBACK CheckRB(HWND hwndChild, LPARAM lParam)
1314 {
1315     LONG lChildID = GetWindowLongA(hwndChild, GWL_ID);
1316     RADIOGROUP *lpRadioGroup = (RADIOGROUP *) lParam;
1317
1318     if ((lChildID >= lpRadioGroup->firstID) &&
1319         (lChildID <= lpRadioGroup->lastID))
1320     {
1321         if (lChildID == lpRadioGroup->checkID)
1322         {
1323             SendMessageA(hwndChild, BM_SETCHECK, BST_CHECKED, 0);
1324         }
1325         else
1326         {
1327             SendMessageA(hwndChild, BM_SETCHECK, BST_UNCHECKED, 0);
1328         }
1329     }
1330
1331     return TRUE;
1332 }
1333
1334
1335 /***********************************************************************
1336  *              CheckRadioButton (USER32.@)
1337  */
1338 BOOL WINAPI CheckRadioButton( HWND hwndDlg, UINT firstID,
1339                               UINT lastID, UINT checkID )
1340 {
1341     RADIOGROUP radioGroup;
1342
1343     /* perform bounds checking for a radio button group */
1344     radioGroup.firstID = min(min(firstID, lastID), checkID);
1345     radioGroup.lastID = max(max(firstID, lastID), checkID);
1346     radioGroup.checkID = checkID;
1347
1348     return EnumChildWindows(hwndDlg, (WNDENUMPROC)CheckRB,
1349                             (LPARAM)&radioGroup);
1350 }
1351
1352
1353 /***********************************************************************
1354  *              GetDialogBaseUnits (USER.243)
1355  *              GetDialogBaseUnits (USER32.@)
1356  */
1357 DWORD WINAPI GetDialogBaseUnits(void)
1358 {
1359     return MAKELONG( xBaseUnit, yBaseUnit );
1360 }
1361
1362
1363 /***********************************************************************
1364  *              MapDialogRect (USER32.@)
1365  */
1366 BOOL WINAPI MapDialogRect( HWND hwnd, LPRECT rect )
1367 {
1368     DIALOGINFO * dlgInfo;
1369     if (!(dlgInfo = DIALOG_get_info( hwnd ))) return FALSE;
1370     rect->left   = MulDiv(rect->left, dlgInfo->xBaseUnit, 4);
1371     rect->right  = MulDiv(rect->right, dlgInfo->xBaseUnit, 4);
1372     rect->top    = MulDiv(rect->top, dlgInfo->yBaseUnit, 8);
1373     rect->bottom = MulDiv(rect->bottom, dlgInfo->yBaseUnit, 8);
1374     return TRUE;
1375 }
1376
1377
1378 /***********************************************************************
1379  *              GetNextDlgGroupItem (USER32.@)
1380  */
1381 HWND WINAPI GetNextDlgGroupItem( HWND hwndDlg, HWND hwndCtrl, BOOL fPrevious )
1382 {
1383     HWND hwnd, retvalue;
1384
1385     hwndDlg = WIN_GetFullHandle( hwndDlg );
1386     hwndCtrl = WIN_GetFullHandle( hwndCtrl );
1387
1388     if(hwndCtrl)
1389     {
1390         /* if the hwndCtrl is the child of the control in the hwndDlg,
1391          * then the hwndDlg has to be the parent of the hwndCtrl */
1392         if(GetParent(hwndCtrl) != hwndDlg && GetParent(GetParent(hwndCtrl)) == hwndDlg)
1393             hwndDlg = GetParent(hwndCtrl);
1394     }
1395
1396     if (hwndCtrl)
1397     {
1398         /* Make sure hwndCtrl is a top-level child */
1399         HWND parent = GetParent( hwndCtrl );
1400         while (parent && parent != hwndDlg) parent = GetParent(parent);
1401         if (parent != hwndDlg) return 0;
1402     }
1403     else
1404     {
1405         /* No ctrl specified -> start from the beginning */
1406         if (!(hwndCtrl = GetWindow( hwndDlg, GW_CHILD ))) return 0;
1407         if (fPrevious) hwndCtrl = GetWindow( hwndCtrl, GW_HWNDLAST );
1408     }
1409
1410     retvalue = hwndCtrl;
1411     hwnd = GetWindow( hwndCtrl, GW_HWNDNEXT );
1412     while (1)
1413     {
1414         if (!hwnd || (GetWindowLongW( hwnd, GWL_STYLE ) & WS_GROUP))
1415         {
1416             /* Wrap-around to the beginning of the group */
1417             HWND tmp;
1418
1419             hwnd = GetWindow( hwndDlg, GW_CHILD );
1420             for (tmp = hwnd; tmp; tmp = GetWindow( tmp, GW_HWNDNEXT ) )
1421             {
1422                 if (GetWindowLongW( tmp, GWL_STYLE ) & WS_GROUP) hwnd = tmp;
1423                 if (tmp == hwndCtrl) break;
1424             }
1425         }
1426         if (hwnd == hwndCtrl) break;
1427         if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE)
1428         {
1429             retvalue = hwnd;
1430             if (!fPrevious) break;
1431         }
1432         hwnd = GetWindow( hwnd, GW_HWNDNEXT );
1433     }
1434     return retvalue;
1435 }
1436
1437
1438 /***********************************************************************
1439  *           DIALOG_GetNextTabItem
1440  *
1441  * Helper for GetNextDlgTabItem
1442  */
1443 static HWND DIALOG_GetNextTabItem( HWND hwndMain, HWND hwndDlg, HWND hwndCtrl, BOOL fPrevious )
1444 {
1445     LONG dsStyle;
1446     LONG exStyle;
1447     UINT wndSearch = fPrevious ? GW_HWNDPREV : GW_HWNDNEXT;
1448     HWND retWnd = 0;
1449     HWND hChildFirst = 0;
1450
1451     if(!hwndCtrl)
1452     {
1453         hChildFirst = GetWindow(hwndDlg,GW_CHILD);
1454         if(fPrevious) hChildFirst = GetWindow(hChildFirst,GW_HWNDLAST);
1455     }
1456     else if (IsChild( hwndMain, hwndCtrl ))
1457     {
1458         hChildFirst = GetWindow(hwndCtrl,wndSearch);
1459         if(!hChildFirst)
1460         {
1461             if(GetParent(hwndCtrl) != hwndMain)
1462                 hChildFirst = GetWindow(GetParent(hwndCtrl),wndSearch);
1463             else
1464             {
1465                 if(fPrevious)
1466                     hChildFirst = GetWindow(hwndCtrl,GW_HWNDLAST);
1467                 else
1468                     hChildFirst = GetWindow(hwndCtrl,GW_HWNDFIRST);
1469             }
1470         }
1471     }
1472
1473     while(hChildFirst)
1474     {
1475         BOOL bCtrl = FALSE;
1476         while(hChildFirst)
1477         {
1478             dsStyle = GetWindowLongA(hChildFirst,GWL_STYLE);
1479             exStyle = GetWindowLongA(hChildFirst,GWL_EXSTYLE);
1480             if( (dsStyle & DS_CONTROL || exStyle & WS_EX_CONTROLPARENT) && (dsStyle & WS_VISIBLE) && !(dsStyle & WS_DISABLED))
1481             {
1482                 bCtrl=TRUE;
1483                 break;
1484             }
1485             else if( (dsStyle & WS_TABSTOP) && (dsStyle & WS_VISIBLE) && !(dsStyle & WS_DISABLED))
1486                 break;
1487             hChildFirst = GetWindow(hChildFirst,wndSearch);
1488         }
1489         if(hChildFirst)
1490         {
1491             if(bCtrl)
1492                 retWnd = DIALOG_GetNextTabItem(hwndMain,hChildFirst,NULL,fPrevious );
1493             else
1494                 retWnd = hChildFirst;
1495         }
1496         if(retWnd) break;
1497         hChildFirst = GetWindow(hChildFirst,wndSearch);
1498     }
1499     if(!retWnd && hwndCtrl)
1500     {
1501         HWND hParent = GetParent(hwndCtrl);
1502         while(hParent)
1503         {
1504             if(hParent == hwndMain) break;
1505             retWnd = DIALOG_GetNextTabItem(hwndMain,GetParent(hParent),hParent,fPrevious );
1506             if(retWnd) break;
1507             hParent = GetParent(hParent);
1508         }
1509         if(!retWnd)
1510             retWnd = DIALOG_GetNextTabItem(hwndMain,hwndMain,NULL,fPrevious );
1511     }
1512     return retWnd;
1513 }
1514
1515 /***********************************************************************
1516  *              GetNextDlgTabItem (USER32.@)
1517  */
1518 HWND WINAPI GetNextDlgTabItem( HWND hwndDlg, HWND hwndCtrl,
1519                                    BOOL fPrevious )
1520 {
1521     hwndDlg = WIN_GetFullHandle( hwndDlg );
1522     hwndCtrl = WIN_GetFullHandle( hwndCtrl );
1523     return DIALOG_GetNextTabItem(hwndDlg,hwndDlg,hwndCtrl,fPrevious);
1524 }
1525
1526 /**********************************************************************
1527  *           DIALOG_DlgDirSelect
1528  *
1529  * Helper function for DlgDirSelect*
1530  */
1531 static BOOL DIALOG_DlgDirSelect( HWND hwnd, LPSTR str, INT len,
1532                                  INT id, BOOL unicode, BOOL combo )
1533 {
1534     char *buffer, *ptr;
1535     INT item, size;
1536     BOOL ret;
1537     HWND listbox = GetDlgItem( hwnd, id );
1538
1539     TRACE("%p '%s' %d\n", hwnd, str, id );
1540     if (!listbox) return FALSE;
1541
1542     item = SendMessageA(listbox, combo ? CB_GETCURSEL : LB_GETCURSEL, 0, 0 );
1543     if (item == LB_ERR) return FALSE;
1544     size = SendMessageA(listbox, combo ? CB_GETLBTEXTLEN : LB_GETTEXTLEN, 0, 0 );
1545     if (size == LB_ERR) return FALSE;
1546
1547     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size+1 ))) return FALSE;
1548
1549     SendMessageA( listbox, combo ? CB_GETLBTEXT : LB_GETTEXT, item, (LPARAM)buffer );
1550
1551     if ((ret = (buffer[0] == '[')))  /* drive or directory */
1552     {
1553         if (buffer[1] == '-')  /* drive */
1554         {
1555             buffer[3] = ':';
1556             buffer[4] = 0;
1557             ptr = buffer + 2;
1558         }
1559         else
1560         {
1561             buffer[strlen(buffer)-1] = '\\';
1562             ptr = buffer + 1;
1563         }
1564     }
1565     else ptr = buffer;
1566
1567     if (unicode)
1568     {
1569         if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, ptr, -1, (LPWSTR)str, len ))
1570             ((LPWSTR)str)[len-1] = 0;
1571     }
1572     else lstrcpynA( str, ptr, len );
1573     HeapFree( GetProcessHeap(), 0, buffer );
1574     TRACE("Returning %d '%s'\n", ret, str );
1575     return ret;
1576 }
1577
1578
1579 /**********************************************************************
1580  *          DIALOG_DlgDirList
1581  *
1582  * Helper function for DlgDirList*
1583  */
1584 static INT DIALOG_DlgDirList( HWND hDlg, LPSTR spec, INT idLBox,
1585                                 INT idStatic, UINT attrib, BOOL combo )
1586 {
1587     HWND hwnd;
1588     LPSTR orig_spec = spec;
1589
1590 #define SENDMSG(msg,wparam,lparam) \
1591     ((attrib & DDL_POSTMSGS) ? PostMessageA( hwnd, msg, wparam, lparam ) \
1592                              : SendMessageA( hwnd, msg, wparam, lparam ))
1593
1594     TRACE("%p '%s' %d %d %04x\n",
1595           hDlg, spec ? spec : "NULL", idLBox, idStatic, attrib );
1596
1597     /* If the path exists and is a directory, chdir to it */
1598     if (!spec || !spec[0] || SetCurrentDirectoryA( spec )) spec = "*.*";
1599     else
1600     {
1601         char *p, *p2;
1602         p = spec;
1603         if ((p2 = strrchr( p, '\\' ))) p = p2;
1604         if ((p2 = strrchr( p, '/' ))) p = p2;
1605         if (p != spec)
1606         {
1607             char sep = *p;
1608             *p = 0;
1609             if (!SetCurrentDirectoryA( spec ))
1610             {
1611                 *p = sep;  /* Restore the original spec */
1612                 return FALSE;
1613             }
1614             spec = p + 1;
1615         }
1616     }
1617
1618     TRACE( "mask=%s\n", spec );
1619
1620     if (idLBox && ((hwnd = GetDlgItem( hDlg, idLBox )) != 0))
1621     {
1622         SENDMSG( combo ? CB_RESETCONTENT : LB_RESETCONTENT, 0, 0 );
1623         if (attrib & DDL_DIRECTORY)
1624         {
1625             if (!(attrib & DDL_EXCLUSIVE))
1626             {
1627                 if (SENDMSG( combo ? CB_DIR : LB_DIR,
1628                              attrib & ~(DDL_DIRECTORY | DDL_DRIVES),
1629                              (LPARAM)spec ) == LB_ERR)
1630                     return FALSE;
1631             }
1632             if (SENDMSG( combo ? CB_DIR : LB_DIR,
1633                        (attrib & (DDL_DIRECTORY | DDL_DRIVES)) | DDL_EXCLUSIVE,
1634                          (LPARAM)"*.*" ) == LB_ERR)
1635                 return FALSE;
1636         }
1637         else
1638         {
1639             if (SENDMSG( combo ? CB_DIR : LB_DIR, attrib,
1640                          (LPARAM)spec ) == LB_ERR)
1641                 return FALSE;
1642         }
1643     }
1644
1645     if (idStatic && ((hwnd = GetDlgItem( hDlg, idStatic )) != 0))
1646     {
1647         char temp[MAX_PATH];
1648         GetCurrentDirectoryA( sizeof(temp), temp );
1649         CharLowerA( temp );
1650         /* Can't use PostMessage() here, because the string is on the stack */
1651         SetDlgItemTextA( hDlg, idStatic, temp );
1652     }
1653
1654     if (orig_spec && (spec != orig_spec))
1655     {
1656         /* Update the original file spec */
1657         char *p = spec;
1658         while ((*orig_spec++ = *p++));
1659     }
1660
1661     return TRUE;
1662 #undef SENDMSG
1663 }
1664
1665
1666 /**********************************************************************
1667  *          DIALOG_DlgDirListW
1668  *
1669  * Helper function for DlgDirList*W
1670  */
1671 static INT DIALOG_DlgDirListW( HWND hDlg, LPWSTR spec, INT idLBox,
1672                                  INT idStatic, UINT attrib, BOOL combo )
1673 {
1674     if (spec)
1675     {
1676         LPSTR specA = HEAP_strdupWtoA( GetProcessHeap(), 0, spec );
1677         INT ret = DIALOG_DlgDirList( hDlg, specA, idLBox, idStatic,
1678                                        attrib, combo );
1679         MultiByteToWideChar( CP_ACP, 0, specA, -1, spec, 0x7fffffff );
1680         HeapFree( GetProcessHeap(), 0, specA );
1681         return ret;
1682     }
1683     return DIALOG_DlgDirList( hDlg, NULL, idLBox, idStatic, attrib, combo );
1684 }
1685
1686
1687 /**********************************************************************
1688  *              DlgDirSelectExA (USER32.@)
1689  */
1690 BOOL WINAPI DlgDirSelectExA( HWND hwnd, LPSTR str, INT len, INT id )
1691 {
1692     return DIALOG_DlgDirSelect( hwnd, str, len, id, FALSE, FALSE );
1693 }
1694
1695
1696 /**********************************************************************
1697  *              DlgDirSelectExW (USER32.@)
1698  */
1699 BOOL WINAPI DlgDirSelectExW( HWND hwnd, LPWSTR str, INT len, INT id )
1700 {
1701     return DIALOG_DlgDirSelect( hwnd, (LPSTR)str, len, id, TRUE, FALSE );
1702 }
1703
1704
1705 /**********************************************************************
1706  *              DlgDirSelectComboBoxExA (USER32.@)
1707  */
1708 BOOL WINAPI DlgDirSelectComboBoxExA( HWND hwnd, LPSTR str, INT len,
1709                                          INT id )
1710 {
1711     return DIALOG_DlgDirSelect( hwnd, str, len, id, FALSE, TRUE );
1712 }
1713
1714
1715 /**********************************************************************
1716  *              DlgDirSelectComboBoxExW (USER32.@)
1717  */
1718 BOOL WINAPI DlgDirSelectComboBoxExW( HWND hwnd, LPWSTR str, INT len,
1719                                          INT id)
1720 {
1721     return DIALOG_DlgDirSelect( hwnd, (LPSTR)str, len, id, TRUE, TRUE );
1722 }
1723
1724
1725 /**********************************************************************
1726  *              DlgDirListA (USER32.@)
1727  */
1728 INT WINAPI DlgDirListA( HWND hDlg, LPSTR spec, INT idLBox,
1729                             INT idStatic, UINT attrib )
1730 {
1731     return DIALOG_DlgDirList( hDlg, spec, idLBox, idStatic, attrib, FALSE );
1732 }
1733
1734
1735 /**********************************************************************
1736  *              DlgDirListW (USER32.@)
1737  */
1738 INT WINAPI DlgDirListW( HWND hDlg, LPWSTR spec, INT idLBox,
1739                             INT idStatic, UINT attrib )
1740 {
1741     return DIALOG_DlgDirListW( hDlg, spec, idLBox, idStatic, attrib, FALSE );
1742 }
1743
1744
1745 /**********************************************************************
1746  *              DlgDirListComboBoxA (USER32.@)
1747  */
1748 INT WINAPI DlgDirListComboBoxA( HWND hDlg, LPSTR spec, INT idCBox,
1749                                     INT idStatic, UINT attrib )
1750 {
1751     return DIALOG_DlgDirList( hDlg, spec, idCBox, idStatic, attrib, TRUE );
1752 }
1753
1754
1755 /**********************************************************************
1756  *              DlgDirListComboBoxW (USER32.@)
1757  */
1758 INT WINAPI DlgDirListComboBoxW( HWND hDlg, LPWSTR spec, INT idCBox,
1759                                     INT idStatic, UINT attrib )
1760 {
1761     return DIALOG_DlgDirListW( hDlg, spec, idCBox, idStatic, attrib, TRUE );
1762 }