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