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