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