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