Release 961222
[wine] / windows / dialog.c
1 /*
2  * Dialog functions
3  *
4  * Copyright 1993, 1994, 1996 Alexandre Julliard
5  */
6
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include "windows.h"
12 #include "dialog.h"
13 #include "drive.h"
14 #include "heap.h"
15 #include "win.h"
16 #include "ldt.h"
17 #include "user.h"
18 #include "winproc.h"
19 #include "message.h"
20 #include "sysmetrics.h"
21 #include "stddebug.h"
22 #include "debug.h"
23
24
25   /* Dialog control information */
26 typedef struct
27 {
28     DWORD      style;
29     DWORD      exStyle;
30     INT16      x;
31     INT16      y;
32     INT16      cx;
33     INT16      cy;
34     UINT16     id;
35     LPCSTR     className;
36     LPCSTR     windowName;
37     LPVOID     data;
38 } DLG_CONTROL_INFO;
39
40   /* Dialog template */
41 typedef struct
42 {
43     DWORD      style;
44     DWORD      exStyle;
45     UINT16     nbItems;
46     INT16      x;
47     INT16      y;
48     INT16      cx;
49     INT16      cy;
50     LPCSTR     menuName;
51     LPCSTR     className;
52     LPCSTR     caption;
53     WORD       pointSize;
54     LPCSTR     faceName;
55 } DLG_TEMPLATE;
56
57   /* Dialog base units */
58 static WORD xBaseUnit = 0, yBaseUnit = 0;
59
60
61 /***********************************************************************
62  *           DIALOG_Init
63  *
64  * Initialisation of the dialog manager.
65  */
66 BOOL32 DIALOG_Init()
67 {
68     TEXTMETRIC16 tm;
69     HDC16 hdc;
70     
71       /* Calculate the dialog base units */
72
73     if (!(hdc = CreateDC16( "DISPLAY", NULL, NULL, NULL ))) return FALSE;
74     GetTextMetrics16( hdc, &tm );
75     DeleteDC32( hdc );
76     xBaseUnit = tm.tmAveCharWidth;
77     yBaseUnit = tm.tmHeight;
78
79       /* Dialog units are based on a proportional system font */
80       /* so we adjust them a bit for a fixed font. */
81     if (!(tm.tmPitchAndFamily & TMPF_FIXED_PITCH))
82         xBaseUnit = xBaseUnit * 5 / 4;
83
84     dprintf_dialog( stddeb, "DIALOG_Init: base units = %d,%d\n",
85                     xBaseUnit, yBaseUnit );
86     return TRUE;
87 }
88
89
90 /***********************************************************************
91  *           DIALOG_GetControl16
92  *
93  * Return the class and text of the control pointed to by ptr,
94  * fill the header structure and return a pointer to the next control.
95  */
96 static LPCSTR DIALOG_GetControl16( LPCSTR p, DLG_CONTROL_INFO *info )
97 {
98     static char buffer[10];
99
100     info->x       = GET_WORD(p);  p += sizeof(WORD);
101     info->y       = GET_WORD(p);  p += sizeof(WORD);
102     info->cx      = GET_WORD(p);  p += sizeof(WORD);
103     info->cy      = GET_WORD(p);  p += sizeof(WORD);
104     info->id      = GET_WORD(p);  p += sizeof(WORD);
105     info->style   = GET_DWORD(p); p += sizeof(DWORD);
106     info->exStyle = 0;
107
108     if (*p & 0x80)
109     {
110         switch((BYTE)*p)
111         {
112             case 0x80: strcpy( buffer, "BUTTON" ); break;
113             case 0x81: strcpy( buffer, "EDIT" ); break;
114             case 0x82: strcpy( buffer, "STATIC" ); break;
115             case 0x83: strcpy( buffer, "LISTBOX" ); break;
116             case 0x84: strcpy( buffer, "SCROLLBAR" ); break;
117             case 0x85: strcpy( buffer, "COMBOBOX" ); break;
118             default:   buffer[0] = '\0'; break;
119         }
120         info->className = buffer;
121         p++;
122     }
123     else 
124     {
125         info->className = p;
126         p += strlen(p) + 1;
127     }
128     dprintf_dialog(stddeb, "   %s ", info->className );
129
130     if ((BYTE)*p == 0xff)
131     {
132           /* Integer id, not documented (?). Only works for SS_ICON controls */
133         info->windowName = (LPCSTR)(UINT32)GET_WORD(p+1);
134         p += 3;
135         dprintf_dialog( stddeb,"%04x", LOWORD(info->windowName) );
136     }
137     else
138     {
139         info->windowName = p;
140         p += strlen(p) + 1;
141         dprintf_dialog(stddeb,"'%s'", info->windowName );
142     }
143
144     info->data = (LPVOID)(*p ? p + 1 : NULL);  /* FIXME: should be a segptr */
145     p += *p + 1;
146
147     dprintf_dialog( stddeb," %d, %d, %d, %d, %d, %08lx, %08lx\n", 
148                     info->id, info->x, info->y, info->cx, info->cy,
149                     info->style, (DWORD)info->data);
150     return p;
151 }
152
153
154 /***********************************************************************
155  *           DIALOG_GetControl32
156  *
157  * Return the class and text of the control pointed to by ptr,
158  * fill the header structure and return a pointer to the next control.
159  */
160 static const WORD *DIALOG_GetControl32( const WORD *p, DLG_CONTROL_INFO *info )
161 {
162     static WCHAR buffer[10];
163
164     info->style   = GET_DWORD(p); p += 2;
165     info->exStyle = GET_DWORD(p); p += 2;
166     info->x       = GET_WORD(p); p++;
167     info->y       = GET_WORD(p); p++;
168     info->cx      = GET_WORD(p); p++;
169     info->cy      = GET_WORD(p); p++;
170     info->id      = GET_WORD(p); p++;
171
172     if (GET_WORD(p) == 0xffff)
173     {
174         switch(GET_WORD(p+1))
175         {
176             case 0x80: lstrcpyAtoW( buffer, "Button" ); break;
177             case 0x81: lstrcpyAtoW( buffer, "Edit" ); break;
178             case 0x82: lstrcpyAtoW( buffer, "Static" ); break;
179             case 0x83: lstrcpyAtoW( buffer, "ListBox" ); break;
180             case 0x84: lstrcpyAtoW( buffer, "ScrollBar" ); break;
181             case 0x85: lstrcpyAtoW( buffer, "ComboBox" ); break;
182             default:   buffer[0] = '\0'; break;
183         }
184         info->className = (LPCSTR)buffer;
185         p += 2;
186     }
187     else
188     {
189         info->className = (LPCSTR)p;
190         p += lstrlen32W( (LPCWSTR)p ) + 1;
191     }
192     dprintf_dialog(stddeb, "   %p ", info->className );
193
194     if (GET_WORD(p) == 0xffff)
195     {
196         info->windowName = (LPCSTR)(p + 1);
197         p += 2;
198         dprintf_dialog( stddeb,"%04x", LOWORD(info->windowName) );
199     }
200     else
201     {
202         info->windowName = (LPCSTR)p;
203         p += lstrlen32W( (LPCWSTR)p ) + 1;
204         dprintf_dialog(stddeb,"'%p'", info->windowName );
205     }
206
207     if (GET_WORD(p))
208     {
209         info->data = (LPVOID)(p + 1);
210         p += GET_WORD(p) / sizeof(WORD);
211     }
212     else info->data = NULL;
213     p++;
214
215     dprintf_dialog( stddeb," %d, %d, %d, %d, %d, %08lx, %08lx, %08lx\n", 
216                     info->id, info->x, info->y, info->cx, info->cy,
217                     info->style, info->exStyle, (DWORD)info->data);
218     /* Next control is on dword boundary */
219     return (const WORD *)((((int)p) + 3) & ~3);
220 }
221
222
223 /***********************************************************************
224  *           DIALOG_CreateControls
225  *
226  * Create the control windows for a dialog.
227  */
228 static BOOL32 DIALOG_CreateControls( WND *pWnd, LPCSTR template, INT32 items,
229                                      HINSTANCE32 hInst, BOOL win32 )
230 {
231     DIALOGINFO *dlgInfo = (DIALOGINFO *)pWnd->wExtra;
232     DLG_CONTROL_INFO info;
233     HWND32 hwndCtrl, hwndDefButton = 0;
234
235     dprintf_dialog(stddeb, " BEGIN\n" );
236     while (items--)
237     {
238         if (!win32)
239         {
240             HINSTANCE16 instance;
241             template = DIALOG_GetControl16( template, &info );
242             if (HIWORD(info.className) && !strcmp( info.className, "EDIT") &&
243                 ((pWnd->dwStyle & DS_LOCALEDIT) != DS_LOCALEDIT))
244             {
245                 if (!dlgInfo->hDialogHeap)
246                 {
247                     dlgInfo->hDialogHeap = GlobalAlloc16(GMEM_FIXED, 0x10000);
248                     if (!dlgInfo->hDialogHeap)
249                     {
250                         fprintf( stderr, "CreateDialogIndirectParam: Insufficient memory to create heap for edit control\n" );
251                         continue;
252                     }
253                     LocalInit(dlgInfo->hDialogHeap, 0, 0xffff);
254                 }
255                 instance = dlgInfo->hDialogHeap;
256             }
257             else instance = (HINSTANCE16)hInst;
258
259             hwndCtrl = CreateWindowEx16( info.exStyle | WS_EX_NOPARENTNOTIFY,
260                                          info.className, info.windowName,
261                                          info.style | WS_CHILD,
262                                          info.x * dlgInfo->xBaseUnit / 4,
263                                          info.y * dlgInfo->yBaseUnit / 8,
264                                          info.cx * dlgInfo->xBaseUnit / 4,
265                                          info.cy * dlgInfo->yBaseUnit / 8,
266                                          pWnd->hwndSelf, (HMENU16)info.id,
267                                          instance, info.data );
268         }
269         else
270         {
271             template = (LPCSTR)DIALOG_GetControl32( (WORD *)template, &info );
272             hwndCtrl = CreateWindowEx32W( info.exStyle | WS_EX_NOPARENTNOTIFY,
273                                           (LPCWSTR)info.className,
274                                           (LPCWSTR)info.windowName,
275                                           info.style | WS_CHILD,
276                                           info.x * dlgInfo->xBaseUnit / 4,
277                                           info.y * dlgInfo->yBaseUnit / 8,
278                                           info.cx * dlgInfo->xBaseUnit / 4,
279                                           info.cy * dlgInfo->yBaseUnit / 8,
280                                           pWnd->hwndSelf, (HMENU32)info.id,
281                                           hInst, info.data );
282         }
283         if (!hwndCtrl) return FALSE;
284
285             /* Send initialisation messages to the control */
286         if (dlgInfo->hUserFont) SendMessage32A( hwndCtrl, WM_SETFONT,
287                                              (WPARAM32)dlgInfo->hUserFont, 0 );
288         if (SendMessage32A(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
289         {
290               /* If there's already a default push-button, set it back */
291               /* to normal and use this one instead. */
292             if (hwndDefButton)
293                 SendMessage32A( hwndDefButton, BM_SETSTYLE32,
294                                 BS_PUSHBUTTON,FALSE );
295             hwndDefButton = hwndCtrl;
296             dlgInfo->idResult = GetWindowWord( hwndCtrl, GWW_ID );
297         }
298     }    
299     dprintf_dialog(stddeb, " END\n" );
300     return TRUE;
301 }
302
303
304 /***********************************************************************
305  *           DIALOG_ParseTemplate16
306  *
307  * Fill a DLG_TEMPLATE structure from the dialog template, and return
308  * a pointer to the first control.
309  */
310 static LPCSTR DIALOG_ParseTemplate16( LPCSTR p, DLG_TEMPLATE * result )
311 {
312     result->style   = GET_DWORD(p); p += sizeof(DWORD);
313     result->exStyle = 0;
314     result->nbItems = *p++;
315     result->x       = GET_WORD(p);  p += sizeof(WORD);
316     result->y       = GET_WORD(p);  p += sizeof(WORD);
317     result->cx      = GET_WORD(p);  p += sizeof(WORD);
318     result->cy      = GET_WORD(p);  p += sizeof(WORD);
319     dprintf_dialog( stddeb, "DIALOG %d, %d, %d, %d\n",
320                     result->x, result->y, result->cx, result->cy );
321     dprintf_dialog( stddeb, " STYLE %08lx\n", result->style );
322
323     /* Get the menu name */
324
325     switch( (BYTE)*p )
326     {
327     case 0:
328         result->menuName = 0;
329         p++;
330         break;
331     case 0xff:
332         result->menuName = (LPCSTR)(UINT32)GET_WORD( p + 1 );
333         p += 3;
334         dprintf_dialog(stddeb, " MENU %04x\n", LOWORD(result->menuName) );
335         break;
336     default:
337         result->menuName = p;
338         dprintf_dialog( stddeb, " MENU '%s'\n", p );
339         p += strlen(p) + 1;
340         break;
341     }
342
343     /* Get the class name */
344
345     if (*p)
346     {
347         result->className = p;
348         dprintf_dialog( stddeb, " CLASS '%s'\n", result->className );
349     }
350     else result->className = DIALOG_CLASS_ATOM;
351     p += strlen(p) + 1;
352
353     /* Get the window caption */
354
355     result->caption = p;
356     p += strlen(p) + 1;
357     dprintf_dialog( stddeb, " CAPTION '%s'\n", result->caption );
358
359     /* Get the font name */
360
361     if (result->style & DS_SETFONT)
362     {
363         result->pointSize = GET_WORD(p);
364         p += sizeof(WORD);
365         result->faceName = p;
366         p += strlen(p) + 1;
367         dprintf_dialog( stddeb, " FONT %d,'%s'\n",
368                         result->pointSize, result->faceName );
369     }
370     return p;
371 }
372
373
374 /***********************************************************************
375  *           DIALOG_ParseTemplate32
376  *
377  * Fill a DLG_TEMPLATE structure from the dialog template, and return
378  * a pointer to the first control.
379  */
380 static LPCSTR DIALOG_ParseTemplate32( LPCSTR template, DLG_TEMPLATE * result )
381 {
382     const WORD *p = (const WORD *)template;
383
384     result->style   = GET_DWORD(p); p += 2;
385     result->exStyle = GET_DWORD(p); p += 2;
386     result->nbItems = GET_WORD(p); p++;
387     result->x       = GET_WORD(p); p++;
388     result->y       = GET_WORD(p); p++;
389     result->cx      = GET_WORD(p); p++;
390     result->cy      = GET_WORD(p); p++;
391     dprintf_dialog( stddeb, "DIALOG %d, %d, %d, %d\n",
392                     result->x, result->y, result->cx, result->cy );
393     dprintf_dialog( stddeb, " STYLE %08lx\n", result->style );
394     dprintf_dialog( stddeb, " EXSTYLE %08lx\n", result->exStyle );
395
396     /* Get the menu name */
397
398     switch(GET_WORD(p))
399     {
400     case 0x0000:
401         result->menuName = NULL;
402         p++;
403         break;
404     case 0xffff:
405         result->menuName = (LPCSTR)(UINT32)GET_WORD( p + 1 );
406         p += 2;
407         dprintf_dialog(stddeb, " MENU %04x\n", LOWORD(result->menuName) );
408         break;
409     default:
410         result->menuName = (LPCSTR)p;
411         dprintf_dialog( stddeb, " MENU '%p'\n", p );
412         p += lstrlen32W( (LPCWSTR)p ) + 1;
413         break;
414     }
415
416     /* Get the class name */
417
418     switch(GET_WORD(p))
419     {
420     case 0x0000:
421         result->className = DIALOG_CLASS_ATOM;
422         p++;
423         break;
424     case 0xffff:
425         result->className = (LPCSTR)(UINT32)GET_WORD( p + 1 );
426         p += 2;
427         dprintf_dialog(stddeb, " CLASS %04x\n", LOWORD(result->className) );
428         break;
429     default:
430         result->className = (LPCSTR)p;
431         dprintf_dialog( stddeb, " CLASS '%p'\n", p );
432         p += lstrlen32W( (LPCWSTR)p ) + 1;
433         break;
434     }
435
436     /* Get the window caption */
437
438     result->caption = (LPCSTR)p;
439     p += lstrlen32W( (LPCWSTR)p ) + 1;
440     dprintf_dialog( stddeb, " CAPTION '%p'\n", result->caption );
441
442     /* Get the font name */
443
444     if (result->style & DS_SETFONT)
445     {
446         result->pointSize = GET_WORD(p);
447         p++;
448         result->faceName = (LPCSTR)p;
449         p += lstrlen32W( (LPCWSTR)p ) + 1;
450         dprintf_dialog( stddeb, " FONT %d,'%p'\n",
451                         result->pointSize, result->faceName );
452     }
453     /* First control is on dword boundary */
454     return (LPCSTR)((((int)p) + 3) & ~3);
455 }
456
457
458 /***********************************************************************
459  *           DIALOG_CreateIndirect
460  */
461 static HWND DIALOG_CreateIndirect( HINSTANCE32 hInst, LPCSTR dlgTemplate,
462                                    HWND owner, DLGPROC16 dlgProc,
463                                    LPARAM param, WINDOWPROCTYPE procType )
464 {
465     HMENU16 hMenu = 0;
466     HFONT16 hFont = 0;
467     HWND hwnd;
468     RECT16 rect;
469     WND * wndPtr;
470     DLG_TEMPLATE template;
471     DIALOGINFO * dlgInfo;
472     WORD xUnit = xBaseUnit;
473     WORD yUnit = yBaseUnit;
474
475       /* Parse dialog template */
476
477     if (!dlgTemplate) return 0;
478     if (procType != WIN_PROC_16)
479         dlgTemplate = DIALOG_ParseTemplate32( dlgTemplate, &template );
480     else
481         dlgTemplate = DIALOG_ParseTemplate16( dlgTemplate, &template );
482
483       /* Load menu */
484
485     if (template.menuName)
486     {
487         LPSTR str = SEGPTR_STRDUP( template.menuName );  /* FIXME: win32 */
488         hMenu = LoadMenu16( hInst, SEGPTR_GET(str) );
489         SEGPTR_FREE( str );
490     }
491
492       /* Create custom font if needed */
493
494     if (template.style & DS_SETFONT)
495     {
496           /* The font height must be negative as it is a point size */
497           /* (see CreateFont() documentation in the Windows SDK).   */
498         hFont = CreateFont16( -template.pointSize, 0, 0, 0, FW_DONTCARE,
499                             FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
500                             DEFAULT_QUALITY, FF_DONTCARE,
501                             template.faceName );  /* FIXME: win32 */
502         if (hFont)
503         {
504             TEXTMETRIC16 tm;
505             HFONT16 oldFont;
506
507             HDC32 hdc = GetDC32(0);
508             oldFont = SelectObject32( hdc, hFont );
509             GetTextMetrics16( hdc, &tm );
510             SelectObject32( hdc, oldFont );
511             ReleaseDC32( 0, hdc );
512             xUnit = tm.tmAveCharWidth;
513             yUnit = tm.tmHeight;
514             if (!(tm.tmPitchAndFamily & TMPF_FIXED_PITCH))
515                 xBaseUnit = xBaseUnit * 5 / 4;  /* See DIALOG_Init() */
516         }
517     }
518     
519     /* Create dialog main window */
520
521     rect.left = rect.top = 0;
522     rect.right = template.cx * xUnit / 4;
523     rect.bottom = template.cy * yUnit / 8;
524     if (template.style & DS_MODALFRAME)
525         template.exStyle |= WS_EX_DLGMODALFRAME;
526     AdjustWindowRectEx16( &rect, template.style, 
527                           hMenu ? TRUE : FALSE , template.exStyle );
528     rect.right -= rect.left;
529     rect.bottom -= rect.top;
530
531     if ((INT16)template.x == CW_USEDEFAULT16)
532     {
533         rect.left = rect.top = (procType == WIN_PROC_16) ? CW_USEDEFAULT16
534                                                          : CW_USEDEFAULT32;
535     }
536     else
537     {
538         rect.left += template.x * xUnit / 4;
539         rect.top += template.y * yUnit / 8;
540         if ( !(template.style & WS_CHILD) )
541         {
542             INT16 dX, dY;
543
544             if( !(template.style & DS_ABSALIGN) )
545                 ClientToScreen16( owner, (POINT16 *)&rect );
546             
547             /* try to fit it into the desktop */
548
549             if( (dX = rect.left + rect.right + SYSMETRICS_CXDLGFRAME 
550                  - SYSMETRICS_CXSCREEN) > 0 ) rect.left -= dX;
551             if( (dY = rect.top + rect.bottom + SYSMETRICS_CYDLGFRAME
552                  - SYSMETRICS_CYSCREEN) > 0 ) rect.top -= dY;
553             if( rect.left < 0 ) rect.left = 0;
554             if( rect.top < 0 ) rect.top = 0;
555         }
556     }
557
558     if (procType != WIN_PROC_16)
559         hwnd = CreateWindowEx32W(template.exStyle, (LPCWSTR)template.className,
560                                  (LPCWSTR)template.caption,
561                                  template.style & ~WS_VISIBLE,
562                                  rect.left, rect.top, rect.right, rect.bottom,
563                                  owner, hMenu, hInst, NULL );
564     else
565         hwnd = CreateWindowEx16(template.exStyle, template.className,
566                                 template.caption, template.style & ~WS_VISIBLE,
567                                 rect.left, rect.top, rect.right, rect.bottom,
568                                 owner, hMenu, hInst, NULL );
569     if (!hwnd)
570     {
571         if (hFont) DeleteObject32( hFont );
572         if (hMenu) DestroyMenu( hMenu );
573         return 0;
574     }
575     wndPtr = WIN_FindWndPtr( hwnd );
576     wndPtr->flags |= WIN_ISDIALOG;
577
578       /* Initialise dialog extra data */
579
580     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
581     WINPROC_SetProc( &dlgInfo->dlgProc, dlgProc, procType );
582     dlgInfo->hUserFont = hFont;
583     dlgInfo->hMenu     = hMenu;
584     dlgInfo->xBaseUnit = xUnit;
585     dlgInfo->yBaseUnit = yUnit;
586     dlgInfo->msgResult = 0; 
587     dlgInfo->idResult  = 0;
588     dlgInfo->hDialogHeap = 0;
589
590     if (dlgInfo->hUserFont)
591         SendMessage32A( hwnd, WM_SETFONT, (WPARAM32)dlgInfo->hUserFont, 0 );
592
593     /* Create controls */
594
595     if (!DIALOG_CreateControls( wndPtr, dlgTemplate, template.nbItems,
596                                 hInst, (procType != WIN_PROC_16) ))
597     {
598         DestroyWindow( hwnd );
599         return 0;
600     }
601
602     /* Send initialisation messages and set focus */
603
604     dlgInfo->hwndFocus = GetNextDlgTabItem32( hwnd, 0, FALSE );
605     if (SendMessage32A( hwnd, WM_INITDIALOG,
606                         (WPARAM32)dlgInfo->hwndFocus, param ))
607         SetFocus32( dlgInfo->hwndFocus );
608     if (template.style & WS_VISIBLE) ShowWindow( hwnd, SW_SHOW );
609     return hwnd;
610 }
611
612
613 /***********************************************************************
614  *           CreateDialog16   (USER.89)
615  */
616 HWND16 CreateDialog16( HINSTANCE16 hInst, SEGPTR dlgTemplate,
617                        HWND16 owner, DLGPROC16 dlgProc )
618 {
619     return CreateDialogParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
620 }
621
622
623 /***********************************************************************
624  *           CreateDialogParam16   (USER.241)
625  */
626 HWND16 CreateDialogParam16( HINSTANCE16 hInst, SEGPTR dlgTemplate,
627                             HWND16 owner, DLGPROC16 dlgProc, LPARAM param )
628 {
629     HWND16 hwnd = 0;
630     HRSRC16 hRsrc;
631     HGLOBAL16 hmem;
632     LPCVOID data;
633
634     dprintf_dialog(stddeb, "CreateDialogParam16: %04x,%08lx,%04x,%08lx,%ld\n",
635                    hInst, (DWORD)dlgTemplate, owner, (DWORD)dlgProc, param );
636
637     if (!(hRsrc = FindResource16( hInst, dlgTemplate, RT_DIALOG ))) return 0;
638     if (!(hmem = LoadResource16( hInst, hRsrc ))) return 0;
639     if (!(data = LockResource16( hmem ))) hwnd = 0;
640     else hwnd = CreateDialogIndirectParam16( hInst, data, owner,
641                                              dlgProc, param );
642     FreeResource16( hmem );
643     return hwnd;
644 }
645
646
647 /***********************************************************************
648  *           CreateDialogParam32A   (USER32.72)
649  */
650 HWND32 CreateDialogParam32A( HINSTANCE32 hInst, LPCSTR name,
651                              HWND32 owner, DLGPROC32 dlgProc, LPARAM param )
652 {
653     if (HIWORD(name))
654     {
655         LPWSTR str = HEAP_strdupAtoW( GetProcessHeap(), 0, name );
656         HWND32 hwnd = CreateDialogParam32W( hInst, str, owner, dlgProc, param);
657         HeapFree( GetProcessHeap(), 0, str );
658         return hwnd;
659     }
660     return CreateDialogParam32W( hInst, (LPCWSTR)name, owner, dlgProc, param );
661 }
662
663
664 /***********************************************************************
665  *           CreateDialogParam32W   (USER32.73)
666  */
667 HWND32 CreateDialogParam32W( HINSTANCE32 hInst, LPCWSTR name,
668                              HWND32 owner, DLGPROC32 dlgProc, LPARAM param )
669 {
670     HANDLE32 hrsrc = FindResource32W( hInst, name, (LPWSTR)RT_DIALOG );
671     if (!hrsrc) return 0;
672     return CreateDialogIndirectParam32W( hInst,
673                                          (LPVOID)LoadResource32(hInst, hrsrc),
674                                          owner, dlgProc, param );
675 }
676
677
678 /***********************************************************************
679  *           CreateDialogIndirect16   (USER.219)
680  */
681 HWND16 CreateDialogIndirect16( HINSTANCE16 hInst, LPCVOID dlgTemplate,
682                                HWND16 owner, DLGPROC16 dlgProc )
683 {
684     return CreateDialogIndirectParam16( hInst, dlgTemplate, owner, dlgProc, 0);
685 }
686
687
688 /***********************************************************************
689  *           CreateDialogIndirectParam16   (USER.242)
690  */
691 HWND16 CreateDialogIndirectParam16( HINSTANCE16 hInst, LPCVOID dlgTemplate,
692                                     HWND16 owner, DLGPROC16 dlgProc,
693                                     LPARAM param )
694 {
695     return DIALOG_CreateIndirect( hInst, dlgTemplate, owner,
696                                   dlgProc, param, WIN_PROC_16 );
697 }
698
699
700 /***********************************************************************
701  *           CreateDialogIndirectParam32A   (USER32.69)
702  */
703 HWND32 CreateDialogIndirectParam32A( HINSTANCE32 hInst, LPCVOID dlgTemplate,
704                                      HWND32 owner, DLGPROC32 dlgProc,
705                                      LPARAM param )
706 {
707     return DIALOG_CreateIndirect( hInst, dlgTemplate, owner,
708                                   (DLGPROC16)dlgProc, param, WIN_PROC_32A );
709 }
710
711
712 /***********************************************************************
713  *           CreateDialogIndirectParam32W   (USER32.71)
714  */
715 HWND32 CreateDialogIndirectParam32W( HINSTANCE32 hInst, LPCVOID dlgTemplate,
716                                      HWND32 owner, DLGPROC32 dlgProc,
717                                      LPARAM param )
718 {
719     return DIALOG_CreateIndirect( hInst, dlgTemplate, owner,
720                                   (DLGPROC16)dlgProc, param, WIN_PROC_32W );
721 }
722
723
724 /***********************************************************************
725  *           DIALOG_DoDialogBox
726  */
727 static INT32 DIALOG_DoDialogBox( HWND hwnd, HWND owner )
728 {
729     WND * wndPtr;
730     DIALOGINFO * dlgInfo;
731     MSG16 msg;
732     INT32 retval;
733
734       /* Owner must be a top-level window */
735     owner = WIN_GetTopParent( owner );
736     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return -1;
737     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
738     EnableWindow( owner, FALSE );
739     ShowWindow( hwnd, SW_SHOW );
740
741     while (MSG_InternalGetMessage(&msg, hwnd, owner, MSGF_DIALOGBOX, PM_REMOVE,
742                                   !(wndPtr->dwStyle & DS_NOIDLEMSG) ))
743     {
744         if (!IsDialogMessage( hwnd, &msg))
745         {
746             TranslateMessage( &msg );
747             DispatchMessage( &msg );
748         }
749         if (dlgInfo->fEnd) break;
750     }
751     retval = dlgInfo->idResult;
752     EnableWindow( owner, TRUE );
753     DestroyWindow( hwnd );
754     return retval;
755 }
756
757
758 /***********************************************************************
759  *           DialogBox16   (USER.87)
760  */
761 INT16 DialogBox16( HINSTANCE16 hInst, SEGPTR dlgTemplate,
762                    HWND16 owner, DLGPROC16 dlgProc )
763 {
764     return DialogBoxParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
765 }
766
767
768 /***********************************************************************
769  *           DialogBoxParam16   (USER.239)
770  */
771 INT16 DialogBoxParam16( HINSTANCE16 hInst, SEGPTR template,
772                         HWND16 owner, DLGPROC16 dlgProc, LPARAM param )
773 {
774     HWND16 hwnd = CreateDialogParam16( hInst, template, owner, dlgProc, param);
775     if (hwnd) return (INT16)DIALOG_DoDialogBox( hwnd, owner );
776     return -1;
777 }
778
779
780 /***********************************************************************
781  *           DialogBoxParam32A   (USER32.138)
782  */
783 INT32 DialogBoxParam32A( HINSTANCE32 hInst, LPCSTR name,
784                          HWND32 owner, DLGPROC32 dlgProc, LPARAM param )
785 {
786     HWND32 hwnd = CreateDialogParam32A( hInst, name, owner, dlgProc, param );
787     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
788     return -1;
789 }
790
791
792 /***********************************************************************
793  *           DialogBoxParam32W   (USER32.139)
794  */
795 INT32 DialogBoxParam32W( HINSTANCE32 hInst, LPCWSTR name,
796                          HWND32 owner, DLGPROC32 dlgProc, LPARAM param )
797 {
798     HWND32 hwnd = CreateDialogParam32W( hInst, name, owner, dlgProc, param );
799     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
800     return -1;
801 }
802
803
804 /***********************************************************************
805  *           DialogBoxIndirect16   (USER.218)
806  */
807 INT16 DialogBoxIndirect16( HINSTANCE16 hInst, HANDLE16 dlgTemplate,
808                            HWND16 owner, DLGPROC16 dlgProc )
809 {
810     return DialogBoxIndirectParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
811 }
812
813
814 /***********************************************************************
815  *           DialogBoxIndirectParam16   (USER.240)
816  */
817 INT16 DialogBoxIndirectParam16( HINSTANCE16 hInst, HANDLE16 dlgTemplate,
818                                 HWND16 owner, DLGPROC16 dlgProc, LPARAM param )
819 {
820     HWND16 hwnd;
821     LPCVOID ptr;
822
823     if (!(ptr = GlobalLock16( dlgTemplate ))) return -1;
824     hwnd = CreateDialogIndirectParam16( hInst, ptr, owner, dlgProc, param );
825     GlobalUnlock16( dlgTemplate );
826     if (hwnd) return (INT16)DIALOG_DoDialogBox( hwnd, owner );
827     return -1;
828 }
829
830
831 /***********************************************************************
832  *           DialogBoxIndirectParam32A   (USER32.135)
833  */
834 INT32 DialogBoxIndirectParam32A( HINSTANCE32 hInstance, LPCVOID template,
835                                  HWND32 owner, DLGPROC32 dlgProc ,LPARAM param)
836 {
837     HWND32 hwnd = CreateDialogIndirectParam32A( hInstance, template,
838                                                 owner, dlgProc, param );
839     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
840     return -1;
841 }
842
843
844 /***********************************************************************
845  *           DialogBoxIndirectParam32W   (USER32.137)
846  */
847 INT32 DialogBoxIndirectParam32W( HINSTANCE32 hInstance, LPCVOID template,
848                                  HWND32 owner, DLGPROC32 dlgProc ,LPARAM param)
849 {
850     HWND32 hwnd = CreateDialogIndirectParam32W( hInstance, template,
851                                                 owner, dlgProc, param );
852     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
853     return -1;
854 }
855
856
857 /***********************************************************************
858  *           EndDialog   (USER.88) (USER32.173)
859  */
860 BOOL16 EndDialog( HWND32 hwnd, INT32 retval )
861 {
862     WND * wndPtr = WIN_FindWndPtr( hwnd );
863     DIALOGINFO * dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
864     dlgInfo->idResult = retval;
865     dlgInfo->fEnd = TRUE;
866     dprintf_dialog(stddeb, "EndDialog: %04x %d\n", hwnd, retval );
867     return TRUE;
868 }
869
870
871 /***********************************************************************
872  *           IsDialogMessage   (USER.90)
873  */
874 BOOL IsDialogMessage( HWND hwndDlg, LPMSG16 msg )
875 {
876     WND * wndPtr;
877     int dlgCode;
878
879     if (!(wndPtr = WIN_FindWndPtr( hwndDlg ))) return FALSE;
880     if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd )) return FALSE;
881
882       /* Only the key messages get special processing */
883     if ((msg->message != WM_KEYDOWN) &&
884         (msg->message != WM_SYSCHAR) &&
885         (msg->message != WM_CHAR))
886         return FALSE;
887
888     dlgCode = SendMessage16( msg->hwnd, WM_GETDLGCODE, 0, 0 );
889     if (dlgCode & DLGC_WANTMESSAGE)
890     {
891         DispatchMessage( msg );
892         return TRUE;
893     }
894
895     switch(msg->message)
896     {
897     case WM_KEYDOWN:
898         if (dlgCode & DLGC_WANTALLKEYS) break;
899         switch(msg->wParam)
900         {
901         case VK_TAB:
902             if (!(dlgCode & DLGC_WANTTAB))
903             {
904                 SendMessage16( hwndDlg, WM_NEXTDLGCTL,
905                              (GetKeyState(VK_SHIFT) & 0x8000), 0 );
906                 return TRUE;
907             }
908             break;
909             
910         case VK_RIGHT:
911         case VK_DOWN:
912             if (!(dlgCode & DLGC_WANTARROWS))
913             {
914                 SetFocus32( GetNextDlgGroupItem32( hwndDlg, GetFocus32(),
915                                                    FALSE ) );
916                 return TRUE;
917             }
918             break;
919
920         case VK_LEFT:
921         case VK_UP:
922             if (!(dlgCode & DLGC_WANTARROWS))
923             {
924                 SetFocus32( GetNextDlgGroupItem32( hwndDlg, GetFocus32(),
925                                                    TRUE ) );
926                 return TRUE;
927             }
928             break;
929
930         case VK_ESCAPE:
931             SendMessage32A( hwndDlg, WM_COMMAND, IDCANCEL,
932                             (LPARAM)GetDlgItem( hwndDlg, IDCANCEL ) );
933             break;
934
935         case VK_RETURN:
936             {
937                 DWORD dw = SendMessage16( hwndDlg, DM_GETDEFID, 0, 0 );
938                 if (HIWORD(dw) == DC_HASDEFID)
939                     SendMessage32A( hwndDlg, WM_COMMAND, 
940                                     MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
941                                     (LPARAM)GetDlgItem( hwndDlg, LOWORD(dw) ));
942                 else
943                     SendMessage32A( hwndDlg, WM_COMMAND, IDOK,
944                                     (LPARAM)GetDlgItem( hwndDlg, IDOK ) );
945             }
946             break;
947
948         default: 
949             TranslateMessage( msg );
950         }
951         break;  /* case WM_KEYDOWN */
952
953         
954     case WM_CHAR:
955         if (dlgCode & (DLGC_WANTALLKEYS | DLGC_WANTCHARS)) break;
956         break;
957
958     case WM_SYSCHAR:
959         if (dlgCode & DLGC_WANTALLKEYS) break;
960         break;
961     }
962
963       /* If we get here, the message has not been treated specially */
964       /* and can be sent to its destination window. */
965     DispatchMessage( msg );
966     return TRUE;
967 }
968
969
970 /****************************************************************
971  *         GetDlgCtrlID   (USER.277) (USER32.233)
972  */
973 INT16 GetDlgCtrlID( HWND32 hwnd )
974 {
975     WND *wndPtr = WIN_FindWndPtr(hwnd);
976     if (wndPtr) return wndPtr->wIDmenu;
977     else return 0;
978 }
979  
980
981 /***********************************************************************
982  *           GetDlgItem   (USER.91)
983  */
984 HWND GetDlgItem( HWND hwndDlg, WORD id )
985 {
986     WND *pWnd;
987
988     if (!(pWnd = WIN_FindWndPtr( hwndDlg ))) return 0;
989     for (pWnd = pWnd->child; pWnd; pWnd = pWnd->next)
990         if (pWnd->wIDmenu == id) return pWnd->hwndSelf;
991     return 0;
992 }
993
994
995 /*******************************************************************
996  *           SendDlgItemMessage16   (USER.101)
997  */
998 LRESULT SendDlgItemMessage16( HWND16 hwnd, INT16 id, UINT16 msg,
999                               WPARAM16 wParam, LPARAM lParam )
1000 {
1001     HWND16 hwndCtrl = GetDlgItem( hwnd, id );
1002     if (hwndCtrl) return SendMessage16( hwndCtrl, msg, wParam, lParam );
1003     else return 0;
1004 }
1005
1006
1007 /*******************************************************************
1008  *           SendDlgItemMessage32A   (USER32.451)
1009  */
1010 LRESULT SendDlgItemMessage32A( HWND32 hwnd, INT32 id, UINT32 msg,
1011                                WPARAM32 wParam, LPARAM lParam )
1012 {
1013     HWND hwndCtrl = GetDlgItem( (HWND16)hwnd, (INT16)id );
1014     if (hwndCtrl) return SendMessage32A( hwndCtrl, msg, wParam, lParam );
1015     else return 0;
1016 }
1017
1018
1019 /*******************************************************************
1020  *           SendDlgItemMessage32W   (USER32.452)
1021  */
1022 LRESULT SendDlgItemMessage32W( HWND32 hwnd, INT32 id, UINT32 msg,
1023                                WPARAM32 wParam, LPARAM lParam )
1024 {
1025     HWND hwndCtrl = GetDlgItem( (HWND16)hwnd, (INT16)id );
1026     if (hwndCtrl) return SendMessage32W( hwndCtrl, msg, wParam, lParam );
1027     else return 0;
1028 }
1029
1030
1031 /*******************************************************************
1032  *           SetDlgItemText16   (USER.92)
1033  */
1034 void SetDlgItemText16( HWND16 hwnd, INT16 id, SEGPTR lpString )
1035 {
1036     SendDlgItemMessage16( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1037 }
1038
1039
1040 /*******************************************************************
1041  *           SetDlgItemText32A   (USER32.477)
1042  */
1043 void SetDlgItemText32A( HWND32 hwnd, INT32 id, LPCSTR lpString )
1044 {
1045     SendDlgItemMessage32A( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1046 }
1047
1048
1049 /*******************************************************************
1050  *           SetDlgItemText32W   (USER32.478)
1051  */
1052 void SetDlgItemText32W( HWND32 hwnd, INT32 id, LPCWSTR lpString )
1053 {
1054     SendDlgItemMessage32W( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1055 }
1056
1057
1058 /***********************************************************************
1059  *           GetDlgItemText16   (USER.93)
1060  */
1061 INT16 GetDlgItemText16( HWND16 hwnd, INT16 id, SEGPTR str, UINT16 len )
1062 {
1063     return (INT16)SendDlgItemMessage16( hwnd, id, WM_GETTEXT,
1064                                         len, (LPARAM)str );
1065 }
1066
1067
1068 /***********************************************************************
1069  *           GetDlgItemText32A   (USER32.236)
1070  */
1071 INT32 GetDlgItemText32A( HWND32 hwnd, INT32 id, LPSTR str, UINT32 len )
1072 {
1073     return (INT32)SendDlgItemMessage32A( hwnd, id, WM_GETTEXT,
1074                                          len, (LPARAM)str );
1075 }
1076
1077
1078 /***********************************************************************
1079  *           GetDlgItemText32W   (USER32.237)
1080  */
1081 INT32 GetDlgItemText32W( HWND32 hwnd, INT32 id, LPWSTR str, UINT32 len )
1082 {
1083     return (INT32)SendDlgItemMessage32W( hwnd, id, WM_GETTEXT,
1084                                          len, (LPARAM)str );
1085 }
1086
1087
1088 /*******************************************************************
1089  *           SetDlgItemInt16   (USER.94)
1090  */
1091 void SetDlgItemInt16( HWND16 hwnd, INT16 id, UINT16 value, BOOL16 fSigned )
1092 {
1093     char *str = (char *)SEGPTR_ALLOC( 20 * sizeof(char) );
1094
1095     if (!str) return;
1096     if (fSigned) sprintf( str, "%d", (INT32)(INT16)value );
1097     else sprintf( str, "%u", value );
1098     SendDlgItemMessage16( hwnd, id, WM_SETTEXT, 0, (LPARAM)SEGPTR_GET(str) );
1099     SEGPTR_FREE(str);
1100 }
1101
1102
1103 /*******************************************************************
1104  *           SetDlgItemInt32   (USER32.476)
1105  */
1106 void SetDlgItemInt32( HWND32 hwnd, INT32 id, UINT32 value, BOOL32 fSigned )
1107 {
1108     char str[20];
1109
1110     if (fSigned) sprintf( str, "%d", (INT32)value );
1111     else sprintf( str, "%u", value );
1112     SendDlgItemMessage32A( hwnd, id, WM_SETTEXT, 0, (LPARAM)str );
1113 }
1114
1115
1116 /***********************************************************************
1117  *           GetDlgItemInt   (USER.95)
1118  */
1119 WORD GetDlgItemInt( HWND hwnd, WORD id, BOOL * translated, BOOL fSigned )
1120 {
1121     char *str;
1122     long result = 0;
1123     
1124     if (translated) *translated = FALSE;
1125     if (!(str = (char *)SEGPTR_ALLOC( 30 * sizeof(char) ))) return 0;
1126     if (SendDlgItemMessage16( hwnd, id, WM_GETTEXT, 30, (LPARAM)SEGPTR_GET(str)))
1127     {
1128         char * endptr;
1129         result = strtol( str, &endptr, 10 );
1130         if (endptr && (endptr != str))  /* Conversion was successful */
1131         {
1132             if (fSigned)
1133             {
1134                 if ((result < -32767) || (result > 32767)) result = 0;
1135                 else if (translated) *translated = TRUE;
1136             }
1137             else
1138             {
1139                 if ((result < 0) || (result > 65535)) result = 0;
1140                 else if (translated) *translated = TRUE;
1141             }
1142         }
1143     }
1144     SEGPTR_FREE(str);
1145     return (WORD)result;
1146 }
1147
1148
1149 /***********************************************************************
1150  *           CheckDlgButton   (USER.97) (USER32.44)
1151  */
1152 BOOL16 CheckDlgButton( HWND32 hwnd, INT32 id, UINT32 check )
1153 {
1154     SendDlgItemMessage32A( hwnd, id, BM_SETCHECK32, check, 0 );
1155     return TRUE;
1156 }
1157
1158
1159 /***********************************************************************
1160  *           IsDlgButtonChecked   (USER.98)
1161  */
1162 WORD IsDlgButtonChecked( HWND hwnd, WORD id )
1163 {
1164     return (WORD)SendDlgItemMessage32A( hwnd, id, BM_GETCHECK32, 0, 0 );
1165 }
1166
1167
1168 /***********************************************************************
1169  *           CheckRadioButton   (USER.96) (USER32.47)
1170  */
1171 BOOL16 CheckRadioButton( HWND32 hwndDlg, UINT32 firstID, UINT32 lastID,
1172                          UINT32 checkID )
1173 {
1174     WND *pWnd = WIN_FindWndPtr( hwndDlg );
1175     if (!pWnd) return FALSE;
1176
1177     for (pWnd = pWnd->child; pWnd; pWnd = pWnd->next)
1178         if ((pWnd->wIDmenu == firstID) || (pWnd->wIDmenu == lastID)) break;
1179     if (!pWnd) return FALSE;
1180
1181     if (pWnd->wIDmenu == lastID)
1182         lastID = firstID;  /* Buttons are in reverse order */
1183     while (pWnd)
1184     {
1185         SendMessage32A( pWnd->hwndSelf, BM_SETCHECK32,
1186                         (pWnd->wIDmenu == checkID), 0 );
1187         if (pWnd->wIDmenu == lastID) break;
1188         pWnd = pWnd->next;
1189     }
1190     return TRUE;
1191 }
1192
1193
1194 /***********************************************************************
1195  *           GetDialogBaseUnits   (USER.243)
1196  */
1197 DWORD GetDialogBaseUnits()
1198 {
1199     return MAKELONG( xBaseUnit, yBaseUnit );
1200 }
1201
1202
1203 /***********************************************************************
1204  *           MapDialogRect16   (USER.103)
1205  */
1206 void MapDialogRect16( HWND16 hwnd, LPRECT16 rect )
1207 {
1208     DIALOGINFO * dlgInfo;
1209     WND * wndPtr = WIN_FindWndPtr( hwnd );
1210     if (!wndPtr) return;
1211     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
1212     rect->left   = (rect->left * dlgInfo->xBaseUnit) / 4;
1213     rect->right  = (rect->right * dlgInfo->xBaseUnit) / 4;
1214     rect->top    = (rect->top * dlgInfo->yBaseUnit) / 8;
1215     rect->bottom = (rect->bottom * dlgInfo->yBaseUnit) / 8;
1216 }
1217
1218
1219 /***********************************************************************
1220  *           MapDialogRect32   (USER32.381)
1221  */
1222 void MapDialogRect32( HWND32 hwnd, LPRECT32 rect )
1223 {
1224     DIALOGINFO * dlgInfo;
1225     WND * wndPtr = WIN_FindWndPtr( hwnd );
1226     if (!wndPtr) return;
1227     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
1228     rect->left   = (rect->left * dlgInfo->xBaseUnit) / 4;
1229     rect->right  = (rect->right * dlgInfo->xBaseUnit) / 4;
1230     rect->top    = (rect->top * dlgInfo->yBaseUnit) / 8;
1231     rect->bottom = (rect->bottom * dlgInfo->yBaseUnit) / 8;
1232 }
1233
1234
1235 /***********************************************************************
1236  *           GetNextDlgGroupItem16   (USER.227)
1237  */
1238 HWND16 GetNextDlgGroupItem16(HWND16 hwndDlg, HWND16 hwndCtrl, BOOL16 fPrevious)
1239 {
1240     return (HWND16)GetNextDlgGroupItem32( hwndDlg, hwndCtrl, fPrevious );
1241 }
1242
1243
1244 /***********************************************************************
1245  *           GetNextDlgGroupItem32   (USER32.274)
1246  */
1247 HWND32 GetNextDlgGroupItem32(HWND32 hwndDlg, HWND32 hwndCtrl, BOOL32 fPrevious)
1248 {
1249     WND *pWnd, *pWndLast, *pWndCtrl, *pWndDlg;
1250
1251     if (!(pWndDlg = WIN_FindWndPtr( hwndDlg ))) return 0;
1252     if (hwndCtrl)
1253     {
1254         if (!(pWndCtrl = WIN_FindWndPtr( hwndCtrl ))) return 0;
1255         /* Make sure hwndCtrl is a top-level child */
1256         while ((pWndCtrl->dwStyle & WS_CHILD) && (pWndCtrl->parent != pWndDlg))
1257             pWndCtrl = pWndCtrl->parent;
1258         if (pWndCtrl->parent != pWndDlg) return 0;
1259     }
1260     else
1261     {
1262         /* No ctrl specified -> start from the beginning */
1263         if (!(pWndCtrl = pWndDlg->child)) return 0;
1264         if (fPrevious) while (pWndCtrl->next) pWndCtrl = pWndCtrl->next;
1265     }
1266
1267     pWndLast = pWndCtrl;
1268     pWnd = pWndCtrl->next;
1269     while (1)
1270     {
1271         if (!pWnd || (pWnd->dwStyle & WS_GROUP))
1272         {
1273             /* Wrap-around to the beginning of the group */
1274             WND *pWndStart = pWndDlg->child;
1275             for (pWnd = pWndStart; pWnd; pWnd = pWnd->next)
1276             {
1277                 if (pWnd->dwStyle & WS_GROUP) pWndStart = pWnd;
1278                 if (pWnd == pWndCtrl) break;
1279             }
1280             pWnd = pWndStart;
1281         }
1282         if (pWnd == pWndCtrl) break;
1283         if ((pWnd->dwStyle & WS_VISIBLE) && !(pWnd->dwStyle & WS_DISABLED))
1284         {
1285             pWndLast = pWnd;
1286             if (!fPrevious) break;
1287         }
1288         pWnd = pWnd->next;
1289     }
1290     return pWndLast->hwndSelf;
1291 }
1292
1293
1294 /***********************************************************************
1295  *           GetNextDlgTabItem16   (USER.228)
1296  */
1297 HWND16 GetNextDlgTabItem16( HWND16 hwndDlg, HWND16 hwndCtrl, BOOL16 fPrevious )
1298 {
1299     return (HWND16)GetNextDlgTabItem32( hwndDlg, hwndCtrl, fPrevious );
1300 }
1301
1302
1303 /***********************************************************************
1304  *           GetNextDlgTabItem32   (USER32.275)
1305  */
1306 HWND32 GetNextDlgTabItem32( HWND32 hwndDlg, HWND32 hwndCtrl, BOOL32 fPrevious )
1307 {
1308     WND *pWnd, *pWndLast, *pWndCtrl, *pWndDlg;
1309
1310     if (!(pWndDlg = WIN_FindWndPtr( hwndDlg ))) return 0;
1311     if (hwndCtrl)
1312     {
1313         if (!(pWndCtrl = WIN_FindWndPtr( hwndCtrl ))) return 0;
1314         /* Make sure hwndCtrl is a top-level child */
1315         while ((pWndCtrl->dwStyle & WS_CHILD) && (pWndCtrl->parent != pWndDlg))
1316             pWndCtrl = pWndCtrl->parent;
1317         if (pWndCtrl->parent != pWndDlg) return 0;
1318     }
1319     else
1320     {
1321         /* No ctrl specified -> start from the beginning */
1322         if (!(pWndCtrl = pWndDlg->child)) return 0;
1323         if (fPrevious) while (pWndCtrl->next) pWndCtrl = pWndCtrl->next;
1324     }
1325
1326     pWndLast = pWndCtrl;
1327     pWnd = pWndCtrl->next;
1328     while (1)
1329     {
1330         if (!pWnd) pWnd = pWndDlg->child;
1331         if (pWnd == pWndCtrl) break;
1332         if ((pWnd->dwStyle & WS_TABSTOP) && (pWnd->dwStyle & WS_VISIBLE) &&
1333             !(pWnd->dwStyle & WS_DISABLED))
1334         {
1335             pWndLast = pWnd;
1336             if (!fPrevious) break;
1337         }
1338         pWnd = pWnd->next;
1339     }
1340     return pWndLast->hwndSelf;
1341 }
1342
1343
1344 /**********************************************************************
1345  *           DIALOG_DlgDirSelect
1346  *
1347  * Helper function for DlgDirSelect*
1348  */
1349 static BOOL32 DIALOG_DlgDirSelect( HWND32 hwnd, LPSTR str, INT32 len,
1350                                    INT32 id, BOOL32 win32, BOOL32 unicode,
1351                                    BOOL32 combo )
1352 {
1353     char *buffer, *ptr;
1354     INT32 item, size;
1355     BOOL32 ret;
1356     HWND32 listbox = GetDlgItem( hwnd, id );
1357
1358     dprintf_dialog( stddeb, "DlgDirSelect: %04x '%s' %d\n", hwnd, str, id );
1359     if (!listbox) return FALSE;
1360     if (win32)
1361     {
1362         item = SendMessage32A(listbox, combo ? CB_GETCURSEL32
1363                                              : LB_GETCURSEL32, 0, 0 );
1364         if (item == LB_ERR) return FALSE;
1365         size = SendMessage32A(listbox, combo ? CB_GETLBTEXTLEN32
1366                                              : LB_GETTEXTLEN32, 0, 0 );
1367         if (size == LB_ERR) return FALSE;
1368     }
1369     else
1370     {
1371         item = SendMessage32A(listbox, combo ? CB_GETCURSEL16
1372                                              : LB_GETCURSEL16, 0, 0 );
1373         if (item == LB_ERR) return FALSE;
1374         size = SendMessage32A(listbox, combo ? CB_GETLBTEXTLEN16
1375                                              : LB_GETTEXTLEN16, 0, 0 );
1376         if (size == LB_ERR) return FALSE;
1377     }
1378
1379     if (!(buffer = SEGPTR_ALLOC( size+1 ))) return FALSE;
1380
1381     if (win32)
1382         SendMessage32A( listbox, combo ? CB_GETLBTEXT32 : LB_GETTEXT32,
1383                         item, (LPARAM)buffer );
1384     else
1385         SendMessage16( listbox, combo ? CB_GETLBTEXT16 : LB_GETTEXT16,
1386                        item, (LPARAM)SEGPTR_GET(buffer) );
1387
1388     if ((ret = (buffer[0] == '[')))  /* drive or directory */
1389     {
1390         if (buffer[1] == '-')  /* drive */
1391         {
1392             buffer[3] = ':';
1393             buffer[4] = 0;
1394             ptr = buffer + 2;
1395         }
1396         else
1397         {
1398             buffer[strlen(buffer)-1] = '\\';
1399             ptr = buffer + 1;
1400         }
1401     }
1402     else ptr = buffer;
1403
1404     if (unicode) lstrcpynAtoW( (LPWSTR)str, ptr, len );
1405     else lstrcpyn32A( str, ptr, len );
1406     SEGPTR_FREE( buffer );
1407     dprintf_dialog( stddeb, "Returning %d '%s'\n", ret, str );
1408     return ret;
1409 }
1410
1411
1412 /**********************************************************************
1413  *          DIALOG_DlgDirList
1414  *
1415  * Helper function for DlgDirList*
1416  */
1417 static INT32 DIALOG_DlgDirList( HWND32 hDlg, LPCSTR spec, INT32 idLBox,
1418                                 INT32 idStatic, UINT32 attrib, BOOL32 combo )
1419 {
1420     int drive;
1421     HWND32 hwnd;
1422
1423 #define SENDMSG(msg,wparam,lparam) \
1424     ((attrib & DDL_POSTMSGS) ? PostMessage( hwnd, msg, wparam, lparam ) \
1425                              : SendMessage32A( hwnd, msg, wparam, lparam ))
1426
1427     dprintf_dialog( stddeb, "DlgDirList: %04x '%s' %d %d %04x\n",
1428                     hDlg, spec ? spec : "NULL", idLBox, idStatic, attrib );
1429
1430     if (spec && spec[0] && (spec[1] == ':'))
1431     {
1432         drive = toupper( spec[0] ) - 'A';
1433         spec += 2;
1434         if (!DRIVE_SetCurrentDrive( drive )) return FALSE;
1435     }
1436     else drive = DRIVE_GetCurrentDrive();
1437
1438     if (idLBox && ((hwnd = GetDlgItem( hDlg, idLBox )) != 0))
1439     {
1440         /* If the path exists and is a directory, chdir to it */
1441         if (!spec || !spec[0] || DRIVE_Chdir( drive, spec )) spec = "*.*";
1442         else
1443         {
1444             const char *p, *p2;
1445             p = spec;
1446             if ((p2 = strrchr( p, '\\' ))) p = p2 + 1;
1447             if ((p2 = strrchr( p, '/' ))) p = p2 + 1;
1448             if (p != spec)
1449             {
1450                 BOOL32 ret = FALSE;
1451                 char *dir = HeapAlloc( SystemHeap, 0, p - spec );
1452                 if (dir)
1453                 {
1454                     lstrcpyn32A( dir, spec, p - spec );
1455                     ret = DRIVE_Chdir( drive, dir );
1456                     HeapFree( SystemHeap, 0, dir );
1457                 }
1458                 if (!ret) return FALSE;
1459                 spec = p;
1460             }
1461         }
1462         
1463         dprintf_dialog( stddeb, "ListBoxDirectory: path=%c:\\%s mask=%s\n",
1464                         'A' + drive, DRIVE_GetDosCwd(drive), spec );
1465         
1466         SENDMSG( combo ? CB_RESETCONTENT32 : LB_RESETCONTENT32, 0, 0 );
1467         if ((attrib & DDL_DIRECTORY) && !(attrib & DDL_EXCLUSIVE))
1468         {
1469             if (SENDMSG( combo ? CB_DIR32 : LB_DIR32,
1470                          attrib & ~(DDL_DIRECTORY | DDL_DRIVES),
1471                          (LPARAM)spec ) == LB_ERR)
1472                 return FALSE;
1473             if (SENDMSG( combo ? CB_DIR32 : LB_DIR32,
1474                        (attrib & (DDL_DIRECTORY | DDL_DRIVES)) | DDL_EXCLUSIVE,
1475                          (LPARAM)"*.*" ) == LB_ERR)
1476                 return FALSE;
1477         }
1478         else
1479         {
1480             if (SENDMSG( combo ? CB_DIR32 : LB_DIR32, attrib,
1481                          (LPARAM)spec ) == LB_ERR)
1482                 return FALSE;
1483         }
1484     }
1485
1486     if (idStatic && ((hwnd = GetDlgItem( hDlg, idStatic )) != 0))
1487     {
1488         char temp[512];
1489         int drive = DRIVE_GetCurrentDrive();
1490         strcpy( temp, "A:\\" );
1491         temp[0] += drive;
1492         lstrcpyn32A( temp + 3, DRIVE_GetDosCwd(drive), sizeof(temp)-3 );
1493         AnsiLower( temp );
1494         /* Can't use PostMessage() here, because the string is on the stack */
1495         SetDlgItemText32A( hDlg, idStatic, temp );
1496     }
1497     return TRUE;
1498 #undef SENDMSG
1499 }
1500
1501
1502 /**********************************************************************
1503  *          DlgDirSelect    (USER.99)
1504  */
1505 BOOL16 DlgDirSelect( HWND16 hwnd, LPSTR str, INT16 id )
1506 {
1507     return DlgDirSelectEx16( hwnd, str, 128, id );
1508 }
1509
1510
1511 /**********************************************************************
1512  *          DlgDirSelectComboBox    (USER.194)
1513  */
1514 BOOL16 DlgDirSelectComboBox( HWND16 hwnd, LPSTR str, INT16 id )
1515 {
1516     return DlgDirSelectComboBoxEx16( hwnd, str, 128, id );
1517 }
1518
1519
1520 /**********************************************************************
1521  *           DlgDirSelectEx16    (USER.422)
1522  */
1523 BOOL16 DlgDirSelectEx16( HWND16 hwnd, LPSTR str, INT16 len, INT16 id )
1524 {
1525     return DIALOG_DlgDirSelect( hwnd, str, len, id, FALSE, FALSE, FALSE );
1526 }
1527
1528
1529 /**********************************************************************
1530  *           DlgDirSelectEx32A    (USER32.148)
1531  */
1532 BOOL32 DlgDirSelectEx32A( HWND32 hwnd, LPSTR str, INT32 len, INT32 id )
1533 {
1534     return DIALOG_DlgDirSelect( hwnd, str, len, id, TRUE, FALSE, FALSE );
1535 }
1536
1537
1538 /**********************************************************************
1539  *           DlgDirSelectEx32W    (USER32.149)
1540  */
1541 BOOL32 DlgDirSelectEx32W( HWND32 hwnd, LPWSTR str, INT32 len, INT32 id )
1542 {
1543     return DIALOG_DlgDirSelect( hwnd, (LPSTR)str, len, id, TRUE, TRUE, FALSE );
1544 }
1545
1546
1547 /**********************************************************************
1548  *           DlgDirSelectComboBoxEx16    (USER.423)
1549  */
1550 BOOL16 DlgDirSelectComboBoxEx16( HWND16 hwnd, LPSTR str, INT16 len, INT16 id )
1551 {
1552     return DIALOG_DlgDirSelect( hwnd, str, len, id, FALSE, FALSE, TRUE );
1553 }
1554
1555
1556 /**********************************************************************
1557  *           DlgDirSelectComboBoxEx32A    (USER32.146)
1558  */
1559 BOOL32 DlgDirSelectComboBoxEx32A( HWND32 hwnd, LPSTR str, INT32 len, INT32 id )
1560 {
1561     return DIALOG_DlgDirSelect( hwnd, str, len, id, TRUE, FALSE, TRUE );
1562 }
1563
1564
1565 /**********************************************************************
1566  *           DlgDirSelectComboBoxEx32W    (USER32.147)
1567  */
1568 BOOL32 DlgDirSelectComboBoxEx32W( HWND32 hwnd, LPWSTR str, INT32 len, INT32 id)
1569 {
1570     return DIALOG_DlgDirSelect( hwnd, (LPSTR)str, len, id, TRUE, TRUE, TRUE );
1571 }
1572
1573
1574 /**********************************************************************
1575  *          DlgDirList16    (USER.100)
1576  */
1577 INT16 DlgDirList16( HWND16 hDlg, LPCSTR spec, INT16 idLBox, INT16 idStatic,
1578                     UINT16 attrib )
1579 {
1580     return DIALOG_DlgDirList( hDlg, spec, idLBox, idStatic, attrib, FALSE );
1581 }
1582
1583
1584 /**********************************************************************
1585  *          DlgDirList32A    (USER32.142)
1586  */
1587 INT32 DlgDirList32A( HWND32 hDlg, LPCSTR spec, INT32 idLBox, INT32 idStatic,
1588                      UINT32 attrib )
1589 {
1590     return DIALOG_DlgDirList( hDlg, spec, idLBox, idStatic, attrib, FALSE );
1591 }
1592
1593
1594 /**********************************************************************
1595  *          DlgDirList32W    (USER32.145)
1596  */
1597 INT32 DlgDirList32W( HWND32 hDlg, LPCWSTR spec, INT32 idLBox, INT32 idStatic,
1598                      UINT32 attrib )
1599 {
1600     INT32 ret;
1601     LPSTR specA = HEAP_strdupWtoA( GetProcessHeap(), 0, spec );
1602     ret = DIALOG_DlgDirList( hDlg, specA, idLBox, idStatic, attrib, FALSE );
1603     HeapFree( GetProcessHeap(), 0, specA );
1604     return ret;
1605 }
1606
1607
1608 /**********************************************************************
1609  *          DlgDirListComboBox16    (USER.195)
1610  */
1611 INT16 DlgDirListComboBox16( HWND16 hDlg, LPCSTR spec, INT16 idCBox,
1612                             INT16 idStatic, UINT16 attrib )
1613 {
1614     return DIALOG_DlgDirList( hDlg, spec, idCBox, idStatic, attrib, TRUE );
1615 }
1616
1617
1618 /**********************************************************************
1619  *          DlgDirListComboBox32A    (USER32.143)
1620  */
1621 INT32 DlgDirListComboBox32A( HWND32 hDlg, LPCSTR spec, INT32 idCBox,
1622                              INT32 idStatic, UINT32 attrib )
1623 {
1624     return DIALOG_DlgDirList( hDlg, spec, idCBox, idStatic, attrib, TRUE );
1625 }
1626
1627
1628 /**********************************************************************
1629  *          DlgDirListComboBox32W    (USER32.144)
1630  */
1631 INT32 DlgDirListComboBox32W( HWND32 hDlg, LPCWSTR spec, INT32 idCBox,
1632                              INT32 idStatic, UINT32 attrib )
1633 {
1634     INT32 ret;
1635     LPSTR specA = HEAP_strdupWtoA( GetProcessHeap(), 0, spec );
1636     ret = DIALOG_DlgDirList( hDlg, specA, idCBox, idStatic, attrib, FALSE );
1637     HeapFree( GetProcessHeap(), 0, specA );
1638     return ret;
1639 }