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