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