Turn on detectable autorepeat if the X Keyboard Extension is
[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  *              CreateDialogParam16 (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  *              CreateDialogIndirectParam16 (USER.242) (USER32.@)
985  */
986 HWND16 WINAPI CreateDialogIndirectParam16( HINSTANCE16 hInst,
987                                            LPCVOID dlgTemplate,
988                                            HWND16 owner, DLGPROC16 dlgProc,
989                                            LPARAM param )
990 {
991     return DIALOG_CreateIndirect( hInst, dlgTemplate, FALSE, owner,
992                                   dlgProc, param, WIN_PROC_16, FALSE );
993 }
994
995
996 /***********************************************************************
997  *              CreateDialogIndirectParamA (USER32.@)
998  */
999 HWND WINAPI CreateDialogIndirectParamA( HINSTANCE hInst,
1000                                             LPCVOID dlgTemplate,
1001                                             HWND owner, DLGPROC dlgProc,
1002                                             LPARAM param )
1003 {
1004     return DIALOG_CreateIndirect( hInst, dlgTemplate, TRUE, owner,
1005                                   (DLGPROC16)dlgProc, param, WIN_PROC_32A, FALSE );
1006 }
1007
1008 /***********************************************************************
1009  *              CreateDialogIndirectParamAorW (USER32.@)
1010  */
1011 HWND WINAPI CreateDialogIndirectParamAorW( HINSTANCE hInst,
1012                                             LPCVOID dlgTemplate,
1013                                             HWND owner, DLGPROC dlgProc,
1014                                             LPARAM param )
1015 {   FIXME("assume WIN_PROC_32W\n");
1016     return DIALOG_CreateIndirect( hInst, dlgTemplate, TRUE, owner,
1017                                   (DLGPROC16)dlgProc, param, WIN_PROC_32W, FALSE );
1018 }
1019
1020 /***********************************************************************
1021  *              CreateDialogIndirectParamW (USER32.@)
1022  */
1023 HWND WINAPI CreateDialogIndirectParamW( HINSTANCE hInst,
1024                                             LPCVOID dlgTemplate,
1025                                             HWND owner, DLGPROC dlgProc,
1026                                             LPARAM param )
1027 {
1028     return DIALOG_CreateIndirect( hInst, dlgTemplate, TRUE, owner,
1029                                   (DLGPROC16)dlgProc, param, WIN_PROC_32W, FALSE );
1030 }
1031
1032
1033 /***********************************************************************
1034  *           DIALOG_DoDialogBox
1035  */
1036 static INT DIALOG_DoDialogBox( HWND hwnd, HWND owner )
1037 {
1038     WND * wndPtr;
1039     DIALOGINFO * dlgInfo;
1040     MSG msg;
1041     INT retval;
1042     HWND ownerMsg = WIN_GetTopParent( owner );
1043
1044     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return -1;
1045     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
1046
1047     if (!(dlgInfo->flags & DF_END)) /* was EndDialog called in WM_INITDIALOG ? */
1048     {
1049         ShowWindow( hwnd, SW_SHOW );
1050         while (MSG_InternalGetMessage(QMSG_WIN32A, &msg, hwnd, ownerMsg, MSGF_DIALOGBOX, 
1051                                       PM_REMOVE, !(wndPtr->dwStyle & DS_NOIDLEMSG), NULL ))
1052         {
1053             if (!IsDialogMessageA( hwnd, &msg))
1054             {
1055                 TranslateMessage( &msg );
1056                 DispatchMessageA( &msg );
1057             }
1058             if (dlgInfo->flags & DF_END) break;
1059         }
1060     }
1061     DIALOG_EnableOwner( owner, (dlgInfo->flags & DF_OWNERENABLED) );
1062     retval = dlgInfo->idResult; 
1063     WIN_ReleaseWndPtr(wndPtr);
1064     DestroyWindow( hwnd );
1065     return retval;
1066 }
1067
1068
1069 /***********************************************************************
1070  *              DialogBox (USER.87)
1071  */
1072 INT16 WINAPI DialogBox16( HINSTANCE16 hInst, LPCSTR dlgTemplate,
1073                           HWND16 owner, DLGPROC16 dlgProc )
1074 {
1075     return DialogBoxParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
1076 }
1077
1078
1079 /***********************************************************************
1080  *              DialogBoxParam (USER.239)
1081  */
1082 INT16 WINAPI DialogBoxParam16( HINSTANCE16 hInst, LPCSTR template,
1083                                HWND16 owner, DLGPROC16 dlgProc, LPARAM param )
1084 {
1085     HWND16 hwnd = 0;
1086     HRSRC16 hRsrc;
1087     HGLOBAL16 hmem;
1088     LPCVOID data;
1089     int ret = -1;
1090
1091     if (!(hRsrc = FindResource16( hInst, template, RT_DIALOGA ))) return 0;
1092     if (!(hmem = LoadResource16( hInst, hRsrc ))) return 0;
1093     if (!(data = LockResource16( hmem ))) hwnd = 0;
1094     else hwnd = DIALOG_CreateIndirect( hInst, data, FALSE, owner,
1095                                   dlgProc, param, WIN_PROC_16, TRUE );
1096     if (hwnd)
1097         ret =(INT16)DIALOG_DoDialogBox( hwnd, owner );
1098     if (data) GlobalUnlock16( hmem );
1099     FreeResource16( hmem );
1100     return ret;
1101 }
1102
1103
1104 /***********************************************************************
1105  *              DialogBoxParamA (USER32.@)
1106  */
1107 INT WINAPI DialogBoxParamA( HINSTANCE hInst, LPCSTR name,
1108                                 HWND owner, DLGPROC dlgProc, LPARAM param )
1109 {
1110     HWND hwnd;
1111     HANDLE hrsrc = FindResourceA( hInst, name, RT_DIALOGA );
1112     if (!hrsrc) return 0;
1113     hwnd = DIALOG_CreateIndirect( hInst, (LPVOID)LoadResource(hInst, hrsrc),
1114                                   TRUE, owner,
1115                                   (DLGPROC16) dlgProc, param, WIN_PROC_32A, TRUE );
1116     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
1117     return -1;
1118 }
1119
1120
1121 /***********************************************************************
1122  *              DialogBoxParamW (USER32.@)
1123  */
1124 INT WINAPI DialogBoxParamW( HINSTANCE hInst, LPCWSTR name,
1125                                 HWND owner, DLGPROC dlgProc, LPARAM param )
1126 {
1127     HWND hwnd;
1128     HANDLE hrsrc = FindResourceW( hInst, name, RT_DIALOGW );
1129     if (!hrsrc) return 0;
1130     hwnd = DIALOG_CreateIndirect( hInst, (LPVOID)LoadResource(hInst, hrsrc),
1131                                   TRUE, owner,
1132                                   (DLGPROC16)dlgProc, param, WIN_PROC_32W, TRUE );
1133     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
1134     return -1;
1135 }
1136
1137
1138 /***********************************************************************
1139  *              DialogBoxIndirect (USER.218)
1140  */
1141 INT16 WINAPI DialogBoxIndirect16( HINSTANCE16 hInst, HANDLE16 dlgTemplate,
1142                                   HWND16 owner, DLGPROC16 dlgProc )
1143 {
1144     return DialogBoxIndirectParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
1145 }
1146
1147
1148 /***********************************************************************
1149  *              DialogBoxIndirectParam16 (USER.240) (USER32.@)
1150  */
1151 INT16 WINAPI DialogBoxIndirectParam16( HINSTANCE16 hInst, HANDLE16 dlgTemplate,
1152                                        HWND16 owner, DLGPROC16 dlgProc,
1153                                        LPARAM param )
1154 {
1155     HWND16 hwnd;
1156     LPCVOID ptr;
1157
1158     if (!(ptr = GlobalLock16( dlgTemplate ))) return -1;
1159     hwnd = DIALOG_CreateIndirect( hInst, ptr, FALSE, owner,
1160                                   dlgProc, param, WIN_PROC_16, TRUE );
1161     GlobalUnlock16( dlgTemplate );
1162     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
1163     return -1;
1164 }
1165
1166
1167 /***********************************************************************
1168  *              DialogBoxIndirectParamA (USER32.@)
1169  */
1170 INT WINAPI DialogBoxIndirectParamA(HINSTANCE hInstance, LPCVOID template,
1171                                        HWND owner, DLGPROC dlgProc,
1172                                        LPARAM param )
1173 {
1174     HWND hwnd = DIALOG_CreateIndirect( hInstance, template, TRUE, owner,
1175                                   (DLGPROC16) dlgProc, param, WIN_PROC_32A, TRUE );
1176     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
1177     return -1;
1178 }
1179
1180
1181 /***********************************************************************
1182  *              DialogBoxIndirectParamW (USER32.@)
1183  */
1184 INT WINAPI DialogBoxIndirectParamW(HINSTANCE hInstance, LPCVOID template,
1185                                        HWND owner, DLGPROC dlgProc,
1186                                        LPARAM param )
1187 {
1188     HWND hwnd = DIALOG_CreateIndirect( hInstance, template, TRUE, owner,
1189                                   (DLGPROC16)dlgProc, param, WIN_PROC_32W, TRUE );
1190     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
1191     return -1;
1192 }
1193
1194 /***********************************************************************
1195  *              DialogBoxIndirectParamAorW (USER32.@)
1196  */
1197 INT WINAPI DialogBoxIndirectParamAorW(HINSTANCE hInstance, LPCVOID template,
1198                                        HWND owner, DLGPROC dlgProc,
1199                                        LPARAM param, DWORD x )
1200 {
1201     HWND hwnd;
1202     FIXME("0x%08x %p 0x%08x %p 0x%08lx 0x%08lx\n",
1203       hInstance, template, owner, dlgProc, param, x);
1204     hwnd = DIALOG_CreateIndirect( hInstance, template, TRUE, owner,
1205                                   (DLGPROC16)dlgProc, param, WIN_PROC_32W, TRUE );
1206     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
1207     return -1;
1208 }
1209
1210 /***********************************************************************
1211  *              EndDialog (USER.88)
1212  */
1213 BOOL16 WINAPI EndDialog16( HWND16 hwnd, INT16 retval )
1214 {
1215     return EndDialog( hwnd, retval );
1216 }
1217
1218
1219 /***********************************************************************
1220  *              EndDialog (USER32.@)
1221  */
1222 BOOL WINAPI EndDialog( HWND hwnd, INT retval )
1223 {
1224     WND * wndPtr = WIN_FindWndPtr( hwnd );
1225     BOOL wasEnabled = TRUE;
1226     DIALOGINFO * dlgInfo;
1227
1228     TRACE("%04x %d\n", hwnd, retval );
1229
1230     if (!wndPtr)
1231     {
1232         ERR("got invalid window handle (%04x); buggy app !?\n", hwnd);
1233         return FALSE;
1234     }
1235
1236     if ((dlgInfo = (DIALOGINFO *)wndPtr->wExtra))
1237     {
1238         dlgInfo->idResult = retval;
1239         dlgInfo->flags |= DF_END;
1240         wasEnabled = (dlgInfo->flags & DF_OWNERENABLED);
1241     }
1242
1243     if(wndPtr->owner)
1244        DIALOG_EnableOwner( wndPtr->owner->hwndSelf, wasEnabled );
1245  
1246     /* Windows sets the focus to the dialog itself in EndDialog */
1247
1248     if (IsChild(hwnd, GetFocus()))
1249        SetFocus(wndPtr->hwndSelf);
1250
1251     /* Don't have to send a ShowWindow(SW_HIDE), just do
1252        SetWindowPos with SWP_HIDEWINDOW as done in Windows */
1253
1254     SetWindowPos(hwnd, (HWND)0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE
1255                  | SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW);
1256
1257     WIN_ReleaseWndPtr(wndPtr);
1258  
1259     return TRUE;
1260 }
1261
1262
1263 /***********************************************************************
1264  *           DIALOG_IsAccelerator
1265  */
1266 static BOOL DIALOG_IsAccelerator( HWND hwnd, HWND hwndDlg, WPARAM vKey )
1267 {
1268     HWND hwndControl = hwnd;
1269     HWND hwndNext;
1270     WND *wndPtr;
1271     BOOL RetVal = FALSE;
1272     INT dlgCode;
1273
1274         do
1275         {
1276             wndPtr = WIN_FindWndPtr( hwndControl );
1277             if ( (wndPtr != NULL) && 
1278                  ((wndPtr->dwStyle & (WS_VISIBLE | WS_DISABLED)) == WS_VISIBLE) )
1279             {
1280                 dlgCode = SendMessageA( hwndControl, WM_GETDLGCODE, 0, 0 );
1281                 if ( (dlgCode & (DLGC_BUTTON | DLGC_STATIC)) && 
1282                      (wndPtr->text!=NULL))
1283                 {
1284                     /* find the accelerator key */
1285                     LPWSTR p = wndPtr->text - 2;
1286                     char a_char = vKey;
1287                     WCHAR w_char = 0;
1288
1289                     do
1290                     {
1291                         p = strchrW( p + 2, '&' );
1292                     }
1293                     while (p != NULL && p[1] == '&');
1294
1295                     /* and check if it's the one we're looking for */
1296                     MultiByteToWideChar(CP_ACP, 0, &a_char, 1, &w_char, 1);
1297                     if (p != NULL && toupperW( p[1] ) == toupperW( w_char ) )
1298                     {
1299                         if ((dlgCode & DLGC_STATIC) || 
1300                             (wndPtr->dwStyle & 0x0f) == BS_GROUPBOX )
1301                         {
1302                             /* set focus to the control */
1303                             SendMessageA( hwndDlg, WM_NEXTDLGCTL,
1304                                     hwndControl, 1);
1305                             /* and bump it on to next */
1306                             SendMessageA( hwndDlg, WM_NEXTDLGCTL, 0, 0);
1307                         }
1308                         else if (dlgCode & DLGC_BUTTON)
1309                         {
1310                             /* send BM_CLICK message to the control */
1311                             SendMessageA( hwndControl, BM_CLICK, 0, 0 );
1312                         }
1313
1314                         RetVal = TRUE;
1315                         WIN_ReleaseWndPtr(wndPtr);
1316                         break;
1317                     }
1318                 }
1319                 hwndNext = GetWindow( hwndControl, GW_CHILD );
1320             }
1321             else
1322             {
1323                 hwndNext = 0;
1324             }
1325             WIN_ReleaseWndPtr(wndPtr);
1326             if (!hwndNext)
1327             {
1328                 hwndNext = GetWindow( hwndControl, GW_HWNDNEXT );
1329             }
1330             while (!hwndNext && hwndControl)
1331             {
1332                 hwndControl = GetParent( hwndControl );
1333                 if (hwndControl == hwndDlg)
1334                 {
1335                     if(hwnd==hwndDlg){  /* prevent endless loop */
1336                         hwndNext=hwnd;
1337                         break;
1338                     }
1339                     hwndNext = GetWindow( hwndDlg, GW_CHILD );
1340                 }
1341                 else
1342                 {
1343                     hwndNext = GetWindow( hwndControl, GW_HWNDNEXT );
1344                 }
1345             }
1346             hwndControl = hwndNext;
1347         }
1348         while (hwndControl && (hwndControl != hwnd));
1349
1350     return RetVal;
1351 }
1352  
1353 /***********************************************************************
1354  *           DIALOG_FindMsgDestination
1355  *
1356  * The messages that IsDialogMessage sends may not go to the dialog
1357  * calling IsDialogMessage if that dialog is a child, and it has the
1358  * DS_CONTROL style set.
1359  * We propagate up until we hit one that does not have DS_CONTROL, or
1360  * whose parent is not a dialog.
1361  *
1362  * This is undocumented behaviour.
1363  */
1364 static HWND DIALOG_FindMsgDestination( HWND hwndDlg )
1365 {
1366     while (GetWindowLongA(hwndDlg, GWL_STYLE) & DS_CONTROL)
1367     {
1368         WND *pParent;
1369         HWND hParent = GetParent(hwndDlg);
1370         if (!hParent) break;
1371
1372         pParent = WIN_FindWndPtr(hParent);
1373         if (!pParent) break;
1374
1375         if (!(pParent->flags & WIN_ISDIALOG))
1376         {
1377             WIN_ReleaseWndPtr(pParent);
1378             break;
1379         }
1380         WIN_ReleaseWndPtr(pParent);
1381
1382         hwndDlg = hParent;
1383     }
1384
1385     return hwndDlg;
1386 }
1387
1388 /***********************************************************************
1389  *           DIALOG_IsDialogMessage
1390  */
1391 static BOOL DIALOG_IsDialogMessage( HWND hwnd, HWND hwndDlg,
1392                                       UINT message, WPARAM wParam,
1393                                       LPARAM lParam, BOOL *translate,
1394                                       BOOL *dispatch, INT dlgCode )
1395 {
1396     *translate = *dispatch = FALSE;
1397
1398     if (message == WM_PAINT)
1399     {
1400         /* Apparently, we have to handle this one as well */
1401         *dispatch = TRUE;
1402         return TRUE;
1403     }
1404
1405       /* Only the key messages get special processing */
1406     if ((message != WM_KEYDOWN) &&
1407         (message != WM_SYSKEYDOWN) &&
1408         (message != WM_SYSCHAR) &&
1409         (message != WM_CHAR))
1410         return FALSE;
1411
1412     if (dlgCode & DLGC_WANTMESSAGE)
1413     {
1414         *translate = *dispatch = TRUE;
1415         return TRUE;
1416     }
1417
1418     hwndDlg = DIALOG_FindMsgDestination(hwndDlg);
1419
1420     switch(message)
1421     {
1422     case WM_KEYDOWN:
1423         switch(wParam)
1424         {
1425         case VK_TAB:
1426             if (!(dlgCode & DLGC_WANTTAB))
1427             {
1428                 SendMessageA( hwndDlg, WM_NEXTDLGCTL,
1429                                 (GetKeyState(VK_SHIFT) & 0x8000), 0 );
1430                 return TRUE;
1431             }
1432             break;
1433             
1434         case VK_RIGHT:
1435         case VK_DOWN:
1436         case VK_LEFT:
1437         case VK_UP:
1438             if (!(dlgCode & DLGC_WANTARROWS))
1439             {
1440                 BOOL fPrevious = (wParam == VK_LEFT || wParam == VK_UP);
1441                 HWND hwndNext = 
1442                     GetNextDlgGroupItem (hwndDlg, GetFocus(), fPrevious );
1443                 SendMessageA( hwndDlg, WM_NEXTDLGCTL, hwndNext, 1 );
1444                 return TRUE;
1445             }
1446             break;
1447
1448         case VK_ESCAPE:
1449             SendMessageA( hwndDlg, WM_COMMAND, IDCANCEL,
1450                             (LPARAM)GetDlgItem( hwndDlg, IDCANCEL ) );
1451             return TRUE;
1452
1453         case VK_RETURN:
1454             {
1455                 DWORD dw = SendMessage16( hwndDlg, DM_GETDEFID, 0, 0 );
1456                 if (HIWORD(dw) == DC_HASDEFID)
1457                 {
1458                     SendMessageA( hwndDlg, WM_COMMAND, 
1459                                     MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
1460                                     (LPARAM)GetDlgItem(hwndDlg, LOWORD(dw)));
1461                 }
1462                 else
1463                 {
1464                     SendMessageA( hwndDlg, WM_COMMAND, IDOK,
1465                                     (LPARAM)GetDlgItem( hwndDlg, IDOK ) );
1466     
1467                 }
1468             }
1469             return TRUE;
1470         }
1471         *translate = TRUE;
1472         break; /* case WM_KEYDOWN */
1473
1474     case WM_CHAR:
1475         if (dlgCode & DLGC_WANTCHARS) break;
1476         /* drop through */
1477
1478     case WM_SYSCHAR:
1479         if (DIALOG_IsAccelerator( hwnd, hwndDlg, wParam ))
1480         {
1481             /* don't translate or dispatch */
1482             return TRUE;
1483         }
1484         break;
1485
1486     case WM_SYSKEYDOWN:
1487         *translate = TRUE;
1488         break;
1489     }
1490
1491     /* If we get here, the message has not been treated specially */
1492     /* and can be sent to its destination window. */
1493     *dispatch = TRUE;
1494     return TRUE;
1495 }
1496
1497
1498 /***********************************************************************
1499  *              IsDialogMessage (USER.90)
1500  */
1501 BOOL16 WINAPI IsDialogMessage16( HWND16 hwndDlg, SEGPTR msg16 )
1502 {
1503     LPMSG16 msg = MapSL(msg16);
1504     BOOL ret, translate, dispatch;
1505     INT dlgCode = 0;
1506
1507     if ((hwndDlg != msg->hwnd) && !IsChild16( hwndDlg, msg->hwnd ))
1508         return FALSE;
1509
1510     if ((msg->message == WM_KEYDOWN) ||
1511         (msg->message == WM_CHAR))
1512     {
1513        dlgCode = SendMessage16( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg16);
1514     }
1515     ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message,
1516                                   msg->wParam, msg->lParam,
1517                                   &translate, &dispatch, dlgCode );
1518     if (translate) TranslateMessage16( msg );
1519     if (dispatch) DispatchMessage16( msg );
1520     return ret;
1521 }
1522
1523
1524 /***********************************************************************
1525  *              IsDialogMessageA (USER32.@)
1526  */
1527 BOOL WINAPI IsDialogMessageA( HWND hwndDlg, LPMSG msg )
1528 {
1529     BOOL ret, translate, dispatch;
1530     INT dlgCode = 0;
1531
1532     if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd ))
1533         return FALSE;
1534
1535     if ((msg->message == WM_KEYDOWN) ||
1536         (msg->message == WM_CHAR))
1537     {
1538         dlgCode = SendMessageA( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg);
1539     }
1540     ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message,
1541                                   msg->wParam, msg->lParam,
1542                                   &translate, &dispatch, dlgCode );
1543     if (translate) TranslateMessage( msg );
1544     if (dispatch) DispatchMessageA( msg );
1545     return ret;
1546 }
1547
1548
1549 /***********************************************************************
1550  *              IsDialogMessageW (USER32.@)
1551  */
1552 BOOL WINAPI IsDialogMessageW( HWND hwndDlg, LPMSG msg )
1553 {
1554     BOOL ret, translate, dispatch;
1555     INT dlgCode = 0;
1556
1557     if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd ))
1558         return FALSE;
1559
1560     if ((msg->message == WM_KEYDOWN) ||
1561         (msg->message == WM_CHAR))
1562     {
1563         dlgCode = SendMessageW( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg);
1564     }
1565     ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message,
1566                                   msg->wParam, msg->lParam,
1567                                   &translate, &dispatch, dlgCode );
1568     if (translate) TranslateMessage( msg );
1569     if (dispatch) DispatchMessageW( msg );
1570     return ret;
1571 }
1572
1573
1574 /***********************************************************************
1575  *              GetDlgCtrlID (USER.277)
1576  */
1577 INT16 WINAPI GetDlgCtrlID16( HWND16 hwnd )
1578 {
1579     WND *wndPtr = WIN_FindWndPtr(hwnd);
1580     INT16 retvalue;
1581     
1582     if (!wndPtr) return 0;
1583
1584     retvalue = wndPtr->wIDmenu;
1585     WIN_ReleaseWndPtr(wndPtr);
1586     return retvalue;
1587 }
1588  
1589
1590 /***********************************************************************
1591  *              GetDlgCtrlID (USER32.@)
1592  */
1593 INT WINAPI GetDlgCtrlID( HWND hwnd )
1594 {
1595     INT retvalue;
1596     WND *wndPtr = WIN_FindWndPtr(hwnd);
1597     if (!wndPtr) return 0;
1598     retvalue = wndPtr->wIDmenu;
1599     WIN_ReleaseWndPtr(wndPtr);
1600     return retvalue;
1601 }
1602  
1603
1604 /***********************************************************************
1605  *              GetDlgItem (USER.91)
1606  */
1607 HWND16 WINAPI GetDlgItem16( HWND16 hwndDlg, INT16 id )
1608 {
1609     WND *pWnd;
1610
1611     if (!(pWnd = WIN_FindWndPtr( hwndDlg ))) return 0;
1612     for (WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
1613         if (pWnd->wIDmenu == (UINT16)id)
1614         {
1615             HWND16 retvalue = pWnd->hwndSelf;
1616             WIN_ReleaseWndPtr(pWnd);
1617             return retvalue;
1618         }
1619     return 0;
1620 }
1621
1622
1623 /***********************************************************************
1624  *              GetDlgItem (USER32.@)
1625  */
1626 HWND WINAPI GetDlgItem( HWND hwndDlg, INT id )
1627 {
1628     WND *pWnd;
1629
1630     if (!(pWnd = WIN_FindWndPtr( hwndDlg ))) return 0;
1631     for (WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd;WIN_UpdateWndPtr(&pWnd,pWnd->next))
1632         if (pWnd->wIDmenu == (UINT16)id)
1633         {
1634             HWND retvalue = pWnd->hwndSelf;
1635             WIN_ReleaseWndPtr(pWnd);
1636             return retvalue;
1637         }
1638     return 0;
1639 }
1640
1641
1642 /*******************************************************************
1643  *              SendDlgItemMessage (USER.101)
1644  */
1645 LRESULT WINAPI SendDlgItemMessage16( HWND16 hwnd, INT16 id, UINT16 msg,
1646                                      WPARAM16 wParam, LPARAM lParam )
1647 {
1648     HWND16 hwndCtrl = GetDlgItem16( hwnd, id );
1649     if (hwndCtrl) return SendMessage16( hwndCtrl, msg, wParam, lParam );
1650     else return 0;
1651 }
1652
1653
1654 /*******************************************************************
1655  *              SendDlgItemMessageA (USER32.@)
1656  */
1657 LRESULT WINAPI SendDlgItemMessageA( HWND hwnd, INT id, UINT msg,
1658                                       WPARAM wParam, LPARAM lParam )
1659 {
1660     HWND hwndCtrl = GetDlgItem( hwnd, id );
1661     if (hwndCtrl) return SendMessageA( hwndCtrl, msg, wParam, lParam );
1662     else return 0;
1663 }
1664
1665
1666 /*******************************************************************
1667  *              SendDlgItemMessageW (USER32.@)
1668  */
1669 LRESULT WINAPI SendDlgItemMessageW( HWND hwnd, INT id, UINT msg,
1670                                       WPARAM wParam, LPARAM lParam )
1671 {
1672     HWND hwndCtrl = GetDlgItem( hwnd, id );
1673     if (hwndCtrl) return SendMessageW( hwndCtrl, msg, wParam, lParam );
1674     else return 0;
1675 }
1676
1677
1678 /*******************************************************************
1679  *              SetDlgItemText (USER.92)
1680  */
1681 void WINAPI SetDlgItemText16( HWND16 hwnd, INT16 id, SEGPTR lpString )
1682 {
1683     SendDlgItemMessage16( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1684 }
1685
1686
1687 /*******************************************************************
1688  *              SetDlgItemTextA (USER32.@)
1689  */
1690 BOOL WINAPI SetDlgItemTextA( HWND hwnd, INT id, LPCSTR lpString )
1691 {
1692     return SendDlgItemMessageA( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1693 }
1694
1695
1696 /*******************************************************************
1697  *              SetDlgItemTextW (USER32.@)
1698  */
1699 BOOL WINAPI SetDlgItemTextW( HWND hwnd, INT id, LPCWSTR lpString )
1700 {
1701     return SendDlgItemMessageW( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1702 }
1703
1704
1705 /***********************************************************************
1706  *              GetDlgItemText (USER.93)
1707  */
1708 INT16 WINAPI GetDlgItemText16( HWND16 hwnd, INT16 id, SEGPTR str, UINT16 len )
1709 {
1710     return (INT16)SendDlgItemMessage16( hwnd, id, WM_GETTEXT,
1711                                         len, (LPARAM)str );
1712 }
1713
1714
1715 /***********************************************************************
1716  *              GetDlgItemTextA (USER32.@)
1717  */
1718 INT WINAPI GetDlgItemTextA( HWND hwnd, INT id, LPSTR str, UINT len )
1719 {
1720     return (INT)SendDlgItemMessageA( hwnd, id, WM_GETTEXT,
1721                                          len, (LPARAM)str );
1722 }
1723
1724
1725 /***********************************************************************
1726  *              GetDlgItemTextW (USER32.@)
1727  */
1728 INT WINAPI GetDlgItemTextW( HWND hwnd, INT id, LPWSTR str, UINT len )
1729 {
1730     return (INT)SendDlgItemMessageW( hwnd, id, WM_GETTEXT,
1731                                          len, (LPARAM)str );
1732 }
1733
1734
1735 /*******************************************************************
1736  *              SetDlgItemInt (USER.94)
1737  */
1738 void WINAPI SetDlgItemInt16( HWND16 hwnd, INT16 id, UINT16 value, BOOL16 fSigned )
1739 {
1740     SetDlgItemInt( hwnd, (UINT)(UINT16)id, value, fSigned );
1741 }
1742
1743
1744 /*******************************************************************
1745  *              SetDlgItemInt (USER32.@)
1746  */
1747 BOOL WINAPI SetDlgItemInt( HWND hwnd, INT id, UINT value,
1748                              BOOL fSigned )
1749 {
1750     char str[20];
1751
1752     if (fSigned) sprintf( str, "%d", (INT)value );
1753     else sprintf( str, "%u", value );
1754     SendDlgItemMessageA( hwnd, id, WM_SETTEXT, 0, (LPARAM)str );
1755     return TRUE;
1756 }
1757
1758
1759 /***********************************************************************
1760  *              GetDlgItemInt (USER.95)
1761  */
1762 UINT16 WINAPI GetDlgItemInt16( HWND16 hwnd, INT16 id, BOOL16 *translated,
1763                                BOOL16 fSigned )
1764 {
1765     UINT result;
1766     BOOL ok;
1767
1768     if (translated) *translated = FALSE;
1769     result = GetDlgItemInt( hwnd, (UINT)(UINT16)id, &ok, fSigned );
1770     if (!ok) return 0;
1771     if (fSigned)
1772     {
1773         if (((INT)result < -32767) || ((INT)result > 32767)) return 0;
1774     }
1775     else
1776     {
1777         if (result > 65535) return 0;
1778     }
1779     if (translated) *translated = TRUE;
1780     return (UINT16)result;
1781 }
1782
1783
1784 /***********************************************************************
1785  *              GetDlgItemInt (USER32.@)
1786  */
1787 UINT WINAPI GetDlgItemInt( HWND hwnd, INT id, BOOL *translated,
1788                                BOOL fSigned )
1789 {
1790     char str[30];
1791     char * endptr;
1792     long result = 0;
1793     
1794     if (translated) *translated = FALSE;
1795     if (!SendDlgItemMessageA(hwnd, id, WM_GETTEXT, sizeof(str), (LPARAM)str))
1796         return 0;
1797     if (fSigned)
1798     {
1799         result = strtol( str, &endptr, 10 );
1800         if (!endptr || (endptr == str))  /* Conversion was unsuccessful */
1801             return 0;
1802         if (((result == LONG_MIN) || (result == LONG_MAX)) && (errno==ERANGE))
1803             return 0;
1804     }
1805     else
1806     {
1807         result = strtoul( str, &endptr, 10 );
1808         if (!endptr || (endptr == str))  /* Conversion was unsuccessful */
1809             return 0;
1810         if ((result == ULONG_MAX) && (errno == ERANGE)) return 0;
1811     }
1812     if (translated) *translated = TRUE;
1813     return (UINT)result;
1814 }
1815
1816
1817 /***********************************************************************
1818  *              CheckDlgButton (USER.97)
1819  */
1820 BOOL16 WINAPI CheckDlgButton16( HWND16 hwnd, INT16 id, UINT16 check )
1821 {
1822     SendDlgItemMessageA( hwnd, id, BM_SETCHECK, check, 0 );
1823     return TRUE;
1824 }
1825
1826
1827 /***********************************************************************
1828  *              CheckDlgButton (USER32.@)
1829  */
1830 BOOL WINAPI CheckDlgButton( HWND hwnd, INT id, UINT check )
1831 {
1832     SendDlgItemMessageA( hwnd, id, BM_SETCHECK, check, 0 );
1833     return TRUE;
1834 }
1835
1836
1837 /***********************************************************************
1838  *              IsDlgButtonChecked (USER.98)
1839  */
1840 UINT16 WINAPI IsDlgButtonChecked16( HWND16 hwnd, UINT16 id )
1841 {
1842     return (UINT16)SendDlgItemMessageA( hwnd, id, BM_GETCHECK, 0, 0 );
1843 }
1844
1845
1846 /***********************************************************************
1847  *              IsDlgButtonChecked (USER32.@)
1848  */
1849 UINT WINAPI IsDlgButtonChecked( HWND hwnd, UINT id )
1850 {
1851     return (UINT)SendDlgItemMessageA( hwnd, id, BM_GETCHECK, 0, 0 );
1852 }
1853
1854
1855 /***********************************************************************
1856  *              CheckRadioButton (USER.96)
1857  */
1858 BOOL16 WINAPI CheckRadioButton16( HWND16 hwndDlg, UINT16 firstID,
1859                                   UINT16 lastID, UINT16 checkID )
1860 {
1861     return CheckRadioButton( hwndDlg, firstID, lastID, checkID );
1862 }
1863
1864
1865 /***********************************************************************
1866  *           CheckRB
1867  * 
1868  * Callback function used to check/uncheck radio buttons that fall 
1869  * within a specific range of IDs.
1870  */
1871 static BOOL CALLBACK CheckRB(HWND hwndChild, LPARAM lParam)
1872 {
1873     LONG lChildID = GetWindowLongA(hwndChild, GWL_ID);
1874     RADIOGROUP *lpRadioGroup = (RADIOGROUP *) lParam;
1875
1876     if ((lChildID >= lpRadioGroup->firstID) && 
1877         (lChildID <= lpRadioGroup->lastID))
1878     {
1879         if (lChildID == lpRadioGroup->checkID)
1880         {
1881             SendMessageA(hwndChild, BM_SETCHECK, BST_CHECKED, 0);
1882         }
1883         else
1884         {
1885             SendMessageA(hwndChild, BM_SETCHECK, BST_UNCHECKED, 0);
1886         }
1887     }
1888
1889     return TRUE;
1890 }
1891
1892
1893 /***********************************************************************
1894  *              CheckRadioButton (USER32.@)
1895  */
1896 BOOL WINAPI CheckRadioButton( HWND hwndDlg, UINT firstID,
1897                               UINT lastID, UINT checkID )
1898 {
1899     RADIOGROUP radioGroup;
1900
1901     /* perform bounds checking for a radio button group */
1902     radioGroup.firstID = min(min(firstID, lastID), checkID);
1903     radioGroup.lastID = max(max(firstID, lastID), checkID);
1904     radioGroup.checkID = checkID;
1905     
1906     return EnumChildWindows(hwndDlg, (WNDENUMPROC)CheckRB, 
1907                             (LPARAM)&radioGroup);
1908 }
1909
1910
1911 /***********************************************************************
1912  *              GetDialogBaseUnits (USER.243) (USER32.@)
1913  */
1914 DWORD WINAPI GetDialogBaseUnits(void)
1915 {
1916     return MAKELONG( xBaseUnit, yBaseUnit );
1917 }
1918
1919
1920 /***********************************************************************
1921  *              MapDialogRect (USER.103)
1922  */
1923 void WINAPI MapDialogRect16( HWND16 hwnd, LPRECT16 rect )
1924 {
1925     DIALOGINFO * dlgInfo;
1926     WND * wndPtr = WIN_FindWndPtr( hwnd );
1927     if (!wndPtr) return;
1928     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
1929     rect->left   = MulDiv(rect->left, dlgInfo->xBaseUnit, 4);
1930     rect->right  = MulDiv(rect->right, dlgInfo->xBaseUnit, 4);
1931     rect->top    = MulDiv(rect->top, dlgInfo->yBaseUnit, 8);
1932     rect->bottom = MulDiv(rect->bottom, dlgInfo->yBaseUnit, 8);
1933     WIN_ReleaseWndPtr(wndPtr);
1934 }
1935
1936
1937 /***********************************************************************
1938  *              MapDialogRect (USER32.@)
1939  */
1940 BOOL WINAPI MapDialogRect( HWND hwnd, LPRECT rect )
1941 {
1942     DIALOGINFO * dlgInfo;
1943     WND * wndPtr = WIN_FindWndPtr( hwnd );
1944     if (!wndPtr) return FALSE;
1945     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
1946     rect->left   = MulDiv(rect->left, dlgInfo->xBaseUnit, 4);
1947     rect->right  = MulDiv(rect->right, dlgInfo->xBaseUnit, 4);
1948     rect->top    = MulDiv(rect->top, dlgInfo->yBaseUnit, 8);
1949     rect->bottom = MulDiv(rect->bottom, dlgInfo->yBaseUnit, 8);
1950     WIN_ReleaseWndPtr(wndPtr);
1951     return TRUE;
1952 }
1953
1954
1955 /***********************************************************************
1956  *              GetNextDlgGroupItem (USER.227)
1957  */
1958 HWND16 WINAPI GetNextDlgGroupItem16( HWND16 hwndDlg, HWND16 hwndCtrl,
1959                                      BOOL16 fPrevious )
1960 {
1961     return (HWND16)GetNextDlgGroupItem( hwndDlg, hwndCtrl, fPrevious );
1962 }
1963
1964
1965 /***********************************************************************
1966  *              GetNextDlgGroupItem (USER32.@)
1967  */
1968 HWND WINAPI GetNextDlgGroupItem( HWND hwndDlg, HWND hwndCtrl,
1969                                      BOOL fPrevious )
1970 {
1971     WND *pWnd = NULL,
1972         *pWndLast = NULL,
1973         *pWndCtrl = NULL,
1974         *pWndDlg = NULL;
1975     HWND retvalue;
1976
1977     if(hwndCtrl)
1978     {
1979         /* if the hwndCtrl is the child of the control in the hwndDlg,
1980          * then the hwndDlg has to be the parent of the hwndCtrl */
1981         if(GetParent(hwndCtrl) != hwndDlg && GetParent(GetParent(hwndCtrl)) == hwndDlg)
1982             hwndDlg = GetParent(hwndCtrl);
1983     }
1984
1985     if (!(pWndDlg = WIN_FindWndPtr( hwndDlg ))) return 0;
1986     if (hwndCtrl)
1987     {
1988         if (!(pWndCtrl = WIN_FindWndPtr( hwndCtrl )))
1989     {
1990             retvalue = 0;
1991             goto END;
1992         }
1993         /* Make sure hwndCtrl is a top-level child */
1994         while ((pWndCtrl->dwStyle & WS_CHILD) && (pWndCtrl->parent != pWndDlg))
1995             WIN_UpdateWndPtr(&pWndCtrl,pWndCtrl->parent);
1996         if (pWndCtrl->parent != pWndDlg)
1997         {
1998             retvalue = 0;
1999             goto END;
2000         }
2001     }
2002     else
2003     {
2004         /* No ctrl specified -> start from the beginning */
2005         if (!(pWndCtrl = WIN_LockWndPtr(pWndDlg->child)))
2006         {
2007             retvalue = 0;
2008             goto END;
2009         }
2010         if (fPrevious)
2011             while (pWndCtrl->next) WIN_UpdateWndPtr(&pWndCtrl,pWndCtrl->next);
2012     }
2013
2014     pWndLast = WIN_LockWndPtr(pWndCtrl);
2015     pWnd = WIN_LockWndPtr(pWndCtrl->next);
2016
2017     while (1)
2018     {
2019         if (!pWnd || (pWnd->dwStyle & WS_GROUP))
2020         {
2021             /* Wrap-around to the beginning of the group */
2022             WND *pWndTemp;
2023
2024             WIN_UpdateWndPtr( &pWnd, pWndDlg->child );
2025             for ( pWndTemp = WIN_LockWndPtr( pWnd ); 
2026                   pWndTemp;
2027                   WIN_UpdateWndPtr( &pWndTemp, pWndTemp->next) )
2028             {
2029                 if (pWndTemp->dwStyle & WS_GROUP) WIN_UpdateWndPtr( &pWnd, pWndTemp );
2030                 if (pWndTemp == pWndCtrl) break;
2031             }
2032             WIN_ReleaseWndPtr( pWndTemp );
2033         }
2034         if (pWnd == pWndCtrl) break;
2035         if ((pWnd->dwStyle & WS_VISIBLE) && !(pWnd->dwStyle & WS_DISABLED))
2036         {
2037             WIN_UpdateWndPtr(&pWndLast,pWnd);
2038             if (!fPrevious) break;
2039         }
2040         WIN_UpdateWndPtr(&pWnd,pWnd->next);
2041     }
2042     retvalue = pWndLast->hwndSelf;
2043
2044     WIN_ReleaseWndPtr(pWndLast);
2045     WIN_ReleaseWndPtr(pWnd);
2046 END:
2047     WIN_ReleaseWndPtr(pWndCtrl);
2048     WIN_ReleaseWndPtr(pWndDlg);
2049
2050     return retvalue;
2051 }
2052
2053
2054 /***********************************************************************
2055  *              GetNextDlgTabItem (USER.228)
2056  */
2057 HWND16 WINAPI GetNextDlgTabItem16( HWND16 hwndDlg, HWND16 hwndCtrl,
2058                                    BOOL16 fPrevious )
2059 {
2060     return (HWND16)GetNextDlgTabItem( hwndDlg, hwndCtrl, fPrevious );
2061 }
2062
2063 /***********************************************************************
2064  *           DIALOG_GetNextTabItem
2065  *
2066  * Helper for GetNextDlgTabItem
2067  */
2068 static HWND DIALOG_GetNextTabItem( HWND hwndMain, HWND hwndDlg, HWND hwndCtrl, BOOL fPrevious )
2069 {
2070     LONG dsStyle;
2071     LONG exStyle;
2072     UINT wndSearch = fPrevious ? GW_HWNDPREV : GW_HWNDNEXT;
2073     HWND retWnd = 0;
2074     HWND hChildFirst = 0;
2075
2076     if(!hwndCtrl) 
2077     {
2078         hChildFirst = GetWindow(hwndDlg,GW_CHILD);
2079         if(fPrevious) hChildFirst = GetWindow(hChildFirst,GW_HWNDLAST);
2080     }
2081     else
2082     {
2083         HWND hParent = GetParent(hwndCtrl);
2084         BOOL bValid = FALSE;
2085         while( hParent)
2086         {
2087             if(hParent == hwndMain)
2088             {
2089                 bValid = TRUE;
2090                 break;
2091             }
2092             hParent = GetParent(hParent);
2093         }
2094         if(bValid)
2095         {
2096             hChildFirst = GetWindow(hwndCtrl,wndSearch);
2097             if(!hChildFirst)
2098             {
2099                 if(GetParent(hwndCtrl) != hwndMain)
2100                     hChildFirst = GetWindow(GetParent(hwndCtrl),wndSearch);
2101                 else
2102                 {
2103                     if(fPrevious)
2104                         hChildFirst = GetWindow(hwndCtrl,GW_HWNDLAST);
2105                     else
2106                         hChildFirst = GetWindow(hwndCtrl,GW_HWNDFIRST);
2107                 }
2108             }
2109         }       
2110     }
2111     while(hChildFirst)
2112     {
2113         BOOL bCtrl = FALSE;
2114         while(hChildFirst)
2115         {
2116             dsStyle = GetWindowLongA(hChildFirst,GWL_STYLE);
2117             exStyle = GetWindowLongA(hChildFirst,GWL_EXSTYLE);
2118             if( (dsStyle & DS_CONTROL || exStyle & WS_EX_CONTROLPARENT) && (dsStyle & WS_VISIBLE) && !(dsStyle & WS_DISABLED))
2119             {
2120                 bCtrl=TRUE;
2121                 break;
2122             }
2123             else if( (dsStyle & WS_TABSTOP) && (dsStyle & WS_VISIBLE) && !(dsStyle & WS_DISABLED))
2124                 break;
2125             hChildFirst = GetWindow(hChildFirst,wndSearch);
2126         }
2127         if(hChildFirst)
2128         {
2129             if(bCtrl)
2130                 retWnd = DIALOG_GetNextTabItem(hwndMain,hChildFirst,(HWND)NULL,fPrevious );
2131             else
2132                 retWnd = hChildFirst;
2133         }
2134         if(retWnd) break;
2135         hChildFirst = GetWindow(hChildFirst,wndSearch);
2136     }
2137     if(!retWnd && hwndCtrl)
2138     {
2139         HWND hParent = GetParent(hwndCtrl);
2140         while(hParent)
2141         {
2142             if(hParent == hwndMain) break;
2143             retWnd = DIALOG_GetNextTabItem(hwndMain,GetParent(hParent),hParent,fPrevious );
2144             if(retWnd) break;
2145             hParent = GetParent(hParent);
2146         }
2147         if(!retWnd)
2148             retWnd = DIALOG_GetNextTabItem(hwndMain,hwndMain,(HWND)NULL,fPrevious );
2149     }
2150     return retWnd;
2151 }
2152
2153 /***********************************************************************
2154  *              GetNextDlgTabItem (USER32.@)
2155  */
2156 HWND WINAPI GetNextDlgTabItem( HWND hwndDlg, HWND hwndCtrl,
2157                                    BOOL fPrevious )
2158 {
2159     return DIALOG_GetNextTabItem(hwndDlg,hwndDlg,hwndCtrl,fPrevious); 
2160 }
2161
2162 /**********************************************************************
2163  *           DIALOG_DlgDirSelect
2164  *
2165  * Helper function for DlgDirSelect*
2166  */
2167 static BOOL DIALOG_DlgDirSelect( HWND hwnd, LPSTR str, INT len,
2168                                    INT id, BOOL win32, BOOL unicode,
2169                                    BOOL combo )
2170 {
2171     char *buffer, *ptr;
2172     INT item, size;
2173     BOOL ret;
2174     HWND listbox = GetDlgItem( hwnd, id );
2175
2176     TRACE("%04x '%s' %d\n", hwnd, str, id );
2177     if (!listbox) return FALSE;
2178     if (win32)
2179     {
2180         item = SendMessageA(listbox, combo ? CB_GETCURSEL
2181                                              : LB_GETCURSEL, 0, 0 );
2182         if (item == LB_ERR) return FALSE;
2183         size = SendMessageA(listbox, combo ? CB_GETLBTEXTLEN
2184                                              : LB_GETTEXTLEN, 0, 0 );
2185         if (size == LB_ERR) return FALSE;
2186     }
2187     else
2188     {
2189         item = SendMessageA(listbox, combo ? CB_GETCURSEL16
2190                                              : LB_GETCURSEL16, 0, 0 );
2191         if (item == LB_ERR) return FALSE;
2192         size = SendMessageA(listbox, combo ? CB_GETLBTEXTLEN16
2193                                              : LB_GETTEXTLEN16, 0, 0 );
2194         if (size == LB_ERR) return FALSE;
2195     }
2196
2197     if (!(buffer = SEGPTR_ALLOC( size+1 ))) return FALSE;
2198
2199     if (win32)
2200         SendMessageA( listbox, combo ? CB_GETLBTEXT : LB_GETTEXT,
2201                         item, (LPARAM)buffer );
2202     else
2203         SendMessage16( listbox, combo ? CB_GETLBTEXT16 : LB_GETTEXT16,
2204                        item, (LPARAM)SEGPTR_GET(buffer) );
2205
2206     if ((ret = (buffer[0] == '[')))  /* drive or directory */
2207     {
2208         if (buffer[1] == '-')  /* drive */
2209         {
2210             buffer[3] = ':';
2211             buffer[4] = 0;
2212             ptr = buffer + 2;
2213         }
2214         else
2215         {
2216             buffer[strlen(buffer)-1] = '\\';
2217             ptr = buffer + 1;
2218         }
2219     }
2220     else ptr = buffer;
2221
2222     if (unicode)
2223     {
2224         if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, ptr, -1, (LPWSTR)str, len ))
2225             ((LPWSTR)str)[len-1] = 0;
2226     }
2227     else lstrcpynA( str, ptr, len );
2228     SEGPTR_FREE( buffer );
2229     TRACE("Returning %d '%s'\n", ret, str );
2230     return ret;
2231 }
2232
2233
2234 /**********************************************************************
2235  *          DIALOG_DlgDirList
2236  *
2237  * Helper function for DlgDirList*
2238  */
2239 static INT DIALOG_DlgDirList( HWND hDlg, LPSTR spec, INT idLBox,
2240                                 INT idStatic, UINT attrib, BOOL combo )
2241 {
2242     HWND hwnd;
2243     LPSTR orig_spec = spec;
2244
2245 #define SENDMSG(msg,wparam,lparam) \
2246     ((attrib & DDL_POSTMSGS) ? PostMessageA( hwnd, msg, wparam, lparam ) \
2247                              : SendMessageA( hwnd, msg, wparam, lparam ))
2248
2249     TRACE("%04x '%s' %d %d %04x\n",
2250                     hDlg, spec ? spec : "NULL", idLBox, idStatic, attrib );
2251
2252     /* If the path exists and is a directory, chdir to it */
2253     if (!spec || !spec[0] || SetCurrentDirectoryA( spec )) spec = "*.*";
2254     else
2255     {
2256         char *p, *p2;
2257         p = spec;
2258         if ((p2 = strrchr( p, '\\' ))) p = p2;
2259         if ((p2 = strrchr( p, '/' ))) p = p2;
2260         if (p != spec)
2261         {
2262             char sep = *p;
2263             *p = 0;
2264             if (!SetCurrentDirectoryA( spec ))
2265             {
2266                 *p = sep;  /* Restore the original spec */
2267                 return FALSE;
2268             }
2269             spec = p + 1;
2270         }
2271     }
2272
2273     TRACE( "mask=%s\n", spec );
2274
2275     if (idLBox && ((hwnd = GetDlgItem( hDlg, idLBox )) != 0))
2276     {
2277         SENDMSG( combo ? CB_RESETCONTENT : LB_RESETCONTENT, 0, 0 );
2278         if (attrib & DDL_DIRECTORY)
2279         {
2280             if (!(attrib & DDL_EXCLUSIVE))
2281             {
2282                 if (SENDMSG( combo ? CB_DIR : LB_DIR,
2283                              attrib & ~(DDL_DIRECTORY | DDL_DRIVES),
2284                              (LPARAM)spec ) == LB_ERR)
2285                     return FALSE;
2286             }
2287             if (SENDMSG( combo ? CB_DIR : LB_DIR,
2288                        (attrib & (DDL_DIRECTORY | DDL_DRIVES)) | DDL_EXCLUSIVE,
2289                          (LPARAM)"*.*" ) == LB_ERR)
2290                 return FALSE;
2291         }
2292         else
2293         {
2294             if (SENDMSG( combo ? CB_DIR : LB_DIR, attrib,
2295                          (LPARAM)spec ) == LB_ERR)
2296                 return FALSE;
2297         }
2298     }
2299
2300     if (idStatic && ((hwnd = GetDlgItem( hDlg, idStatic )) != 0))
2301     {
2302         char temp[MAX_PATH];
2303         GetCurrentDirectoryA( sizeof(temp), temp );
2304         CharLowerA( temp );
2305         /* Can't use PostMessage() here, because the string is on the stack */
2306         SetDlgItemTextA( hDlg, idStatic, temp );
2307     }
2308
2309     if (orig_spec && (spec != orig_spec))
2310     {
2311         /* Update the original file spec */
2312         char *p = spec;
2313         while ((*orig_spec++ = *p++));
2314     }
2315
2316     return TRUE;
2317 #undef SENDMSG
2318 }
2319
2320
2321 /**********************************************************************
2322  *          DIALOG_DlgDirListW
2323  *
2324  * Helper function for DlgDirList*W
2325  */
2326 static INT DIALOG_DlgDirListW( HWND hDlg, LPWSTR spec, INT idLBox,
2327                                  INT idStatic, UINT attrib, BOOL combo )
2328 {
2329     if (spec)
2330     {
2331         LPSTR specA = HEAP_strdupWtoA( GetProcessHeap(), 0, spec );
2332         INT ret = DIALOG_DlgDirList( hDlg, specA, idLBox, idStatic,
2333                                        attrib, combo );
2334         MultiByteToWideChar( CP_ACP, 0, specA, -1, spec, 0x7fffffff );
2335         HeapFree( GetProcessHeap(), 0, specA );
2336         return ret;
2337     }
2338     return DIALOG_DlgDirList( hDlg, NULL, idLBox, idStatic, attrib, combo );
2339 }
2340
2341
2342 /**********************************************************************
2343  *              DlgDirSelect (USER.99)
2344  */
2345 BOOL16 WINAPI DlgDirSelect16( HWND16 hwnd, LPSTR str, INT16 id )
2346 {
2347     return DlgDirSelectEx16( hwnd, str, 128, id );
2348 }
2349
2350
2351 /**********************************************************************
2352  *              DlgDirSelectComboBox (USER.194)
2353  */
2354 BOOL16 WINAPI DlgDirSelectComboBox16( HWND16 hwnd, LPSTR str, INT16 id )
2355 {
2356     return DlgDirSelectComboBoxEx16( hwnd, str, 128, id );
2357 }
2358
2359
2360 /**********************************************************************
2361  *              DlgDirSelectEx (USER.422)
2362  */
2363 BOOL16 WINAPI DlgDirSelectEx16( HWND16 hwnd, LPSTR str, INT16 len, INT16 id )
2364 {
2365     return DIALOG_DlgDirSelect( hwnd, str, len, id, FALSE, FALSE, FALSE );
2366 }
2367
2368
2369 /**********************************************************************
2370  *              DlgDirSelectExA (USER32.@)
2371  */
2372 BOOL WINAPI DlgDirSelectExA( HWND hwnd, LPSTR str, INT len, INT id )
2373 {
2374     return DIALOG_DlgDirSelect( hwnd, str, len, id, TRUE, FALSE, FALSE );
2375 }
2376
2377
2378 /**********************************************************************
2379  *              DlgDirSelectExW (USER32.@)
2380  */
2381 BOOL WINAPI DlgDirSelectExW( HWND hwnd, LPWSTR str, INT len, INT id )
2382 {
2383     return DIALOG_DlgDirSelect( hwnd, (LPSTR)str, len, id, TRUE, TRUE, FALSE );
2384 }
2385
2386
2387 /**********************************************************************
2388  *              DlgDirSelectComboBoxEx (USER.423)
2389  */
2390 BOOL16 WINAPI DlgDirSelectComboBoxEx16( HWND16 hwnd, LPSTR str, INT16 len,
2391                                         INT16 id )
2392 {
2393     return DIALOG_DlgDirSelect( hwnd, str, len, id, FALSE, FALSE, TRUE );
2394 }
2395
2396
2397 /**********************************************************************
2398  *              DlgDirSelectComboBoxExA (USER32.@)
2399  */
2400 BOOL WINAPI DlgDirSelectComboBoxExA( HWND hwnd, LPSTR str, INT len,
2401                                          INT id )
2402 {
2403     return DIALOG_DlgDirSelect( hwnd, str, len, id, TRUE, FALSE, TRUE );
2404 }
2405
2406
2407 /**********************************************************************
2408  *              DlgDirSelectComboBoxExW (USER32.@)
2409  */
2410 BOOL WINAPI DlgDirSelectComboBoxExW( HWND hwnd, LPWSTR str, INT len,
2411                                          INT id)
2412 {
2413     return DIALOG_DlgDirSelect( hwnd, (LPSTR)str, len, id, TRUE, TRUE, TRUE );
2414 }
2415
2416
2417 /**********************************************************************
2418  *              DlgDirList (USER.100)
2419  */
2420 INT16 WINAPI DlgDirList16( HWND16 hDlg, LPSTR spec, INT16 idLBox,
2421                            INT16 idStatic, UINT16 attrib )
2422 {
2423     /* according to Win16 docs, DDL_DRIVES should make DDL_EXCLUSIVE
2424      * be set automatically (this is different in Win32, and
2425      * DIALOG_DlgDirList sends Win32 messages to the control,
2426      * so do it here) */
2427     if (attrib & DDL_DRIVES) attrib |= DDL_EXCLUSIVE;
2428     return DIALOG_DlgDirList( hDlg, spec, idLBox, idStatic, attrib, FALSE );
2429 }
2430
2431
2432 /**********************************************************************
2433  *              DlgDirListA (USER32.@)
2434  */
2435 INT WINAPI DlgDirListA( HWND hDlg, LPSTR spec, INT idLBox,
2436                             INT idStatic, UINT attrib )
2437 {
2438     return DIALOG_DlgDirList( hDlg, spec, idLBox, idStatic, attrib, FALSE );
2439 }
2440
2441
2442 /**********************************************************************
2443  *              DlgDirListW (USER32.@)
2444  */
2445 INT WINAPI DlgDirListW( HWND hDlg, LPWSTR spec, INT idLBox,
2446                             INT idStatic, UINT attrib )
2447 {
2448     return DIALOG_DlgDirListW( hDlg, spec, idLBox, idStatic, attrib, FALSE );
2449 }
2450
2451
2452 /**********************************************************************
2453  *              DlgDirListComboBox (USER.195)
2454  */
2455 INT16 WINAPI DlgDirListComboBox16( HWND16 hDlg, LPSTR spec, INT16 idCBox,
2456                                    INT16 idStatic, UINT16 attrib )
2457 {
2458     return DIALOG_DlgDirList( hDlg, spec, idCBox, idStatic, attrib, TRUE );
2459 }
2460
2461
2462 /**********************************************************************
2463  *              DlgDirListComboBoxA (USER32.@)
2464  */
2465 INT WINAPI DlgDirListComboBoxA( HWND hDlg, LPSTR spec, INT idCBox,
2466                                     INT idStatic, UINT attrib )
2467 {
2468     return DIALOG_DlgDirList( hDlg, spec, idCBox, idStatic, attrib, TRUE );
2469 }
2470
2471
2472 /**********************************************************************
2473  *              DlgDirListComboBoxW (USER32.@)
2474  */
2475 INT WINAPI DlgDirListComboBoxW( HWND hDlg, LPWSTR spec, INT idCBox,
2476                                     INT idStatic, UINT attrib )
2477 {
2478     return DIALOG_DlgDirListW( hDlg, spec, idCBox, idStatic, attrib, TRUE );
2479 }