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