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