Print the message name for registered messages.
[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 | CS_DBLCLKS, /* 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_CreateControls16
411  *
412  * Create the control windows for a dialog.
413  */
414 static BOOL DIALOG_CreateControls16( HWND hwnd, LPCSTR template,
415                                      const DLG_TEMPLATE *dlgTemplate, HINSTANCE16 hInst )
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         HINSTANCE16 instance = hInst;
426         SEGPTR segptr;
427
428         template = DIALOG_GetControl16( template, &info );
429         if (HIWORD(info.className) && !strcmp( info.className, "EDIT") &&
430             !(GetWindowLongW( hwnd, GWL_STYLE ) & DS_LOCALEDIT))
431         {
432             if (!dlgInfo->hDialogHeap)
433             {
434                 dlgInfo->hDialogHeap = GlobalAlloc16(GMEM_FIXED, 0x10000);
435                 if (!dlgInfo->hDialogHeap)
436                 {
437                     ERR("Insufficient memory to create heap for edit control\n" );
438                     continue;
439                 }
440                 LocalInit16(dlgInfo->hDialogHeap, 0, 0xffff);
441             }
442             instance = dlgInfo->hDialogHeap;
443         }
444
445         segptr = MapLS( info.data );
446         hwndCtrl = WIN_Handle32( CreateWindowEx16( info.exStyle | WS_EX_NOPARENTNOTIFY,
447                                                    info.className, info.windowName,
448                                                    info.style | WS_CHILD,
449                                                    MulDiv(info.x, dlgInfo->xBaseUnit, 4),
450                                                    MulDiv(info.y, dlgInfo->yBaseUnit, 8),
451                                                    MulDiv(info.cx, dlgInfo->xBaseUnit, 4),
452                                                    MulDiv(info.cy, dlgInfo->yBaseUnit, 8),
453                                                    HWND_16(hwnd), (HMENU16)info.id,
454                                                    instance, (LPVOID)segptr ));
455         UnMapLS( segptr );
456
457         if (!hwndCtrl) return FALSE;
458
459             /* Send initialisation messages to the control */
460         if (dlgInfo->hUserFont) SendMessageA( hwndCtrl, WM_SETFONT,
461                                              (WPARAM)dlgInfo->hUserFont, 0 );
462         if (SendMessageA(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
463         {
464               /* If there's already a default push-button, set it back */
465               /* to normal and use this one instead. */
466             if (hwndDefButton)
467                 SendMessageA( hwndDefButton, BM_SETSTYLE,
468                                 BS_PUSHBUTTON,FALSE );
469             hwndDefButton = hwndCtrl;
470             dlgInfo->idResult = GetWindowLongA( hwndCtrl, GWL_ID );
471         }
472     }
473     TRACE(" END\n" );
474     return TRUE;
475 }
476
477
478 /***********************************************************************
479  *           DIALOG_CreateControls32
480  *
481  * Create the control windows for a dialog.
482  */
483 static BOOL DIALOG_CreateControls32( HWND hwnd, LPCSTR template,
484                                      const DLG_TEMPLATE *dlgTemplate, HINSTANCE hInst )
485 {
486     DIALOGINFO *dlgInfo = DIALOG_get_info( hwnd );
487     DLG_CONTROL_INFO info;
488     HWND hwndCtrl, hwndDefButton = 0;
489     INT items = dlgTemplate->nbItems;
490
491     TRACE(" BEGIN\n" );
492     while (items--)
493     {
494         template = (LPCSTR)DIALOG_GetControl32( (WORD *)template, &info,
495                                                 dlgTemplate->dialogEx );
496         /* Is this it? */
497         if (info.style & WS_BORDER)
498         {
499             info.style &= ~WS_BORDER;
500             info.exStyle |= WS_EX_CLIENTEDGE;
501         }
502         hwndCtrl = CreateWindowExW( info.exStyle | WS_EX_NOPARENTNOTIFY,
503                                     (LPCWSTR)info.className,
504                                     (LPCWSTR)info.windowName,
505                                     info.style | WS_CHILD,
506                                     MulDiv(info.x, dlgInfo->xBaseUnit, 4),
507                                     MulDiv(info.y, dlgInfo->yBaseUnit, 8),
508                                     MulDiv(info.cx, dlgInfo->xBaseUnit, 4),
509                                     MulDiv(info.cy, dlgInfo->yBaseUnit, 8),
510                                     hwnd, (HMENU)info.id,
511                                     hInst, (LPVOID)info.data );
512         if (!hwndCtrl) return FALSE;
513
514             /* Send initialisation messages to the control */
515         if (dlgInfo->hUserFont) SendMessageA( hwndCtrl, WM_SETFONT,
516                                              (WPARAM)dlgInfo->hUserFont, 0 );
517         if (SendMessageA(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
518         {
519               /* If there's already a default push-button, set it back */
520               /* to normal and use this one instead. */
521             if (hwndDefButton)
522                 SendMessageA( hwndDefButton, BM_SETSTYLE,
523                                 BS_PUSHBUTTON,FALSE );
524             hwndDefButton = hwndCtrl;
525             dlgInfo->idResult = GetWindowLongA( hwndCtrl, GWL_ID );
526         }
527     }
528     TRACE(" END\n" );
529     return TRUE;
530 }
531
532
533 /***********************************************************************
534  *           DIALOG_ParseTemplate16
535  *
536  * Fill a DLG_TEMPLATE structure from the dialog template, and return
537  * a pointer to the first control.
538  */
539 static LPCSTR DIALOG_ParseTemplate16( LPCSTR p, DLG_TEMPLATE * result )
540 {
541     result->style   = GET_DWORD(p); p += sizeof(DWORD);
542     result->exStyle = 0;
543     result->nbItems = (unsigned char) *p++;
544     result->x       = GET_WORD(p);  p += sizeof(WORD);
545     result->y       = GET_WORD(p);  p += sizeof(WORD);
546     result->cx      = GET_WORD(p);  p += sizeof(WORD);
547     result->cy      = GET_WORD(p);  p += sizeof(WORD);
548     TRACE("DIALOG %d, %d, %d, %d\n",
549                     result->x, result->y, result->cx, result->cy );
550     TRACE(" STYLE %08lx\n", result->style );
551
552     /* Get the menu name */
553
554     switch( (BYTE)*p )
555     {
556     case 0:
557         result->menuName = 0;
558         p++;
559         break;
560     case 0xff:
561         result->menuName = (LPCSTR)(UINT)GET_WORD( p + 1 );
562         p += 3;
563         TRACE(" MENU %04x\n", LOWORD(result->menuName) );
564         break;
565     default:
566         result->menuName = p;
567         TRACE(" MENU '%s'\n", p );
568         p += strlen(p) + 1;
569         break;
570     }
571
572     /* Get the class name */
573
574     if (*p)
575     {
576         result->className = p;
577         TRACE(" CLASS '%s'\n", result->className );
578     }
579     else result->className = DIALOG_CLASS_ATOM;
580     p += strlen(p) + 1;
581
582     /* Get the window caption */
583
584     result->caption = p;
585     p += strlen(p) + 1;
586     TRACE(" CAPTION '%s'\n", result->caption );
587
588     /* Get the font name */
589
590     if (result->style & DS_SETFONT)
591     {
592         result->pointSize = GET_WORD(p);
593         p += sizeof(WORD);
594         result->faceName = p;
595         p += strlen(p) + 1;
596         TRACE(" FONT %d,'%s'\n",
597                         result->pointSize, result->faceName );
598     }
599     return p;
600 }
601
602
603 /***********************************************************************
604  *           DIALOG_ParseTemplate32
605  *
606  * Fill a DLG_TEMPLATE structure from the dialog template, and return
607  * a pointer to the first control.
608  */
609 static LPCSTR DIALOG_ParseTemplate32( LPCSTR template, DLG_TEMPLATE * result )
610 {
611     const WORD *p = (const WORD *)template;
612
613     result->style = GET_DWORD(p); p += 2;
614     if (result->style == 0xffff0001)  /* DIALOGEX resource */
615     {
616         result->dialogEx = TRUE;
617         result->helpId   = GET_DWORD(p); p += 2;
618         result->exStyle  = GET_DWORD(p); p += 2;
619         result->style    = GET_DWORD(p); p += 2;
620     }
621     else
622     {
623         result->dialogEx = FALSE;
624         result->helpId   = 0;
625         result->exStyle  = GET_DWORD(p); p += 2;
626     }
627     result->nbItems = GET_WORD(p); p++;
628     result->x       = GET_WORD(p); p++;
629     result->y       = GET_WORD(p); p++;
630     result->cx      = GET_WORD(p); p++;
631     result->cy      = GET_WORD(p); p++;
632     TRACE("DIALOG%s %d, %d, %d, %d, %ld\n",
633            result->dialogEx ? "EX" : "", result->x, result->y,
634            result->cx, result->cy, result->helpId );
635     TRACE(" STYLE 0x%08lx\n", result->style );
636     TRACE(" EXSTYLE 0x%08lx\n", result->exStyle );
637
638     /* Get the menu name */
639
640     switch(GET_WORD(p))
641     {
642     case 0x0000:
643         result->menuName = NULL;
644         p++;
645         break;
646     case 0xffff:
647         result->menuName = (LPCSTR)(UINT)GET_WORD( p + 1 );
648         p += 2;
649         TRACE(" MENU %04x\n", LOWORD(result->menuName) );
650         break;
651     default:
652         result->menuName = (LPCSTR)p;
653         TRACE(" MENU %s\n", debugstr_w( (LPCWSTR)p ));
654         p += strlenW( (LPCWSTR)p ) + 1;
655         break;
656     }
657
658     /* Get the class name */
659
660     switch(GET_WORD(p))
661     {
662     case 0x0000:
663         result->className = DIALOG_CLASS_ATOM;
664         p++;
665         break;
666     case 0xffff:
667         result->className = (LPCSTR)(UINT)GET_WORD( p + 1 );
668         p += 2;
669         TRACE(" CLASS %04x\n", LOWORD(result->className) );
670         break;
671     default:
672         result->className = (LPCSTR)p;
673         TRACE(" CLASS %s\n", debugstr_w( (LPCWSTR)p ));
674         p += strlenW( (LPCWSTR)p ) + 1;
675         break;
676     }
677
678     /* Get the window caption */
679
680     result->caption = (LPCSTR)p;
681     p += strlenW( (LPCWSTR)p ) + 1;
682     TRACE(" CAPTION %s\n", debugstr_w( (LPCWSTR)result->caption ) );
683
684     /* Get the font name */
685
686     if (result->style & DS_SETFONT)
687     {
688         result->pointSize = GET_WORD(p);
689         p++;
690         if (result->dialogEx)
691         {
692             result->weight = GET_WORD(p); p++;
693             result->italic = LOBYTE(GET_WORD(p)); p++;
694         }
695         else
696         {
697             result->weight = FW_DONTCARE;
698             result->italic = FALSE;
699         }
700         result->faceName = (LPCSTR)p;
701         p += strlenW( (LPCWSTR)p ) + 1;
702         TRACE(" FONT %d, %s, %d, %s\n",
703               result->pointSize, debugstr_w( (LPCWSTR)result->faceName ),
704               result->weight, result->italic ? "TRUE" : "FALSE" );
705     }
706
707     /* First control is on dword boundary */
708     return (LPCSTR)((((int)p) + 3) & ~3);
709 }
710
711
712 /***********************************************************************
713  *           DIALOG_CreateIndirect
714  *       Creates a dialog box window
715  *
716  *       modal = TRUE if we are called from a modal dialog box.
717  *       (it's more compatible to do it here, as under Windows the owner
718  *       is never disabled if the dialog fails because of an invalid template)
719  */
720 static HWND DIALOG_CreateIndirect( HINSTANCE hInst, LPCVOID dlgTemplate,
721                                    HWND owner, DLGPROC dlgProc, LPARAM param,
722                                    WINDOWPROCTYPE procType, BOOL modal )
723 {
724     HWND hwnd;
725     RECT rect;
726     WND * wndPtr;
727     DLG_TEMPLATE template;
728     DIALOGINFO * dlgInfo;
729     BOOL ownerEnabled = TRUE;
730     BOOL win32Template = (procType != WIN_PROC_16);
731     BOOL res;
732
733       /* Parse dialog template */
734
735     if (!dlgTemplate) return 0;
736     if (win32Template)
737         dlgTemplate = DIALOG_ParseTemplate32( dlgTemplate, &template );
738     else
739         dlgTemplate = DIALOG_ParseTemplate16( dlgTemplate, &template );
740
741       /* Initialise dialog extra data */
742
743     if (!(dlgInfo = HeapAlloc( GetProcessHeap(), 0, sizeof(*dlgInfo) ))) return 0;
744     dlgInfo->hwndFocus   = 0;
745     dlgInfo->hUserFont   = 0;
746     dlgInfo->hMenu       = 0;
747     dlgInfo->xBaseUnit   = xBaseUnit;
748     dlgInfo->yBaseUnit   = yBaseUnit;
749     dlgInfo->idResult    = 0;
750     dlgInfo->flags       = 0;
751     dlgInfo->hDialogHeap = 0;
752
753       /* Load menu */
754
755     if (template.menuName)
756     {
757         if (!win32Template) dlgInfo->hMenu = HMENU_32(LoadMenu16( HINSTANCE_16(hInst), template.menuName ));
758         else dlgInfo->hMenu = LoadMenuW( hInst, (LPCWSTR)template.menuName );
759     }
760
761       /* Create custom font if needed */
762
763     if (template.style & DS_SETFONT)
764     {
765           /* We convert the size to pixels and then make it -ve.  This works
766            * for both +ve and -ve template.pointSize */
767         HDC dc;
768         int pixels;
769         dc = GetDC(0);
770         pixels = MulDiv(template.pointSize, GetDeviceCaps(dc , LOGPIXELSY), 72);
771         ReleaseDC(0, dc);
772         if (win32Template)
773             dlgInfo->hUserFont = CreateFontW( -pixels, 0, 0, 0, template.weight,
774                                               template.italic, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
775                                               PROOF_QUALITY, FF_DONTCARE,
776                                               (LPCWSTR)template.faceName );
777         else
778             dlgInfo->hUserFont = CreateFontA( -pixels, 0, 0, 0, FW_DONTCARE,
779                                               FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
780                                               PROOF_QUALITY, FF_DONTCARE, template.faceName );
781         if (dlgInfo->hUserFont)
782         {
783             SIZE charSize;
784             if (DIALOG_GetCharSize( dlgInfo->hUserFont, &charSize ))
785             {
786                 dlgInfo->xBaseUnit = charSize.cx;
787                 dlgInfo->yBaseUnit = charSize.cy;
788             }
789         }
790         TRACE("units = %d,%d\n", dlgInfo->xBaseUnit, dlgInfo->yBaseUnit );
791     }
792
793     /* Create dialog main window */
794
795     rect.left = rect.top = 0;
796     rect.right = MulDiv(template.cx, dlgInfo->xBaseUnit, 4);
797     rect.bottom =  MulDiv(template.cy, dlgInfo->yBaseUnit, 8);
798     if (template.style & DS_MODALFRAME)
799         template.exStyle |= WS_EX_DLGMODALFRAME;
800     AdjustWindowRectEx( &rect, template.style, (dlgInfo->hMenu != 0), template.exStyle );
801     rect.right -= rect.left;
802     rect.bottom -= rect.top;
803
804     if ((INT16)template.x == CW_USEDEFAULT16)
805     {
806         rect.left = rect.top = win32Template? CW_USEDEFAULT : CW_USEDEFAULT16;
807     }
808     else
809     {
810         if (template.style & DS_CENTER)
811         {
812             rect.left = (GetSystemMetrics(SM_CXSCREEN) - rect.right) / 2;
813             rect.top = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom) / 2;
814         }
815         else
816         {
817             rect.left += MulDiv(template.x, dlgInfo->xBaseUnit, 4);
818             rect.top += MulDiv(template.y, dlgInfo->yBaseUnit, 8);
819         }
820         if ( !(template.style & WS_CHILD) )
821         {
822             INT16 dX, dY;
823
824             if( !(template.style & DS_ABSALIGN) )
825                 ClientToScreen( owner, (POINT *)&rect );
826
827             /* try to fit it into the desktop */
828
829             if( (dX = rect.left + rect.right + GetSystemMetrics(SM_CXDLGFRAME)
830                  - GetSystemMetrics(SM_CXSCREEN)) > 0 ) rect.left -= dX;
831             if( (dY = rect.top + rect.bottom + GetSystemMetrics(SM_CYDLGFRAME)
832                  - GetSystemMetrics(SM_CYSCREEN)) > 0 ) rect.top -= dY;
833             if( rect.left < 0 ) rect.left = 0;
834             if( rect.top < 0 ) rect.top = 0;
835         }
836     }
837
838     if (modal)
839     {
840         ownerEnabled = DIALOG_DisableOwner( owner );
841         if (ownerEnabled) dlgInfo->flags |= DF_OWNERENABLED;
842     }
843
844     if (!win32Template)
845         hwnd = WIN_Handle32( CreateWindowEx16(template.exStyle, template.className,
846                                               template.caption, template.style & ~WS_VISIBLE,
847                                               rect.left, rect.top, rect.right, rect.bottom,
848                                               HWND_16(owner), HMENU_16(dlgInfo->hMenu),
849                                               HINSTANCE_16(hInst), NULL ));
850     else
851         hwnd = CreateWindowExW(template.exStyle, (LPCWSTR)template.className,
852                                  (LPCWSTR)template.caption,
853                                  template.style & ~WS_VISIBLE,
854                                  rect.left, rect.top, rect.right, rect.bottom,
855                                  owner, dlgInfo->hMenu, hInst, NULL );
856
857     if (!hwnd)
858     {
859         if (dlgInfo->hUserFont) DeleteObject( dlgInfo->hUserFont );
860         if (dlgInfo->hMenu) DestroyMenu( dlgInfo->hMenu );
861         if (modal && (dlgInfo->flags & DF_OWNERENABLED)) DIALOG_EnableOwner(owner);
862         HeapFree( GetProcessHeap(), 0, dlgInfo );
863         return 0;
864     }
865     wndPtr = WIN_GetPtr( hwnd );
866     wndPtr->flags |= WIN_ISDIALOG;
867     WIN_ReleasePtr( wndPtr );
868
869     if (template.helpId) SetWindowContextHelpId( hwnd, template.helpId );
870     SetWindowLongW( hwnd, DWL_WINE_DIALOGINFO, (LONG)dlgInfo );
871     switch(procType)
872     {
873     case WIN_PROC_16: SetWindowLong16( HWND_16(hwnd), DWL_DLGPROC, (LONG)dlgProc ); break;
874     case WIN_PROC_32A: SetWindowLongA( hwnd, DWL_DLGPROC, (LONG)dlgProc ); break;
875     case WIN_PROC_32W: SetWindowLongW( hwnd, DWL_DLGPROC, (LONG)dlgProc ); break;
876     default: break;
877     }
878
879     if (dlgInfo->hUserFont)
880         SendMessageA( hwnd, WM_SETFONT, (WPARAM)dlgInfo->hUserFont, 0 );
881
882     /* Create controls */
883
884     if (win32Template)
885         res = DIALOG_CreateControls32( hwnd, dlgTemplate, &template, hInst );
886     else
887         res = DIALOG_CreateControls16( hwnd, dlgTemplate, &template, HINSTANCE_16(hInst) );
888
889     if (res)
890     {
891         HWND hwndPreInitFocus;
892
893         /* Send initialisation messages and set focus */
894
895         dlgInfo->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE );
896
897         hwndPreInitFocus = GetFocus();
898         if (SendMessageA( hwnd, WM_INITDIALOG, (WPARAM)dlgInfo->hwndFocus, param ))
899         {
900             /* check where the focus is again,
901              * some controls status might have changed in WM_INITDIALOG */
902             dlgInfo->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE);
903             if( dlgInfo->hwndFocus )
904                 SetFocus( dlgInfo->hwndFocus );
905         }
906         else
907         {
908             /* If the dlgproc has returned FALSE (indicating handling of keyboard focus)
909                but the focus has not changed, set the focus where we expect it. */
910             if ((GetFocus() == hwndPreInitFocus) &&
911                 (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
912             {
913                 dlgInfo->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE);
914                 if( dlgInfo->hwndFocus )
915                     SetFocus( dlgInfo->hwndFocus );
916             }
917         }
918
919         if (template.style & WS_VISIBLE && !(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
920         {
921            ShowWindow( hwnd, SW_SHOWNORMAL );   /* SW_SHOW doesn't always work */
922         }
923         return hwnd;
924     }
925     if( IsWindow(hwnd) ) DestroyWindow( hwnd );
926     if (modal && ownerEnabled) DIALOG_EnableOwner(owner);
927     return 0;
928 }
929
930
931 /***********************************************************************
932  *              CreateDialog (USER.89)
933  */
934 HWND16 WINAPI CreateDialog16( HINSTANCE16 hInst, LPCSTR dlgTemplate,
935                               HWND16 owner, DLGPROC16 dlgProc )
936 {
937     return CreateDialogParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
938 }
939
940
941 /***********************************************************************
942  *              CreateDialogParam (USER.241)
943  */
944 HWND16 WINAPI CreateDialogParam16( HINSTANCE16 hInst, LPCSTR dlgTemplate,
945                                    HWND16 owner, DLGPROC16 dlgProc,
946                                    LPARAM param )
947 {
948     HWND16 hwnd = 0;
949     HRSRC16 hRsrc;
950     HGLOBAL16 hmem;
951     LPCVOID data;
952
953     TRACE("%04x,%s,%04x,%08lx,%ld\n",
954           hInst, debugstr_a(dlgTemplate), owner, (DWORD)dlgProc, param );
955
956     if (!(hRsrc = FindResource16( hInst, dlgTemplate, RT_DIALOGA ))) return 0;
957     if (!(hmem = LoadResource16( hInst, hRsrc ))) return 0;
958     if (!(data = LockResource16( hmem ))) hwnd = 0;
959     else hwnd = CreateDialogIndirectParam16( hInst, data, owner,
960                                              dlgProc, param );
961     FreeResource16( hmem );
962     return hwnd;
963 }
964
965 /***********************************************************************
966  *              CreateDialogParamA (USER32.@)
967  */
968 HWND WINAPI CreateDialogParamA( HINSTANCE hInst, LPCSTR name,
969                                     HWND owner, DLGPROC dlgProc,
970                                     LPARAM param )
971 {
972     HRSRC hrsrc = FindResourceA( hInst, name, RT_DIALOGA );
973     if (!hrsrc) return 0;
974     return CreateDialogIndirectParamA( hInst,
975                                          (LPVOID)LoadResource(hInst, hrsrc),
976                                          owner, dlgProc, param );
977 }
978
979
980 /***********************************************************************
981  *              CreateDialogParamW (USER32.@)
982  */
983 HWND WINAPI CreateDialogParamW( HINSTANCE hInst, LPCWSTR name,
984                                     HWND owner, DLGPROC dlgProc,
985                                     LPARAM param )
986 {
987     HRSRC hrsrc = FindResourceW( hInst, name, RT_DIALOGW );
988     if (!hrsrc) return 0;
989     return CreateDialogIndirectParamW( hInst,
990                                          (LPVOID)LoadResource(hInst, hrsrc),
991                                          owner, dlgProc, param );
992 }
993
994
995 /***********************************************************************
996  *              CreateDialogIndirect (USER.219)
997  */
998 HWND16 WINAPI CreateDialogIndirect16( HINSTANCE16 hInst, LPCVOID dlgTemplate,
999                                       HWND16 owner, DLGPROC16 dlgProc )
1000 {
1001     return CreateDialogIndirectParam16( hInst, dlgTemplate, owner, dlgProc, 0);
1002 }
1003
1004
1005 /***********************************************************************
1006  *              CreateDialogIndirectParam (USER.242)
1007  */
1008 HWND16 WINAPI CreateDialogIndirectParam16( HINSTANCE16 hInst,
1009                                            LPCVOID dlgTemplate,
1010                                            HWND16 owner, DLGPROC16 dlgProc,
1011                                            LPARAM param )
1012 {
1013     return HWND_16( DIALOG_CreateIndirect( HINSTANCE_32(hInst), dlgTemplate, WIN_Handle32(owner),
1014                                            (DLGPROC)dlgProc, param, WIN_PROC_16, FALSE ));
1015 }
1016
1017
1018 /***********************************************************************
1019  *              CreateDialogIndirectParamA (USER32.@)
1020  */
1021 HWND WINAPI CreateDialogIndirectParamA( HINSTANCE hInst,
1022                                             LPCDLGTEMPLATEA dlgTemplate,
1023                                             HWND owner, DLGPROC dlgProc,
1024                                             LPARAM param )
1025 {
1026     return DIALOG_CreateIndirect( hInst, dlgTemplate, owner, dlgProc, param, WIN_PROC_32A, FALSE );
1027 }
1028
1029 /***********************************************************************
1030  *              CreateDialogIndirectParamAorW (USER32.@)
1031  */
1032 HWND WINAPI CreateDialogIndirectParamAorW( HINSTANCE hInst,
1033                                             LPCVOID dlgTemplate,
1034                                             HWND owner, DLGPROC dlgProc,
1035                                             LPARAM param )
1036 {   FIXME("assume WIN_PROC_32W\n");
1037     return DIALOG_CreateIndirect( hInst, dlgTemplate, owner, dlgProc, param, WIN_PROC_32W, FALSE );
1038 }
1039
1040 /***********************************************************************
1041  *              CreateDialogIndirectParamW (USER32.@)
1042  */
1043 HWND WINAPI CreateDialogIndirectParamW( HINSTANCE hInst,
1044                                             LPCDLGTEMPLATEW dlgTemplate,
1045                                             HWND owner, DLGPROC dlgProc,
1046                                             LPARAM param )
1047 {
1048     return DIALOG_CreateIndirect( hInst, dlgTemplate, owner, dlgProc, param, WIN_PROC_32W, FALSE );
1049 }
1050
1051
1052 /***********************************************************************
1053  *           DIALOG_DoDialogBox
1054  */
1055 static INT DIALOG_DoDialogBox( HWND hwnd, HWND owner )
1056 {
1057     DIALOGINFO * dlgInfo;
1058     MSG msg;
1059     INT retval;
1060     HWND ownerMsg = GetAncestor( owner, GA_ROOT );
1061
1062     if (!(dlgInfo = DIALOG_get_info( hwnd ))) return -1;
1063
1064     if (!(dlgInfo->flags & DF_END)) /* was EndDialog called in WM_INITDIALOG ? */
1065     {
1066         ShowWindow( hwnd, SW_SHOW );
1067         for (;;)
1068         {
1069             if (!(GetWindowLongW( hwnd, GWL_STYLE ) & DS_NOIDLEMSG))
1070             {
1071                 if (!PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ))
1072                 {
1073                     /* No message present -> send ENTERIDLE and wait */
1074                     SendMessageW( ownerMsg, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)hwnd );
1075                     if (!GetMessageW( &msg, 0, 0, 0 )) break;
1076                 }
1077             }
1078             else if (!GetMessageW( &msg, 0, 0, 0 )) break;
1079
1080             if (!IsWindow( hwnd )) return -1;
1081             if (!(dlgInfo->flags & DF_END) && !IsDialogMessageW( hwnd, &msg))
1082             {
1083                 TranslateMessage( &msg );
1084                 DispatchMessageW( &msg );
1085             }
1086             if (dlgInfo->flags & DF_END) break;
1087         }
1088     }
1089     if (dlgInfo->flags & DF_OWNERENABLED) DIALOG_EnableOwner( owner );
1090     retval = dlgInfo->idResult;
1091     DestroyWindow( hwnd );
1092     return retval;
1093 }
1094
1095
1096 /***********************************************************************
1097  *              DialogBox (USER.87)
1098  */
1099 INT16 WINAPI DialogBox16( HINSTANCE16 hInst, LPCSTR dlgTemplate,
1100                           HWND16 owner, DLGPROC16 dlgProc )
1101 {
1102     return DialogBoxParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
1103 }
1104
1105
1106 /***********************************************************************
1107  *              DialogBoxParam (USER.239)
1108  */
1109 INT16 WINAPI DialogBoxParam16( HINSTANCE16 hInst, LPCSTR template,
1110                                HWND16 owner16, DLGPROC16 dlgProc, LPARAM param )
1111 {
1112     HWND hwnd = 0;
1113     HRSRC16 hRsrc;
1114     HGLOBAL16 hmem;
1115     LPCVOID data;
1116     int ret = -1;
1117
1118     if (!(hRsrc = FindResource16( hInst, template, RT_DIALOGA ))) return 0;
1119     if (!(hmem = LoadResource16( hInst, hRsrc ))) return 0;
1120     if ((data = LockResource16( hmem )))
1121     {
1122         HWND owner = WIN_Handle32(owner16);
1123         hwnd = DIALOG_CreateIndirect( HINSTANCE_32(hInst), data, owner,
1124                                       (DLGPROC)dlgProc, param, WIN_PROC_16, TRUE );
1125         if (hwnd) ret = DIALOG_DoDialogBox( hwnd, owner );
1126         GlobalUnlock16( hmem );
1127     }
1128     FreeResource16( hmem );
1129     return ret;
1130 }
1131
1132
1133 /***********************************************************************
1134  *              DialogBoxParamA (USER32.@)
1135  */
1136 INT_PTR WINAPI DialogBoxParamA( HINSTANCE hInst, LPCSTR name,
1137                                 HWND owner, DLGPROC dlgProc, LPARAM param )
1138 {
1139     HWND hwnd;
1140     HRSRC hrsrc = FindResourceA( hInst, name, RT_DIALOGA );
1141     if (!hrsrc) return 0;
1142     hwnd = DIALOG_CreateIndirect( hInst, (LPVOID)LoadResource(hInst, hrsrc),
1143                                   owner, dlgProc, param, WIN_PROC_32A, TRUE );
1144     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
1145     return -1;
1146 }
1147
1148
1149 /***********************************************************************
1150  *              DialogBoxParamW (USER32.@)
1151  */
1152 INT_PTR WINAPI DialogBoxParamW( HINSTANCE hInst, LPCWSTR name,
1153                                 HWND owner, DLGPROC dlgProc, LPARAM param )
1154 {
1155     HWND hwnd;
1156     HRSRC hrsrc = FindResourceW( hInst, name, RT_DIALOGW );
1157     if (!hrsrc) return 0;
1158     hwnd = DIALOG_CreateIndirect( hInst, (LPVOID)LoadResource(hInst, hrsrc),
1159                                   owner, dlgProc, param, WIN_PROC_32W, TRUE );
1160     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
1161     return -1;
1162 }
1163
1164
1165 /***********************************************************************
1166  *              DialogBoxIndirect (USER.218)
1167  */
1168 INT16 WINAPI DialogBoxIndirect16( HINSTANCE16 hInst, HANDLE16 dlgTemplate,
1169                                   HWND16 owner, DLGPROC16 dlgProc )
1170 {
1171     return DialogBoxIndirectParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
1172 }
1173
1174
1175 /***********************************************************************
1176  *              DialogBoxIndirectParam (USER.240)
1177  */
1178 INT16 WINAPI DialogBoxIndirectParam16( HINSTANCE16 hInst, HANDLE16 dlgTemplate,
1179                                        HWND16 owner16, DLGPROC16 dlgProc,
1180                                        LPARAM param )
1181 {
1182     HWND hwnd, owner = WIN_Handle32( owner16 );
1183     LPCVOID ptr;
1184
1185     if (!(ptr = GlobalLock16( dlgTemplate ))) return -1;
1186     hwnd = DIALOG_CreateIndirect( HINSTANCE_32(hInst), ptr, owner, (DLGPROC)dlgProc,
1187                                   param, WIN_PROC_16, TRUE );
1188     GlobalUnlock16( dlgTemplate );
1189     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
1190     return -1;
1191 }
1192
1193
1194 /***********************************************************************
1195  *              DialogBoxIndirectParamA (USER32.@)
1196  */
1197 INT_PTR WINAPI DialogBoxIndirectParamA(HINSTANCE hInstance, LPCDLGTEMPLATEA template,
1198                                        HWND owner, DLGPROC dlgProc,
1199                                        LPARAM param )
1200 {
1201     HWND hwnd = DIALOG_CreateIndirect( hInstance, template, owner,
1202                                        dlgProc, param, WIN_PROC_32A, TRUE );
1203     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
1204     return -1;
1205 }
1206
1207
1208 /***********************************************************************
1209  *              DialogBoxIndirectParamW (USER32.@)
1210  */
1211 INT_PTR WINAPI DialogBoxIndirectParamW(HINSTANCE hInstance, LPCDLGTEMPLATEW template,
1212                                        HWND owner, DLGPROC dlgProc,
1213                                        LPARAM param )
1214 {
1215     HWND hwnd = DIALOG_CreateIndirect( hInstance, template, owner,
1216                                        dlgProc, param, WIN_PROC_32W, TRUE );
1217     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
1218     return -1;
1219 }
1220
1221 /***********************************************************************
1222  *              DialogBoxIndirectParamAorW (USER32.@)
1223  */
1224 INT_PTR WINAPI DialogBoxIndirectParamAorW(HINSTANCE hInstance, LPCVOID template,
1225                                        HWND owner, DLGPROC dlgProc,
1226                                        LPARAM param, DWORD x )
1227 {
1228     HWND hwnd;
1229     FIXME("%p %p %p %p 0x%08lx 0x%08lx\n",
1230           hInstance, template, owner, dlgProc, param, x);
1231     hwnd = DIALOG_CreateIndirect( hInstance, template, owner, dlgProc, param, WIN_PROC_32W, TRUE );
1232     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
1233     return -1;
1234 }
1235
1236 /***********************************************************************
1237  *              EndDialog (USER32.@)
1238  */
1239 BOOL WINAPI EndDialog( HWND hwnd, INT_PTR retval )
1240 {
1241     BOOL wasEnabled = TRUE;
1242     DIALOGINFO * dlgInfo;
1243     HWND owner;
1244
1245     TRACE("%p %d\n", hwnd, retval );
1246
1247     if (!(dlgInfo = DIALOG_get_info( hwnd )))
1248     {
1249         ERR("got invalid window handle (%p); buggy app !?\n", hwnd);
1250         return FALSE;
1251     }
1252     dlgInfo->idResult = retval;
1253     dlgInfo->flags |= DF_END;
1254     wasEnabled = (dlgInfo->flags & DF_OWNERENABLED);
1255
1256     if (wasEnabled && (owner = GetWindow( hwnd, GW_OWNER )))
1257         DIALOG_EnableOwner( owner );
1258
1259     /* Windows sets the focus to the dialog itself in EndDialog */
1260
1261     if (IsChild(hwnd, GetFocus()))
1262        SetFocus( hwnd );
1263
1264     /* Don't have to send a ShowWindow(SW_HIDE), just do
1265        SetWindowPos with SWP_HIDEWINDOW as done in Windows */
1266
1267     SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE
1268                  | SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW);
1269
1270     /* unblock dialog loop */
1271     PostMessageA(hwnd, WM_NULL, 0, 0);
1272     return TRUE;
1273 }
1274
1275
1276 /***********************************************************************
1277  *           DIALOG_IsAccelerator
1278  */
1279 static BOOL DIALOG_IsAccelerator( HWND hwnd, HWND hwndDlg, WPARAM wParam )
1280 {
1281     HWND hwndControl = hwnd;
1282     HWND hwndNext;
1283     INT dlgCode;
1284     WCHAR buffer[128];
1285
1286     do
1287     {
1288         DWORD style = GetWindowLongW( hwndControl, GWL_STYLE );
1289         if ((style & (WS_VISIBLE | WS_DISABLED)) == WS_VISIBLE)
1290         {
1291             dlgCode = SendMessageA( hwndControl, WM_GETDLGCODE, 0, 0 );
1292             if ( (dlgCode & (DLGC_BUTTON | DLGC_STATIC)) &&
1293                  GetWindowTextW( hwndControl, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1294             {
1295                 /* find the accelerator key */
1296                 LPWSTR p = buffer - 2;
1297
1298                 do
1299                 {
1300                     p = strchrW( p + 2, '&' );
1301                 }
1302                 while (p != NULL && p[1] == '&');
1303
1304                 /* and check if it's the one we're looking for */
1305                 if (p != NULL && toupperW( p[1] ) == toupperW( wParam ) )
1306                 {
1307                     if ((dlgCode & DLGC_STATIC) || (style & 0x0f) == BS_GROUPBOX )
1308                     {
1309                         /* set focus to the control */
1310                         SendMessageA( hwndDlg, WM_NEXTDLGCTL, (WPARAM)hwndControl, 1);
1311                         /* and bump it on to next */
1312                         SendMessageA( hwndDlg, WM_NEXTDLGCTL, 0, 0);
1313                     }
1314                     else if (dlgCode & DLGC_BUTTON)
1315                     {
1316                         /* send BM_CLICK message to the control */
1317                         SendMessageA( hwndControl, BM_CLICK, 0, 0 );
1318                     }
1319                     return TRUE;
1320                 }
1321             }
1322             hwndNext = GetWindow( hwndControl, GW_CHILD );
1323         }
1324         else hwndNext = 0;
1325
1326         if (!hwndNext) hwndNext = GetWindow( hwndControl, GW_HWNDNEXT );
1327
1328         while (!hwndNext && hwndControl)
1329         {
1330             hwndControl = GetParent( hwndControl );
1331             if (hwndControl == hwndDlg)
1332             {
1333                 if(hwnd==hwndDlg)   /* prevent endless loop */
1334                 {
1335                     hwndNext=hwnd;
1336                     break;
1337                 }
1338                 hwndNext = GetWindow( hwndDlg, GW_CHILD );
1339             }
1340             else
1341                 hwndNext = GetWindow( hwndControl, GW_HWNDNEXT );
1342         }
1343         hwndControl = hwndNext;
1344     }
1345     while (hwndControl && (hwndControl != hwnd));
1346
1347     return FALSE;
1348 }
1349
1350 /***********************************************************************
1351  *           DIALOG_FindMsgDestination
1352  *
1353  * The messages that IsDialogMessage sends may not go to the dialog
1354  * calling IsDialogMessage if that dialog is a child, and it has the
1355  * DS_CONTROL style set.
1356  * We propagate up until we hit one that does not have DS_CONTROL, or
1357  * whose parent is not a dialog.
1358  *
1359  * This is undocumented behaviour.
1360  */
1361 static HWND DIALOG_FindMsgDestination( HWND hwndDlg )
1362 {
1363     while (GetWindowLongA(hwndDlg, GWL_STYLE) & DS_CONTROL)
1364     {
1365         WND *pParent;
1366         HWND hParent = GetParent(hwndDlg);
1367         if (!hParent) break;
1368
1369         pParent = WIN_FindWndPtr(hParent);
1370         if (!pParent) break;
1371
1372         if (!(pParent->flags & WIN_ISDIALOG))
1373         {
1374             WIN_ReleaseWndPtr(pParent);
1375             break;
1376         }
1377         WIN_ReleaseWndPtr(pParent);
1378
1379         hwndDlg = hParent;
1380     }
1381
1382     return hwndDlg;
1383 }
1384
1385 /***********************************************************************
1386  *              IsDialogMessageW (USER32.@)
1387  */
1388 BOOL WINAPI IsDialogMessageW( HWND hwndDlg, LPMSG msg )
1389 {
1390     INT dlgCode = 0;
1391
1392     if (CallMsgFilterW( msg, MSGF_DIALOGBOX )) return TRUE;
1393
1394     hwndDlg = WIN_GetFullHandle( hwndDlg );
1395     if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd )) return FALSE;
1396
1397     hwndDlg = DIALOG_FindMsgDestination(hwndDlg);
1398
1399     switch(msg->message)
1400     {
1401     case WM_KEYDOWN:
1402         dlgCode = SendMessageW( msg->hwnd, WM_GETDLGCODE, msg->wParam, (LPARAM)msg );
1403         if (dlgCode & DLGC_WANTMESSAGE) break;
1404
1405         switch(msg->wParam)
1406         {
1407         case VK_TAB:
1408             if (!(dlgCode & DLGC_WANTTAB))
1409             {
1410                 SendMessageW( hwndDlg, WM_NEXTDLGCTL, (GetKeyState(VK_SHIFT) & 0x8000), 0 );
1411                 return TRUE;
1412             }
1413             break;
1414
1415         case VK_RIGHT:
1416         case VK_DOWN:
1417         case VK_LEFT:
1418         case VK_UP:
1419             if (!(dlgCode & DLGC_WANTARROWS))
1420             {
1421                 BOOL fPrevious = (msg->wParam == VK_LEFT || msg->wParam == VK_UP);
1422                 HWND hwndNext = GetNextDlgGroupItem (hwndDlg, GetFocus(), fPrevious );
1423                 SendMessageW( hwndDlg, WM_NEXTDLGCTL, (WPARAM)hwndNext, 1 );
1424                 return TRUE;
1425             }
1426             break;
1427
1428         case VK_CANCEL:
1429         case VK_ESCAPE:
1430             SendMessageW( hwndDlg, WM_COMMAND, IDCANCEL, (LPARAM)GetDlgItem( hwndDlg, IDCANCEL ) );
1431             return TRUE;
1432
1433         case VK_EXECUTE:
1434         case VK_RETURN:
1435             {
1436                 DWORD dw = SendMessageW( hwndDlg, DM_GETDEFID, 0, 0 );
1437                 if (HIWORD(dw) == DC_HASDEFID)
1438                 {
1439                     SendMessageW( hwndDlg, WM_COMMAND, MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
1440                                     (LPARAM)GetDlgItem(hwndDlg, LOWORD(dw)));
1441                 }
1442                 else
1443                 {
1444                     SendMessageW( hwndDlg, WM_COMMAND, IDOK, (LPARAM)GetDlgItem( hwndDlg, IDOK ) );
1445
1446                 }
1447             }
1448             return TRUE;
1449         }
1450         break;
1451
1452     case WM_CHAR:
1453         dlgCode = SendMessageW( msg->hwnd, WM_GETDLGCODE, msg->wParam, (LPARAM)msg );
1454         if (dlgCode & (DLGC_WANTCHARS|DLGC_WANTMESSAGE)) break;
1455         if (msg->wParam == '\t' && (dlgCode & DLGC_WANTTAB)) break;
1456         /* drop through */
1457
1458     case WM_SYSCHAR:
1459         if (DIALOG_IsAccelerator( WIN_GetFullHandle(msg->hwnd), hwndDlg, msg->wParam ))
1460         {
1461             /* don't translate or dispatch */
1462             return TRUE;
1463         }
1464         break;
1465     }
1466
1467     TranslateMessage( msg );
1468     DispatchMessageW( msg );
1469     return TRUE;
1470 }
1471
1472
1473 /***********************************************************************
1474  *              GetDlgCtrlID (USER32.@)
1475  */
1476 INT WINAPI GetDlgCtrlID( HWND hwnd )
1477 {
1478     return GetWindowLongW( hwnd, GWL_ID );
1479 }
1480
1481
1482 /***********************************************************************
1483  *              GetDlgItem (USER32.@)
1484  */
1485 HWND WINAPI GetDlgItem( HWND hwndDlg, INT id )
1486 {
1487     int i;
1488     HWND *list = WIN_ListChildren( hwndDlg );
1489     HWND ret = 0;
1490
1491     if (!list) return 0;
1492
1493     for (i = 0; list[i]; i++) if (GetWindowLongW( list[i], GWL_ID ) == id) break;
1494     ret = list[i];
1495     HeapFree( GetProcessHeap(), 0, list );
1496     return ret;
1497 }
1498
1499
1500 /*******************************************************************
1501  *              SendDlgItemMessageA (USER32.@)
1502  */
1503 LRESULT WINAPI SendDlgItemMessageA( HWND hwnd, INT id, UINT msg,
1504                                       WPARAM wParam, LPARAM lParam )
1505 {
1506     HWND hwndCtrl = GetDlgItem( hwnd, id );
1507     if (hwndCtrl) return SendMessageA( hwndCtrl, msg, wParam, lParam );
1508     else return 0;
1509 }
1510
1511
1512 /*******************************************************************
1513  *              SendDlgItemMessageW (USER32.@)
1514  */
1515 LRESULT WINAPI SendDlgItemMessageW( HWND hwnd, INT id, UINT msg,
1516                                       WPARAM wParam, LPARAM lParam )
1517 {
1518     HWND hwndCtrl = GetDlgItem( hwnd, id );
1519     if (hwndCtrl) return SendMessageW( hwndCtrl, msg, wParam, lParam );
1520     else return 0;
1521 }
1522
1523
1524 /*******************************************************************
1525  *              SetDlgItemTextA (USER32.@)
1526  */
1527 BOOL WINAPI SetDlgItemTextA( HWND hwnd, INT id, LPCSTR lpString )
1528 {
1529     return SendDlgItemMessageA( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1530 }
1531
1532
1533 /*******************************************************************
1534  *              SetDlgItemTextW (USER32.@)
1535  */
1536 BOOL WINAPI SetDlgItemTextW( HWND hwnd, INT id, LPCWSTR lpString )
1537 {
1538     return SendDlgItemMessageW( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1539 }
1540
1541
1542 /***********************************************************************
1543  *              GetDlgItemTextA (USER32.@)
1544  */
1545 INT WINAPI GetDlgItemTextA( HWND hwnd, INT id, LPSTR str, UINT len )
1546 {
1547     return (INT)SendDlgItemMessageA( hwnd, id, WM_GETTEXT,
1548                                          len, (LPARAM)str );
1549 }
1550
1551
1552 /***********************************************************************
1553  *              GetDlgItemTextW (USER32.@)
1554  */
1555 INT WINAPI GetDlgItemTextW( HWND hwnd, INT id, LPWSTR str, UINT len )
1556 {
1557     return (INT)SendDlgItemMessageW( hwnd, id, WM_GETTEXT,
1558                                          len, (LPARAM)str );
1559 }
1560
1561
1562 /*******************************************************************
1563  *              SetDlgItemInt (USER32.@)
1564  */
1565 BOOL WINAPI SetDlgItemInt( HWND hwnd, INT id, UINT value,
1566                              BOOL fSigned )
1567 {
1568     char str[20];
1569
1570     if (fSigned) sprintf( str, "%d", (INT)value );
1571     else sprintf( str, "%u", value );
1572     SendDlgItemMessageA( hwnd, id, WM_SETTEXT, 0, (LPARAM)str );
1573     return TRUE;
1574 }
1575
1576
1577 /***********************************************************************
1578  *              GetDlgItemInt (USER32.@)
1579  */
1580 UINT WINAPI GetDlgItemInt( HWND hwnd, INT id, BOOL *translated,
1581                                BOOL fSigned )
1582 {
1583     char str[30];
1584     char * endptr;
1585     long result = 0;
1586
1587     if (translated) *translated = FALSE;
1588     if (!SendDlgItemMessageA(hwnd, id, WM_GETTEXT, sizeof(str), (LPARAM)str))
1589         return 0;
1590     if (fSigned)
1591     {
1592         result = strtol( str, &endptr, 10 );
1593         if (!endptr || (endptr == str))  /* Conversion was unsuccessful */
1594             return 0;
1595         if (((result == LONG_MIN) || (result == LONG_MAX)) && (errno==ERANGE))
1596             return 0;
1597     }
1598     else
1599     {
1600         result = strtoul( str, &endptr, 10 );
1601         if (!endptr || (endptr == str))  /* Conversion was unsuccessful */
1602             return 0;
1603         if ((result == ULONG_MAX) && (errno == ERANGE)) return 0;
1604     }
1605     if (translated) *translated = TRUE;
1606     return (UINT)result;
1607 }
1608
1609
1610 /***********************************************************************
1611  *              CheckDlgButton (USER32.@)
1612  */
1613 BOOL WINAPI CheckDlgButton( HWND hwnd, INT id, UINT check )
1614 {
1615     SendDlgItemMessageA( hwnd, id, BM_SETCHECK, check, 0 );
1616     return TRUE;
1617 }
1618
1619
1620 /***********************************************************************
1621  *              IsDlgButtonChecked (USER32.@)
1622  */
1623 UINT WINAPI IsDlgButtonChecked( HWND hwnd, UINT id )
1624 {
1625     return (UINT)SendDlgItemMessageA( hwnd, id, BM_GETCHECK, 0, 0 );
1626 }
1627
1628
1629 /***********************************************************************
1630  *           CheckRB
1631  *
1632  * Callback function used to check/uncheck radio buttons that fall
1633  * within a specific range of IDs.
1634  */
1635 static BOOL CALLBACK CheckRB(HWND hwndChild, LPARAM lParam)
1636 {
1637     LONG lChildID = GetWindowLongA(hwndChild, GWL_ID);
1638     RADIOGROUP *lpRadioGroup = (RADIOGROUP *) lParam;
1639
1640     if ((lChildID >= lpRadioGroup->firstID) &&
1641         (lChildID <= lpRadioGroup->lastID))
1642     {
1643         if (lChildID == lpRadioGroup->checkID)
1644         {
1645             SendMessageA(hwndChild, BM_SETCHECK, BST_CHECKED, 0);
1646         }
1647         else
1648         {
1649             SendMessageA(hwndChild, BM_SETCHECK, BST_UNCHECKED, 0);
1650         }
1651     }
1652
1653     return TRUE;
1654 }
1655
1656
1657 /***********************************************************************
1658  *              CheckRadioButton (USER32.@)
1659  */
1660 BOOL WINAPI CheckRadioButton( HWND hwndDlg, UINT firstID,
1661                               UINT lastID, UINT checkID )
1662 {
1663     RADIOGROUP radioGroup;
1664
1665     /* perform bounds checking for a radio button group */
1666     radioGroup.firstID = min(min(firstID, lastID), checkID);
1667     radioGroup.lastID = max(max(firstID, lastID), checkID);
1668     radioGroup.checkID = checkID;
1669
1670     return EnumChildWindows(hwndDlg, (WNDENUMPROC)CheckRB,
1671                             (LPARAM)&radioGroup);
1672 }
1673
1674
1675 /***********************************************************************
1676  *              GetDialogBaseUnits (USER.243)
1677  *              GetDialogBaseUnits (USER32.@)
1678  */
1679 DWORD WINAPI GetDialogBaseUnits(void)
1680 {
1681     return MAKELONG( xBaseUnit, yBaseUnit );
1682 }
1683
1684
1685 /***********************************************************************
1686  *              MapDialogRect (USER32.@)
1687  */
1688 BOOL WINAPI MapDialogRect( HWND hwnd, LPRECT rect )
1689 {
1690     DIALOGINFO * dlgInfo;
1691     if (!(dlgInfo = DIALOG_get_info( hwnd ))) return FALSE;
1692     rect->left   = MulDiv(rect->left, dlgInfo->xBaseUnit, 4);
1693     rect->right  = MulDiv(rect->right, dlgInfo->xBaseUnit, 4);
1694     rect->top    = MulDiv(rect->top, dlgInfo->yBaseUnit, 8);
1695     rect->bottom = MulDiv(rect->bottom, dlgInfo->yBaseUnit, 8);
1696     return TRUE;
1697 }
1698
1699
1700 /***********************************************************************
1701  *              GetNextDlgGroupItem (USER32.@)
1702  */
1703 HWND WINAPI GetNextDlgGroupItem( HWND hwndDlg, HWND hwndCtrl, BOOL fPrevious )
1704 {
1705     HWND hwnd, retvalue;
1706
1707     hwndDlg = WIN_GetFullHandle( hwndDlg );
1708     hwndCtrl = WIN_GetFullHandle( hwndCtrl );
1709
1710     if(hwndCtrl)
1711     {
1712         /* if the hwndCtrl is the child of the control in the hwndDlg,
1713          * then the hwndDlg has to be the parent of the hwndCtrl */
1714         if(GetParent(hwndCtrl) != hwndDlg && GetParent(GetParent(hwndCtrl)) == hwndDlg)
1715             hwndDlg = GetParent(hwndCtrl);
1716     }
1717
1718     if (hwndCtrl)
1719     {
1720         /* Make sure hwndCtrl is a top-level child */
1721         HWND parent = GetParent( hwndCtrl );
1722         while (parent && parent != hwndDlg) parent = GetParent(parent);
1723         if (parent != hwndDlg) return 0;
1724     }
1725     else
1726     {
1727         /* No ctrl specified -> start from the beginning */
1728         if (!(hwndCtrl = GetWindow( hwndDlg, GW_CHILD ))) return 0;
1729         if (fPrevious) hwndCtrl = GetWindow( hwndCtrl, GW_HWNDLAST );
1730     }
1731
1732     retvalue = hwndCtrl;
1733     hwnd = GetWindow( hwndCtrl, GW_HWNDNEXT );
1734     while (1)
1735     {
1736         if (!hwnd || (GetWindowLongW( hwnd, GWL_STYLE ) & WS_GROUP))
1737         {
1738             /* Wrap-around to the beginning of the group */
1739             HWND tmp;
1740
1741             hwnd = GetWindow( hwndDlg, GW_CHILD );
1742             for (tmp = hwnd; tmp; tmp = GetWindow( tmp, GW_HWNDNEXT ) )
1743             {
1744                 if (GetWindowLongW( tmp, GWL_STYLE ) & WS_GROUP) hwnd = tmp;
1745                 if (tmp == hwndCtrl) break;
1746             }
1747         }
1748         if (hwnd == hwndCtrl) break;
1749         if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE)
1750         {
1751             retvalue = hwnd;
1752             if (!fPrevious) break;
1753         }
1754         hwnd = GetWindow( hwnd, GW_HWNDNEXT );
1755     }
1756     return retvalue;
1757 }
1758
1759
1760 /***********************************************************************
1761  *           DIALOG_GetNextTabItem
1762  *
1763  * Helper for GetNextDlgTabItem
1764  */
1765 static HWND DIALOG_GetNextTabItem( HWND hwndMain, HWND hwndDlg, HWND hwndCtrl, BOOL fPrevious )
1766 {
1767     LONG dsStyle;
1768     LONG exStyle;
1769     UINT wndSearch = fPrevious ? GW_HWNDPREV : GW_HWNDNEXT;
1770     HWND retWnd = 0;
1771     HWND hChildFirst = 0;
1772
1773     if(!hwndCtrl)
1774     {
1775         hChildFirst = GetWindow(hwndDlg,GW_CHILD);
1776         if(fPrevious) hChildFirst = GetWindow(hChildFirst,GW_HWNDLAST);
1777     }
1778     else if (IsChild( hwndMain, hwndCtrl ))
1779     {
1780         hChildFirst = GetWindow(hwndCtrl,wndSearch);
1781         if(!hChildFirst)
1782         {
1783             if(GetParent(hwndCtrl) != hwndMain)
1784                 hChildFirst = GetWindow(GetParent(hwndCtrl),wndSearch);
1785             else
1786             {
1787                 if(fPrevious)
1788                     hChildFirst = GetWindow(hwndCtrl,GW_HWNDLAST);
1789                 else
1790                     hChildFirst = GetWindow(hwndCtrl,GW_HWNDFIRST);
1791             }
1792         }
1793     }
1794
1795     while(hChildFirst)
1796     {
1797         BOOL bCtrl = FALSE;
1798         while(hChildFirst)
1799         {
1800             dsStyle = GetWindowLongA(hChildFirst,GWL_STYLE);
1801             exStyle = GetWindowLongA(hChildFirst,GWL_EXSTYLE);
1802             if( (dsStyle & DS_CONTROL || exStyle & WS_EX_CONTROLPARENT) && (dsStyle & WS_VISIBLE) && !(dsStyle & WS_DISABLED))
1803             {
1804                 bCtrl=TRUE;
1805                 break;
1806             }
1807             else if( (dsStyle & WS_TABSTOP) && (dsStyle & WS_VISIBLE) && !(dsStyle & WS_DISABLED))
1808                 break;
1809             hChildFirst = GetWindow(hChildFirst,wndSearch);
1810         }
1811         if(hChildFirst)
1812         {
1813             if(bCtrl)
1814                 retWnd = DIALOG_GetNextTabItem(hwndMain,hChildFirst,NULL,fPrevious );
1815             else
1816                 retWnd = hChildFirst;
1817         }
1818         if(retWnd) break;
1819         hChildFirst = GetWindow(hChildFirst,wndSearch);
1820     }
1821     if(!retWnd && hwndCtrl)
1822     {
1823         HWND hParent = GetParent(hwndCtrl);
1824         while(hParent)
1825         {
1826             if(hParent == hwndMain) break;
1827             retWnd = DIALOG_GetNextTabItem(hwndMain,GetParent(hParent),hParent,fPrevious );
1828             if(retWnd) break;
1829             hParent = GetParent(hParent);
1830         }
1831         if(!retWnd)
1832             retWnd = DIALOG_GetNextTabItem(hwndMain,hwndMain,NULL,fPrevious );
1833     }
1834     return retWnd;
1835 }
1836
1837 /***********************************************************************
1838  *              GetNextDlgTabItem (USER32.@)
1839  */
1840 HWND WINAPI GetNextDlgTabItem( HWND hwndDlg, HWND hwndCtrl,
1841                                    BOOL fPrevious )
1842 {
1843     hwndDlg = WIN_GetFullHandle( hwndDlg );
1844     hwndCtrl = WIN_GetFullHandle( hwndCtrl );
1845     return DIALOG_GetNextTabItem(hwndDlg,hwndDlg,hwndCtrl,fPrevious);
1846 }
1847
1848 /**********************************************************************
1849  *           DIALOG_DlgDirSelect
1850  *
1851  * Helper function for DlgDirSelect*
1852  */
1853 static BOOL DIALOG_DlgDirSelect( HWND hwnd, LPSTR str, INT len,
1854                                  INT id, BOOL unicode, BOOL combo )
1855 {
1856     char *buffer, *ptr;
1857     INT item, size;
1858     BOOL ret;
1859     HWND listbox = GetDlgItem( hwnd, id );
1860
1861     TRACE("%p '%s' %d\n", hwnd, str, id );
1862     if (!listbox) return FALSE;
1863
1864     item = SendMessageA(listbox, combo ? CB_GETCURSEL : LB_GETCURSEL, 0, 0 );
1865     if (item == LB_ERR) return FALSE;
1866     size = SendMessageA(listbox, combo ? CB_GETLBTEXTLEN : LB_GETTEXTLEN, 0, 0 );
1867     if (size == LB_ERR) return FALSE;
1868
1869     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size+1 ))) return FALSE;
1870
1871     SendMessageA( listbox, combo ? CB_GETLBTEXT : LB_GETTEXT, item, (LPARAM)buffer );
1872
1873     if ((ret = (buffer[0] == '[')))  /* drive or directory */
1874     {
1875         if (buffer[1] == '-')  /* drive */
1876         {
1877             buffer[3] = ':';
1878             buffer[4] = 0;
1879             ptr = buffer + 2;
1880         }
1881         else
1882         {
1883             buffer[strlen(buffer)-1] = '\\';
1884             ptr = buffer + 1;
1885         }
1886     }
1887     else ptr = buffer;
1888
1889     if (unicode)
1890     {
1891         if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, ptr, -1, (LPWSTR)str, len ))
1892             ((LPWSTR)str)[len-1] = 0;
1893     }
1894     else lstrcpynA( str, ptr, len );
1895     HeapFree( GetProcessHeap(), 0, buffer );
1896     TRACE("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     HWND hwnd;
1910     LPSTR orig_spec = spec;
1911
1912 #define SENDMSG(msg,wparam,lparam) \
1913     ((attrib & DDL_POSTMSGS) ? PostMessageA( hwnd, msg, wparam, lparam ) \
1914                              : SendMessageA( hwnd, msg, wparam, lparam ))
1915
1916     TRACE("%p '%s' %d %d %04x\n",
1917           hDlg, spec ? spec : "NULL", idLBox, idStatic, attrib );
1918
1919     /* If the path exists and is a directory, chdir to it */
1920     if (!spec || !spec[0] || SetCurrentDirectoryA( spec )) spec = "*.*";
1921     else
1922     {
1923         char *p, *p2;
1924         p = spec;
1925         if ((p2 = strrchr( p, '\\' ))) p = p2;
1926         if ((p2 = strrchr( p, '/' ))) p = p2;
1927         if (p != spec)
1928         {
1929             char sep = *p;
1930             *p = 0;
1931             if (!SetCurrentDirectoryA( spec ))
1932             {
1933                 *p = sep;  /* Restore the original spec */
1934                 return FALSE;
1935             }
1936             spec = p + 1;
1937         }
1938     }
1939
1940     TRACE( "mask=%s\n", spec );
1941
1942     if (idLBox && ((hwnd = GetDlgItem( hDlg, idLBox )) != 0))
1943     {
1944         SENDMSG( combo ? CB_RESETCONTENT : LB_RESETCONTENT, 0, 0 );
1945         if (attrib & DDL_DIRECTORY)
1946         {
1947             if (!(attrib & DDL_EXCLUSIVE))
1948             {
1949                 if (SENDMSG( combo ? CB_DIR : LB_DIR,
1950                              attrib & ~(DDL_DIRECTORY | DDL_DRIVES),
1951                              (LPARAM)spec ) == LB_ERR)
1952                     return FALSE;
1953             }
1954             if (SENDMSG( combo ? CB_DIR : LB_DIR,
1955                        (attrib & (DDL_DIRECTORY | DDL_DRIVES)) | DDL_EXCLUSIVE,
1956                          (LPARAM)"*.*" ) == LB_ERR)
1957                 return FALSE;
1958         }
1959         else
1960         {
1961             if (SENDMSG( combo ? CB_DIR : LB_DIR, attrib,
1962                          (LPARAM)spec ) == LB_ERR)
1963                 return FALSE;
1964         }
1965     }
1966
1967     if (idStatic && ((hwnd = GetDlgItem( hDlg, idStatic )) != 0))
1968     {
1969         char temp[MAX_PATH];
1970         GetCurrentDirectoryA( sizeof(temp), temp );
1971         CharLowerA( temp );
1972         /* Can't use PostMessage() here, because the string is on the stack */
1973         SetDlgItemTextA( hDlg, idStatic, temp );
1974     }
1975
1976     if (orig_spec && (spec != orig_spec))
1977     {
1978         /* Update the original file spec */
1979         char *p = spec;
1980         while ((*orig_spec++ = *p++));
1981     }
1982
1983     return TRUE;
1984 #undef SENDMSG
1985 }
1986
1987
1988 /**********************************************************************
1989  *          DIALOG_DlgDirListW
1990  *
1991  * Helper function for DlgDirList*W
1992  */
1993 static INT DIALOG_DlgDirListW( HWND hDlg, LPWSTR spec, INT idLBox,
1994                                  INT idStatic, UINT attrib, BOOL combo )
1995 {
1996     if (spec)
1997     {
1998         LPSTR specA = HEAP_strdupWtoA( GetProcessHeap(), 0, spec );
1999         INT ret = DIALOG_DlgDirList( hDlg, specA, idLBox, idStatic,
2000                                        attrib, combo );
2001         MultiByteToWideChar( CP_ACP, 0, specA, -1, spec, 0x7fffffff );
2002         HeapFree( GetProcessHeap(), 0, specA );
2003         return ret;
2004     }
2005     return DIALOG_DlgDirList( hDlg, NULL, idLBox, idStatic, attrib, combo );
2006 }
2007
2008
2009 /**********************************************************************
2010  *              DlgDirSelectExA (USER32.@)
2011  */
2012 BOOL WINAPI DlgDirSelectExA( HWND hwnd, LPSTR str, INT len, INT id )
2013 {
2014     return DIALOG_DlgDirSelect( hwnd, str, len, id, FALSE, FALSE );
2015 }
2016
2017
2018 /**********************************************************************
2019  *              DlgDirSelectExW (USER32.@)
2020  */
2021 BOOL WINAPI DlgDirSelectExW( HWND hwnd, LPWSTR str, INT len, INT id )
2022 {
2023     return DIALOG_DlgDirSelect( hwnd, (LPSTR)str, len, id, TRUE, FALSE );
2024 }
2025
2026
2027 /**********************************************************************
2028  *              DlgDirSelectComboBoxExA (USER32.@)
2029  */
2030 BOOL WINAPI DlgDirSelectComboBoxExA( HWND hwnd, LPSTR str, INT len,
2031                                          INT id )
2032 {
2033     return DIALOG_DlgDirSelect( hwnd, str, len, id, FALSE, TRUE );
2034 }
2035
2036
2037 /**********************************************************************
2038  *              DlgDirSelectComboBoxExW (USER32.@)
2039  */
2040 BOOL WINAPI DlgDirSelectComboBoxExW( HWND hwnd, LPWSTR str, INT len,
2041                                          INT id)
2042 {
2043     return DIALOG_DlgDirSelect( hwnd, (LPSTR)str, len, id, TRUE, TRUE );
2044 }
2045
2046
2047 /**********************************************************************
2048  *              DlgDirListA (USER32.@)
2049  */
2050 INT WINAPI DlgDirListA( HWND hDlg, LPSTR spec, INT idLBox,
2051                             INT idStatic, UINT attrib )
2052 {
2053     return DIALOG_DlgDirList( hDlg, spec, idLBox, idStatic, attrib, FALSE );
2054 }
2055
2056
2057 /**********************************************************************
2058  *              DlgDirListW (USER32.@)
2059  */
2060 INT WINAPI DlgDirListW( HWND hDlg, LPWSTR spec, INT idLBox,
2061                             INT idStatic, UINT attrib )
2062 {
2063     return DIALOG_DlgDirListW( hDlg, spec, idLBox, idStatic, attrib, FALSE );
2064 }
2065
2066
2067 /**********************************************************************
2068  *              DlgDirListComboBoxA (USER32.@)
2069  */
2070 INT WINAPI DlgDirListComboBoxA( HWND hDlg, LPSTR spec, INT idCBox,
2071                                     INT idStatic, UINT attrib )
2072 {
2073     return DIALOG_DlgDirList( hDlg, spec, idCBox, idStatic, attrib, TRUE );
2074 }
2075
2076
2077 /**********************************************************************
2078  *              DlgDirListComboBoxW (USER32.@)
2079  */
2080 INT WINAPI DlgDirListComboBoxW( HWND hDlg, LPWSTR spec, INT idCBox,
2081                                     INT idStatic, UINT attrib )
2082 {
2083     return DIALOG_DlgDirListW( hDlg, spec, idCBox, idStatic, attrib, TRUE );
2084 }