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