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