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