Release 960728
[wine] / windows / dialog.c
1 /*
2  * Dialog functions
3  *
4  * Copyright 1993, 1994, 1996 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include "windows.h"
11 #include "dialog.h"
12 #include "heap.h"
13 #include "win.h"
14 #include "ldt.h"
15 #include "stackframe.h"
16 #include "string32.h"
17 #include "user.h"
18 #include "winproc.h"
19 #include "message.h"
20 #include "stddebug.h"
21 #include "debug.h"
22
23
24   /* Dialog control information */
25 typedef struct
26 {
27     DWORD      style;
28     DWORD      exStyle;
29     INT16      x;
30     INT16      y;
31     INT16      cx;
32     INT16      cy;
33     UINT16     id;
34     LPCSTR     className;
35     LPCSTR     windowName;
36     LPVOID     data;
37 } DLG_CONTROL_INFO;
38
39   /* Dialog template */
40 typedef struct
41 {
42     DWORD      style;
43     DWORD      exStyle;
44     UINT16     nbItems;
45     INT16      x;
46     INT16      y;
47     INT16      cx;
48     INT16      cy;
49     LPCSTR     menuName;
50     LPCSTR     className;
51     LPCSTR     caption;
52     WORD       pointSize;
53     LPCSTR     faceName;
54 } DLG_TEMPLATE;
55
56   /* Dialog base units */
57 static WORD xBaseUnit = 0, yBaseUnit = 0;
58
59
60 /***********************************************************************
61  *           DIALOG_Init
62  *
63  * Initialisation of the dialog manager.
64  */
65 BOOL DIALOG_Init()
66 {
67     TEXTMETRIC16 tm;
68     HDC hdc;
69     
70       /* Calculate the dialog base units */
71
72     if (!(hdc = CreateDC( "DISPLAY", NULL, NULL, NULL ))) return FALSE;
73     GetTextMetrics16( hdc, &tm );
74     DeleteDC( hdc );
75     xBaseUnit = tm.tmAveCharWidth;
76     yBaseUnit = tm.tmHeight;
77
78       /* Dialog units are based on a proportional system font */
79       /* so we adjust them a bit for a fixed font. */
80     if (tm.tmPitchAndFamily & TMPF_FIXED_PITCH) xBaseUnit = xBaseUnit * 5 / 4;
81
82     dprintf_dialog( stddeb, "DIALOG_Init: base units = %d,%d\n",
83                     xBaseUnit, yBaseUnit );
84     return TRUE;
85 }
86
87
88 /***********************************************************************
89  *           DIALOG_GetFirstTabItem
90  *
91  * Return the first item of the dialog that has the WS_TABSTOP style.
92  */
93 HWND DIALOG_GetFirstTabItem( HWND hwndDlg )
94 {
95     WND *pWnd = WIN_FindWndPtr( hwndDlg );
96     for (pWnd = pWnd->child; pWnd; pWnd = pWnd->next)
97         if (pWnd->dwStyle & WS_TABSTOP) return pWnd->hwndSelf;
98     return 0;
99 }
100
101
102 /***********************************************************************
103  *           DIALOG_GetControl16
104  *
105  * Return the class and text of the control pointed to by ptr,
106  * fill the header structure and return a pointer to the next control.
107  */
108 static LPCSTR DIALOG_GetControl16( LPCSTR p, DLG_CONTROL_INFO *info )
109 {
110     static char buffer[10];
111
112     info->x       = GET_WORD(p);  p += sizeof(WORD);
113     info->y       = GET_WORD(p);  p += sizeof(WORD);
114     info->cx      = GET_WORD(p);  p += sizeof(WORD);
115     info->cy      = GET_WORD(p);  p += sizeof(WORD);
116     info->id      = GET_WORD(p);  p += sizeof(WORD);
117     info->style   = GET_DWORD(p); p += sizeof(DWORD);
118     info->exStyle = 0;
119
120     if (*p & 0x80)
121     {
122         switch((BYTE)*p)
123         {
124             case 0x80: strcpy( buffer, "BUTTON" ); break;
125             case 0x81: strcpy( buffer, "EDIT" ); break;
126             case 0x82: strcpy( buffer, "STATIC" ); break;
127             case 0x83: strcpy( buffer, "LISTBOX" ); break;
128             case 0x84: strcpy( buffer, "SCROLLBAR" ); break;
129             case 0x85: strcpy( buffer, "COMBOBOX" ); break;
130             default:   buffer[0] = '\0'; break;
131         }
132         info->className = buffer;
133         p++;
134     }
135     else 
136     {
137         info->className = p;
138         p += strlen(p) + 1;
139     }
140     dprintf_dialog(stddeb, "   %s ", info->className );
141
142     if ((BYTE)*p == 0xff)
143     {
144           /* Integer id, not documented (?). Only works for SS_ICON controls */
145         info->windowName = (LPCSTR)(UINT32)GET_WORD(p+1);
146         p += 3;
147         dprintf_dialog( stddeb,"%04x", LOWORD(info->windowName) );
148     }
149     else
150     {
151         info->windowName = p;
152         p += strlen(p) + 1;
153         dprintf_dialog(stddeb,"'%s'", info->windowName );
154     }
155
156     info->data = (LPVOID)(*p ? p + 1 : NULL);  /* FIXME: should be a segptr */
157     p += *p + 1;
158
159     dprintf_dialog( stddeb," %d, %d, %d, %d, %d, %08lx, %08lx\n", 
160                     info->id, info->x, info->y, info->cx, info->cy,
161                     info->style, (DWORD)info->data);
162     return p;
163 }
164
165
166 /***********************************************************************
167  *           DIALOG_GetControl32
168  *
169  * Return the class and text of the control pointed to by ptr,
170  * fill the header structure and return a pointer to the next control.
171  */
172 static const WORD *DIALOG_GetControl32( const WORD *p, DLG_CONTROL_INFO *info )
173 {
174     static WCHAR buffer[10];
175
176     info->style   = GET_DWORD(p); p += 2;
177     info->exStyle = GET_DWORD(p); p += 2;
178     info->x       = GET_WORD(p); p++;
179     info->y       = GET_WORD(p); p++;
180     info->cx      = GET_WORD(p); p++;
181     info->cy      = GET_WORD(p); p++;
182     info->id      = GET_WORD(p); p++;
183
184     if (GET_WORD(p) == 0xffff)
185     {
186         switch(GET_WORD(p+1))
187         {
188             case 0x80: STRING32_AnsiToUni( buffer, "BUTTON" ); break;
189             case 0x81: STRING32_AnsiToUni( buffer, "EDIT" ); break;
190             case 0x82: STRING32_AnsiToUni( buffer, "STATIC" ); break;
191             case 0x83: STRING32_AnsiToUni( buffer, "LISTBOX" ); break;
192             case 0x84: STRING32_AnsiToUni( buffer, "SCROLLBAR" ); break;
193             case 0x85: STRING32_AnsiToUni( buffer, "COMBOBOX" ); break;
194             default:   buffer[0] = '\0'; break;
195         }
196         info->className = (LPCSTR)buffer;
197         p += 2;
198     }
199     else
200     {
201         info->className = (LPCSTR)p;
202         p += lstrlen32W( (LPCWSTR)p ) + 1;
203     }
204     dprintf_dialog(stddeb, "   %p ", info->className );
205
206     if (GET_WORD(p) == 0xffff)
207     {
208         info->windowName = (LPCSTR)(p + 1);
209         p += 2;
210         dprintf_dialog( stddeb,"%04x", LOWORD(info->windowName) );
211     }
212     else
213     {
214         info->windowName = (LPCSTR)p;
215         p += lstrlen32W( (LPCWSTR)p ) + 1;
216         dprintf_dialog(stddeb,"'%p'", info->windowName );
217     }
218
219     if (GET_WORD(p))
220     {
221         info->data = (LPVOID)(p + 1);
222         p += GET_WORD(p) / sizeof(WORD);
223     }
224     else info->data = NULL;
225     p++;
226
227     dprintf_dialog( stddeb," %d, %d, %d, %d, %d, %08lx, %08lx, %08lx\n", 
228                     info->id, info->x, info->y, info->cx, info->cy,
229                     info->style, info->exStyle, (DWORD)info->data);
230     /* Next control is on dword boundary */
231     return (const WORD *)((((int)p) + 3) & ~3);
232 }
233
234
235 /***********************************************************************
236  *           DIALOG_CreateControls
237  *
238  * Create the control windows for a dialog.
239  */
240 static BOOL32 DIALOG_CreateControls( WND *pWnd, LPCSTR template, INT32 items,
241                                      HINSTANCE32 hInst, BOOL win32 )
242 {
243     DIALOGINFO *dlgInfo = (DIALOGINFO *)pWnd->wExtra;
244     DLG_CONTROL_INFO info;
245     HWND32 hwndCtrl, hwndDefButton = 0;
246
247     dprintf_dialog(stddeb, " BEGIN\n" );
248     while (items--)
249     {
250         if (!win32)
251         {
252             HINSTANCE16 instance;
253             template = DIALOG_GetControl16( template, &info );
254             if (HIWORD(info.className) && !strcmp( info.className, "EDIT") &&
255                 ((info.style & DS_LOCALEDIT) != DS_LOCALEDIT))
256             {
257                 if (!dlgInfo->hDialogHeap)
258                 {
259                     dlgInfo->hDialogHeap = GlobalAlloc16(GMEM_FIXED, 0x10000);
260                     if (!dlgInfo->hDialogHeap)
261                     {
262                         fprintf( stderr, "CreateDialogIndirectParam: Insufficient memory to create heap for edit control\n" );
263                         continue;
264                     }
265                     LocalInit(dlgInfo->hDialogHeap, 0, 0xffff);
266                 }
267                 instance = dlgInfo->hDialogHeap;
268             }
269             else instance = (HINSTANCE16)hInst;
270
271             hwndCtrl = CreateWindowEx16( info.exStyle | WS_EX_NOPARENTNOTIFY,
272                                          info.className, info.windowName,
273                                          info.style | WS_CHILD,
274                                          info.x * dlgInfo->xBaseUnit / 4,
275                                          info.y * dlgInfo->yBaseUnit / 8,
276                                          info.cx * dlgInfo->xBaseUnit / 4,
277                                          info.cy * dlgInfo->yBaseUnit / 8,
278                                          pWnd->hwndSelf, (HMENU)info.id,
279                                          instance, info.data );
280         }
281         else
282         {
283             template = (LPCSTR)DIALOG_GetControl32( (WORD *)template, &info );
284             hwndCtrl = CreateWindowEx32W( info.exStyle | WS_EX_NOPARENTNOTIFY,
285                                           (LPCWSTR)info.className,
286                                           (LPCWSTR)info.windowName,
287                                           info.style | WS_CHILD,
288                                           info.x * dlgInfo->xBaseUnit / 4,
289                                           info.y * dlgInfo->yBaseUnit / 8,
290                                           info.cx * dlgInfo->xBaseUnit / 4,
291                                           info.cy * dlgInfo->yBaseUnit / 8,
292                                           pWnd->hwndSelf, (HMENU)info.id,
293                                           hInst, info.data );
294         }
295         if (!hwndCtrl) return FALSE;
296
297             /* Send initialisation messages to the control */
298         if (dlgInfo->hUserFont) SendMessage32A( hwndCtrl, WM_SETFONT,
299                                                (WPARAM)dlgInfo->hUserFont, 0 );
300         if (SendMessage32A(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
301         {
302               /* If there's already a default push-button, set it back */
303               /* to normal and use this one instead. */
304             if (hwndDefButton)
305                 SendMessage32A( hwndDefButton, BM_SETSTYLE32,
306                                 BS_PUSHBUTTON,FALSE );
307             hwndDefButton = hwndCtrl;
308             dlgInfo->msgResult = GetWindowWord( hwndCtrl, GWW_ID );
309         }
310     }    
311     dprintf_dialog(stddeb, " END\n" );
312     return TRUE;
313 }
314
315
316 /***********************************************************************
317  *           DIALOG_ParseTemplate16
318  *
319  * Fill a DLG_TEMPLATE structure from the dialog template, and return
320  * a pointer to the first control.
321  */
322 static LPCSTR DIALOG_ParseTemplate16( LPCSTR p, DLG_TEMPLATE * result )
323 {
324     result->style   = GET_DWORD(p); p += sizeof(DWORD);
325     result->exStyle = 0;
326     result->nbItems = *p++;
327     result->x       = GET_WORD(p);  p += sizeof(WORD);
328     result->y       = GET_WORD(p);  p += sizeof(WORD);
329     result->cx      = GET_WORD(p);  p += sizeof(WORD);
330     result->cy      = GET_WORD(p);  p += sizeof(WORD);
331     dprintf_dialog( stddeb, "DIALOG %d, %d, %d, %d\n",
332                     result->x, result->y, result->cx, result->cy );
333     dprintf_dialog( stddeb, " STYLE %08lx\n", result->style );
334
335     /* Get the menu name */
336
337     switch( (BYTE)*p )
338     {
339     case 0:
340         result->menuName = 0;
341         p++;
342         break;
343     case 0xff:
344         result->menuName = (LPCSTR)(UINT32)GET_WORD( p + 1 );
345         p += 3;
346         dprintf_dialog(stddeb, " MENU %04x\n", LOWORD(result->menuName) );
347         break;
348     default:
349         result->menuName = p;
350         dprintf_dialog( stddeb, " MENU '%s'\n", p );
351         p += strlen(p) + 1;
352         break;
353     }
354
355     /* Get the class name */
356
357     if (*p)
358     {
359         result->className = p;
360         dprintf_dialog( stddeb, " CLASS '%s'\n", result->className );
361     }
362     else result->className = DIALOG_CLASS_ATOM;
363     p += strlen(p) + 1;
364
365     /* Get the window caption */
366
367     result->caption = p;
368     p += strlen(p) + 1;
369     dprintf_dialog( stddeb, " CAPTION '%s'\n", result->caption );
370
371     /* Get the font name */
372
373     if (result->style & DS_SETFONT)
374     {
375         result->pointSize = GET_WORD(p);
376         p += sizeof(WORD);
377         result->faceName = p;
378         p += strlen(p) + 1;
379         dprintf_dialog( stddeb, " FONT %d,'%s'\n",
380                         result->pointSize, result->faceName );
381     }
382     return p;
383 }
384
385
386 /***********************************************************************
387  *           DIALOG_ParseTemplate32
388  *
389  * Fill a DLG_TEMPLATE structure from the dialog template, and return
390  * a pointer to the first control.
391  */
392 static LPCSTR DIALOG_ParseTemplate32( LPCSTR template, DLG_TEMPLATE * result )
393 {
394     const WORD *p = (const WORD *)template;
395
396     result->style   = GET_DWORD(p); p += 2;
397     result->exStyle = GET_DWORD(p); p += 2;
398     result->nbItems = GET_WORD(p); p++;
399     result->x       = GET_WORD(p); p++;
400     result->y       = GET_WORD(p); p++;
401     result->cx      = GET_WORD(p); p++;
402     result->cy      = GET_WORD(p); p++;
403     dprintf_dialog( stddeb, "DIALOG %d, %d, %d, %d\n",
404                     result->x, result->y, result->cx, result->cy );
405     dprintf_dialog( stddeb, " STYLE %08lx\n", result->style );
406     dprintf_dialog( stddeb, " EXSTYLE %08lx\n", result->exStyle );
407
408     /* Get the menu name */
409
410     switch(GET_WORD(p))
411     {
412     case 0x0000:
413         result->menuName = NULL;
414         p++;
415         break;
416     case 0xffff:
417         result->menuName = (LPCSTR)(UINT32)GET_WORD( p + 1 );
418         p += 2;
419         dprintf_dialog(stddeb, " MENU %04x\n", LOWORD(result->menuName) );
420         break;
421     default:
422         result->menuName = (LPCSTR)p;
423         dprintf_dialog( stddeb, " MENU '%p'\n", p );
424         p += lstrlen32W( (LPCWSTR)p ) + 1;
425         break;
426     }
427
428     /* Get the class name */
429
430     switch(GET_WORD(p))
431     {
432     case 0x0000:
433         result->className = DIALOG_CLASS_ATOM;
434         p++;
435         break;
436     case 0xffff:
437         result->className = (LPCSTR)(UINT32)GET_WORD( p + 1 );
438         p += 2;
439         dprintf_dialog(stddeb, " CLASS %04x\n", LOWORD(result->className) );
440         break;
441     default:
442         result->className = (LPCSTR)p;
443         dprintf_dialog( stddeb, " CLASS '%p'\n", p );
444         p += lstrlen32W( (LPCWSTR)p ) + 1;
445         break;
446     }
447
448     /* Get the window caption */
449
450     result->caption = (LPCSTR)p;
451     p += lstrlen32W( (LPCWSTR)p ) + 1;
452     dprintf_dialog( stddeb, " CAPTION '%p'\n", result->caption );
453
454     /* Get the font name */
455
456     if (result->style & DS_SETFONT)
457     {
458         result->pointSize = GET_WORD(p);
459         p++;
460         result->faceName = (LPCSTR)p;
461         p += lstrlen32W( (LPCWSTR)p ) + 1;
462         dprintf_dialog( stddeb, " FONT %d,'%p'\n",
463                         result->pointSize, result->faceName );
464     }
465     /* First control is on dword boundary */
466     return (LPCSTR)((((int)p) + 3) & ~3);
467 }
468
469
470 /***********************************************************************
471  *           DIALOG_CreateIndirect
472  */
473 static HWND DIALOG_CreateIndirect( HINSTANCE hInst, LPCSTR dlgTemplate,
474                                    HWND owner, DLGPROC16 dlgProc,
475                                    LPARAM param, WINDOWPROCTYPE procType )
476 {
477     HMENU hMenu = 0;
478     HFONT hFont = 0;
479     HWND hwnd;
480     RECT16 rect;
481     WND * wndPtr;
482     DLG_TEMPLATE template;
483     DIALOGINFO * dlgInfo;
484     WORD xUnit = xBaseUnit;
485     WORD yUnit = yBaseUnit;
486
487       /* Parse dialog template */
488
489     if (!dlgTemplate) return 0;
490     if (procType != WIN_PROC_16)
491         dlgTemplate = DIALOG_ParseTemplate32( dlgTemplate, &template );
492     else
493         dlgTemplate = DIALOG_ParseTemplate16( dlgTemplate, &template );
494
495       /* Load menu */
496
497     if (template.menuName)
498     {
499         LPSTR str = SEGPTR_STRDUP( template.menuName );  /* FIXME: win32 */
500         hMenu = LoadMenu16( hInst, SEGPTR_GET(str) );
501         SEGPTR_FREE( str );
502     }
503
504       /* Create custom font if needed */
505
506     if (template.style & DS_SETFONT)
507     {
508           /* The font height must be negative as it is a point size */
509           /* (see CreateFont() documentation in the Windows SDK).   */
510         hFont = CreateFont16( -template.pointSize, 0, 0, 0, FW_DONTCARE,
511                             FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
512                             DEFAULT_QUALITY, FF_DONTCARE,
513                             template.faceName );  /* FIXME: win32 */
514         if (hFont)
515         {
516             TEXTMETRIC16 tm;
517             HFONT oldFont;
518             HDC hdc;
519
520             hdc = GetDC(0);
521             oldFont = SelectObject( hdc, hFont );
522             GetTextMetrics16( hdc, &tm );
523             SelectObject( hdc, oldFont );
524             ReleaseDC( 0, hdc );
525             xUnit = tm.tmAveCharWidth;
526             yUnit = tm.tmHeight;
527             if (tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
528                 xBaseUnit = xBaseUnit * 5 / 4;  /* See DIALOG_Init() */
529         }
530     }
531     
532     /* Create dialog main window */
533
534     rect.left = rect.top = 0;
535     rect.right = template.cx * xUnit / 4;
536     rect.bottom = template.cy * yUnit / 8;
537     if (template.style & DS_MODALFRAME)
538         template.exStyle |= WS_EX_DLGMODALFRAME;
539     AdjustWindowRectEx16( &rect, template.style, 
540                           hMenu ? TRUE : FALSE , template.exStyle );
541     rect.right -= rect.left;
542     rect.bottom -= rect.top;
543
544     if ((INT16)template.x == CW_USEDEFAULT16)
545     {
546         rect.left = rect.top = (procType == WIN_PROC_16) ? CW_USEDEFAULT16
547                                                          : CW_USEDEFAULT32;
548     }
549     else
550     {
551         rect.left += template.x * xUnit / 4;
552         rect.top += template.y * yUnit / 8;
553         if (!(template.style & DS_ABSALIGN))
554             ClientToScreen16( owner, (POINT16 *)&rect );
555     }
556
557     if (procType != WIN_PROC_16)
558         hwnd = CreateWindowEx32W(template.exStyle, (LPCWSTR)template.className,
559                                  (LPCWSTR)template.caption,
560                                  template.style & ~WS_VISIBLE,
561                                  rect.left, rect.top, rect.right, rect.bottom,
562                                  owner, hMenu, hInst, NULL );
563     else
564         hwnd = CreateWindowEx16(template.exStyle, template.className,
565                                 template.caption, template.style & ~WS_VISIBLE,
566                                 rect.left, rect.top, rect.right, rect.bottom,
567                                 owner, hMenu, hInst, NULL );
568     if (!hwnd)
569     {
570         if (hFont) DeleteObject( hFont );
571         if (hMenu) DestroyMenu( hMenu );
572         return 0;
573     }
574     wndPtr = WIN_FindWndPtr( hwnd );
575     wndPtr->flags |= WIN_ISDIALOG;
576
577       /* Initialise dialog extra data */
578
579     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
580     WINPROC_SetProc( &dlgInfo->dlgProc, dlgProc, procType );
581     dlgInfo->hUserFont = hFont;
582     dlgInfo->hMenu     = hMenu;
583     dlgInfo->xBaseUnit = xUnit;
584     dlgInfo->yBaseUnit = yUnit;
585     dlgInfo->msgResult = 0;  /* This is used to store the default button id */
586     dlgInfo->hDialogHeap = 0;
587
588     /* Create controls */
589
590     if (!DIALOG_CreateControls( wndPtr, dlgTemplate, template.nbItems,
591                                 hInst, (procType != WIN_PROC_16) ))
592     {
593         DestroyWindow( hwnd );
594         return 0;
595     }
596
597     /* Send initialisation messages and set focus */
598
599     dlgInfo->hwndFocus = DIALOG_GetFirstTabItem( hwnd );
600     if (dlgInfo->hUserFont)
601         SendMessage32A( hwnd, WM_SETFONT, (WPARAM)dlgInfo->hUserFont, 0 );
602     if (SendMessage32A(hwnd, WM_INITDIALOG, (WPARAM)dlgInfo->hwndFocus, param))
603         SetFocus( dlgInfo->hwndFocus );
604     if (template.style & WS_VISIBLE) ShowWindow( hwnd, SW_SHOW );
605     return hwnd;
606 }
607
608
609 /***********************************************************************
610  *           CreateDialog16   (USER.89)
611  */
612 HWND16 CreateDialog16( HINSTANCE16 hInst, SEGPTR dlgTemplate,
613                        HWND16 owner, DLGPROC16 dlgProc )
614 {
615     return CreateDialogParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
616 }
617
618
619 /***********************************************************************
620  *           CreateDialogParam16   (USER.241)
621  */
622 HWND16 CreateDialogParam16( HINSTANCE16 hInst, SEGPTR dlgTemplate,
623                             HWND16 owner, DLGPROC16 dlgProc, LPARAM param )
624 {
625     HWND16 hwnd = 0;
626     HRSRC hRsrc;
627     HGLOBAL16 hmem;
628     LPCVOID data;
629
630     dprintf_dialog(stddeb, "CreateDialogParam16: %04x,%08lx,%04x,%08lx,%ld\n",
631                    hInst, (DWORD)dlgTemplate, owner, (DWORD)dlgProc, param );
632
633     if (!(hRsrc = FindResource16( hInst, dlgTemplate, RT_DIALOG ))) return 0;
634     if (!(hmem = LoadResource16( hInst, hRsrc ))) return 0;
635     if (!(data = LockResource16( hmem ))) hwnd = 0;
636     else hwnd = CreateDialogIndirectParam16( hInst, data, owner,
637                                              dlgProc, param );
638     FreeResource16( hmem );
639     return hwnd;
640 }
641
642
643 /***********************************************************************
644  *           CreateDialogParam32A   (USER32.72)
645  */
646 HWND32 CreateDialogParam32A( HINSTANCE32 hInst, LPCSTR name,
647                              HWND32 owner, DLGPROC32 dlgProc, LPARAM param )
648 {
649     if (HIWORD(name))
650     {
651         LPWSTR str = STRING32_DupAnsiToUni( name );
652         HWND32 hwnd = CreateDialogParam32W( hInst, str, owner, dlgProc, param);
653         free( str );
654         return hwnd;
655     }
656     return CreateDialogParam32W( hInst, (LPCWSTR)name, owner, dlgProc, param );
657 }
658
659
660 /***********************************************************************
661  *           CreateDialogParam32W   (USER32.73)
662  */
663 HWND32 CreateDialogParam32W( HINSTANCE32 hInst, LPCWSTR name,
664                              HWND32 owner, DLGPROC32 dlgProc, LPARAM param )
665 {
666     HANDLE32 hrsrc = FindResource32W( hInst, name, (LPWSTR)RT_DIALOG );
667     if (!hrsrc) return 0;
668     return CreateDialogIndirectParam32W( hInst,
669                                          (LPVOID)LoadResource32(hInst, hrsrc),
670                                          owner, dlgProc, param );
671 }
672
673
674 /***********************************************************************
675  *           CreateDialogIndirect16   (USER.219)
676  */
677 HWND16 CreateDialogIndirect16( HINSTANCE16 hInst, LPCVOID dlgTemplate,
678                                HWND16 owner, DLGPROC16 dlgProc )
679 {
680     return CreateDialogIndirectParam16( hInst, dlgTemplate, owner, dlgProc, 0);
681 }
682
683
684 /***********************************************************************
685  *           CreateDialogIndirectParam16   (USER.242)
686  */
687 HWND16 CreateDialogIndirectParam16( HINSTANCE16 hInst, LPCVOID dlgTemplate,
688                                     HWND16 owner, DLGPROC16 dlgProc,
689                                     LPARAM param )
690 {
691     return DIALOG_CreateIndirect( hInst, dlgTemplate, owner,
692                                   dlgProc, param, WIN_PROC_16 );
693 }
694
695
696 /***********************************************************************
697  *           CreateDialogIndirectParam32A   (USER32.69)
698  */
699 HWND32 CreateDialogIndirectParam32A( HINSTANCE32 hInst, LPCVOID dlgTemplate,
700                                      HWND32 owner, DLGPROC32 dlgProc,
701                                      LPARAM param )
702 {
703     return DIALOG_CreateIndirect( hInst, dlgTemplate, owner,
704                                   (DLGPROC16)dlgProc, param, WIN_PROC_32A );
705 }
706
707
708 /***********************************************************************
709  *           CreateDialogIndirectParam32W   (USER32.71)
710  */
711 HWND32 CreateDialogIndirectParam32W( HINSTANCE32 hInst, LPCVOID dlgTemplate,
712                                      HWND32 owner, DLGPROC32 dlgProc,
713                                      LPARAM param )
714 {
715     return DIALOG_CreateIndirect( hInst, dlgTemplate, owner,
716                                   (DLGPROC16)dlgProc, param, WIN_PROC_32W );
717 }
718
719
720 /***********************************************************************
721  *           DIALOG_DoDialogBox
722  */
723 static INT32 DIALOG_DoDialogBox( HWND hwnd, HWND owner )
724 {
725     WND * wndPtr;
726     DIALOGINFO * dlgInfo;
727     HANDLE msgHandle;
728     MSG16* lpmsg;
729     INT32 retval;
730
731       /* Owner must be a top-level window */
732     owner = WIN_GetTopParent( owner );
733     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return -1;
734     if (!(msgHandle = USER_HEAP_ALLOC( sizeof(MSG16) ))) return -1;
735     lpmsg = (MSG16 *) USER_HEAP_LIN_ADDR( msgHandle );
736     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
737     EnableWindow( owner, FALSE );
738     ShowWindow( hwnd, SW_SHOW );
739
740     while (MSG_InternalGetMessage( (SEGPTR)USER_HEAP_SEG_ADDR(msgHandle), hwnd, owner,
741                                    MSGF_DIALOGBOX, PM_REMOVE,
742                                    !(wndPtr->dwStyle & DS_NOIDLEMSG) ))
743     {
744         if (!IsDialogMessage( hwnd, lpmsg))
745         {
746             TranslateMessage( lpmsg );
747             DispatchMessage( lpmsg );
748         }
749         if (dlgInfo->fEnd) break;
750     }
751     retval = dlgInfo->msgResult;
752     DestroyWindow( hwnd );
753     USER_HEAP_FREE( msgHandle );
754     EnableWindow( owner, TRUE );
755     return retval;
756 }
757
758
759 /***********************************************************************
760  *           DialogBox16   (USER.87)
761  */
762 INT16 DialogBox16( HINSTANCE16 hInst, SEGPTR dlgTemplate,
763                    HWND16 owner, DLGPROC16 dlgProc )
764 {
765     return DialogBoxParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
766 }
767
768
769 /***********************************************************************
770  *           DialogBoxParam16   (USER.239)
771  */
772 INT16 DialogBoxParam16( HINSTANCE16 hInst, SEGPTR template,
773                         HWND16 owner, DLGPROC16 dlgProc, LPARAM param )
774 {
775     HWND16 hwnd = CreateDialogParam16( hInst, template, owner, dlgProc, param);
776     if (hwnd) return (INT16)DIALOG_DoDialogBox( hwnd, owner );
777     return -1;
778 }
779
780
781 /***********************************************************************
782  *           DialogBoxParam32A   (USER32.138)
783  */
784 INT32 DialogBoxParam32A( HINSTANCE32 hInst, LPCSTR name,
785                          HWND32 owner, DLGPROC32 dlgProc, LPARAM param )
786 {
787     HWND32 hwnd = CreateDialogParam32A( hInst, name, owner, dlgProc, param );
788     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
789     return -1;
790 }
791
792
793 /***********************************************************************
794  *           DialogBoxParam32W   (USER32.139)
795  */
796 INT32 DialogBoxParam32W( HINSTANCE32 hInst, LPCWSTR name,
797                          HWND32 owner, DLGPROC32 dlgProc, LPARAM param )
798 {
799     HWND32 hwnd = CreateDialogParam32W( hInst, name, owner, dlgProc, param );
800     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
801     return -1;
802 }
803
804
805 /***********************************************************************
806  *           DialogBoxIndirect16   (USER.218)
807  */
808 INT16 DialogBoxIndirect16( HINSTANCE16 hInst, HANDLE16 dlgTemplate,
809                            HWND16 owner, DLGPROC16 dlgProc )
810 {
811     return DialogBoxIndirectParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
812 }
813
814
815 /***********************************************************************
816  *           DialogBoxIndirectParam16   (USER.240)
817  */
818 INT16 DialogBoxIndirectParam16( HINSTANCE16 hInst, HANDLE16 dlgTemplate,
819                                 HWND16 owner, DLGPROC16 dlgProc, LPARAM param )
820 {
821     HWND16 hwnd;
822     LPCVOID ptr;
823
824     if (!(ptr = GlobalLock16( dlgTemplate ))) return -1;
825     hwnd = CreateDialogIndirectParam16( hInst, ptr, owner, dlgProc, param );
826     GlobalUnlock16( dlgTemplate );
827     if (hwnd) return (INT16)DIALOG_DoDialogBox( hwnd, owner );
828     return -1;
829 }
830
831
832 /***********************************************************************
833  *           DialogBoxIndirectParam32A   (USER32.135)
834  */
835 INT32 DialogBoxIndirectParam32A( HINSTANCE32 hInstance, LPCVOID template,
836                                  HWND32 owner, DLGPROC32 dlgProc ,LPARAM param)
837 {
838     HWND32 hwnd = CreateDialogIndirectParam32A( hInstance, template,
839                                                 owner, dlgProc, param );
840     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
841     return -1;
842 }
843
844
845 /***********************************************************************
846  *           DialogBoxIndirectParam32W   (USER32.137)
847  */
848 INT32 DialogBoxIndirectParam32W( HINSTANCE32 hInstance, LPCVOID template,
849                                  HWND32 owner, DLGPROC32 dlgProc ,LPARAM param)
850 {
851     HWND32 hwnd = CreateDialogIndirectParam32W( hInstance, template,
852                                                 owner, dlgProc, param );
853     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
854     return -1;
855 }
856
857
858 /***********************************************************************
859  *           EndDialog   (USER.88) (USER32.173)
860  */
861 BOOL16 EndDialog( HWND32 hwnd, INT32 retval )
862 {
863     WND * wndPtr = WIN_FindWndPtr( hwnd );
864     DIALOGINFO * dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
865     dlgInfo->msgResult = retval;
866     dlgInfo->fEnd = TRUE;
867     dprintf_dialog(stddeb, "EndDialog: %04x %d\n", hwnd, retval );
868     return TRUE;
869 }
870
871
872 /***********************************************************************
873  *           IsDialogMessage   (USER.90)
874  */
875 BOOL IsDialogMessage( HWND hwndDlg, LPMSG16 msg )
876 {
877     WND * wndPtr;
878     int dlgCode;
879
880     if (!(wndPtr = WIN_FindWndPtr( hwndDlg ))) return FALSE;
881     if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd )) return FALSE;
882
883       /* Only the key messages get special processing */
884     if ((msg->message != WM_KEYDOWN) &&
885         (msg->message != WM_SYSCHAR) &&
886         (msg->message != WM_CHAR))
887         return FALSE;
888
889     dlgCode = SendMessage16( msg->hwnd, WM_GETDLGCODE, 0, 0 );
890     if (dlgCode & DLGC_WANTMESSAGE)
891     {
892         DispatchMessage( msg );
893         return TRUE;
894     }
895
896     switch(msg->message)
897     {
898     case WM_KEYDOWN:
899         if (dlgCode & DLGC_WANTALLKEYS) break;
900         switch(msg->wParam)
901         {
902         case VK_TAB:
903             if (!(dlgCode & DLGC_WANTTAB))
904             {
905                 SendMessage16( hwndDlg, WM_NEXTDLGCTL,
906                              (GetKeyState(VK_SHIFT) & 0x80), 0 );
907                 return TRUE;
908             }
909             break;
910             
911         case VK_RIGHT:
912         case VK_DOWN:
913             if (!(dlgCode & DLGC_WANTARROWS))
914             {
915                 SetFocus(GetNextDlgGroupItem(hwndDlg,GetFocus(),FALSE));
916                 return TRUE;
917             }
918             break;
919
920         case VK_LEFT:
921         case VK_UP:
922             if (!(dlgCode & DLGC_WANTARROWS))
923             {
924                 SetFocus(GetNextDlgGroupItem(hwndDlg,GetFocus(),TRUE));
925                 return TRUE;
926             }
927             break;
928
929         case VK_ESCAPE:
930             SendMessage32A( hwndDlg, WM_COMMAND, IDCANCEL,
931                             (LPARAM)GetDlgItem( hwndDlg, IDCANCEL ) );
932             break;
933
934         case VK_RETURN:
935             {
936                 DWORD dw = SendMessage16( hwndDlg, DM_GETDEFID, 0, 0 );
937                 if (HIWORD(dw) == DC_HASDEFID)
938                     SendMessage32A( hwndDlg, WM_COMMAND, 
939                                     MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
940                                     (LPARAM)GetDlgItem( hwndDlg, LOWORD(dw) ));
941                 else
942                     SendMessage32A( hwndDlg, WM_COMMAND, IDOK,
943                                     (LPARAM)GetDlgItem( hwndDlg, IDOK ) );
944             }
945             break;
946
947         default: 
948             TranslateMessage( msg );
949         }
950         break;  /* case WM_KEYDOWN */
951
952         
953     case WM_CHAR:
954         if (dlgCode & (DLGC_WANTALLKEYS | DLGC_WANTCHARS)) break;
955         break;
956
957     case WM_SYSCHAR:
958         if (dlgCode & DLGC_WANTALLKEYS) break;
959         break;
960     }
961
962       /* If we get here, the message has not been treated specially */
963       /* and can be sent to its destination window. */
964     DispatchMessage( msg );
965     return TRUE;
966 }
967
968
969 /****************************************************************
970  *         GetDlgCtrlID   (USER.277) (USER32.233)
971  */
972 INT16 GetDlgCtrlID( HWND32 hwnd )
973 {
974     WND *wndPtr = WIN_FindWndPtr(hwnd);
975     if (wndPtr) return wndPtr->wIDmenu;
976     else return 0;
977 }
978  
979
980 /***********************************************************************
981  *           GetDlgItem   (USER.91)
982  */
983 HWND GetDlgItem( HWND hwndDlg, WORD id )
984 {
985     WND *pWnd;
986
987     if (!(pWnd = WIN_FindWndPtr( hwndDlg ))) return 0;
988     for (pWnd = pWnd->child; pWnd; pWnd = pWnd->next)
989         if (pWnd->wIDmenu == id) return pWnd->hwndSelf;
990     return 0;
991 }
992
993
994 /*******************************************************************
995  *           SendDlgItemMessage16   (USER.101)
996  */
997 LRESULT SendDlgItemMessage16( HWND16 hwnd, INT16 id, UINT16 msg,
998                               WPARAM16 wParam, LPARAM lParam )
999 {
1000     HWND16 hwndCtrl = GetDlgItem( hwnd, id );
1001     if (hwndCtrl) return SendMessage16( hwndCtrl, msg, wParam, lParam );
1002     else return 0;
1003 }
1004
1005
1006 /*******************************************************************
1007  *           SendDlgItemMessage32A   (USER32.451)
1008  */
1009 LRESULT SendDlgItemMessage32A( HWND32 hwnd, INT32 id, UINT32 msg,
1010                                WPARAM32 wParam, LPARAM lParam )
1011 {
1012     HWND hwndCtrl = GetDlgItem( (HWND16)hwnd, (INT16)id );
1013     if (hwndCtrl) return SendMessage32A( hwndCtrl, msg, wParam, lParam );
1014     else return 0;
1015 }
1016
1017
1018 /*******************************************************************
1019  *           SendDlgItemMessage32W   (USER32.452)
1020  */
1021 LRESULT SendDlgItemMessage32W( HWND32 hwnd, INT32 id, UINT32 msg,
1022                                WPARAM32 wParam, LPARAM lParam )
1023 {
1024     HWND hwndCtrl = GetDlgItem( (HWND16)hwnd, (INT16)id );
1025     if (hwndCtrl) return SendMessage32W( hwndCtrl, msg, wParam, lParam );
1026     else return 0;
1027 }
1028
1029
1030 /*******************************************************************
1031  *           SetDlgItemText16   (USER.92)
1032  */
1033 void SetDlgItemText16( HWND16 hwnd, INT16 id, SEGPTR lpString )
1034 {
1035     SendDlgItemMessage16( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1036 }
1037
1038
1039 /*******************************************************************
1040  *           SetDlgItemText32A   (USER32.477)
1041  */
1042 void SetDlgItemText32A( HWND32 hwnd, INT32 id, LPCSTR lpString )
1043 {
1044     SendDlgItemMessage32A( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1045 }
1046
1047
1048 /*******************************************************************
1049  *           SetDlgItemText32W   (USER32.478)
1050  */
1051 void SetDlgItemText32W( HWND32 hwnd, INT32 id, LPCWSTR lpString )
1052 {
1053     SendDlgItemMessage32W( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
1054 }
1055
1056
1057 /***********************************************************************
1058  *           GetDlgItemText16   (USER.93)
1059  */
1060 INT16 GetDlgItemText16( HWND16 hwnd, INT16 id, SEGPTR str, UINT16 len )
1061 {
1062     return (INT16)SendDlgItemMessage16( hwnd, id, WM_GETTEXT,
1063                                         len, (LPARAM)str );
1064 }
1065
1066
1067 /***********************************************************************
1068  *           GetDlgItemText32A   (USER32.236)
1069  */
1070 INT32 GetDlgItemText32A( HWND32 hwnd, INT32 id, LPSTR str, UINT32 len )
1071 {
1072     return (INT32)SendDlgItemMessage32A( hwnd, id, WM_GETTEXT,
1073                                          len, (LPARAM)str );
1074 }
1075
1076
1077 /***********************************************************************
1078  *           GetDlgItemText32W   (USER32.237)
1079  */
1080 INT32 GetDlgItemText32W( HWND32 hwnd, INT32 id, LPWSTR str, UINT32 len )
1081 {
1082     return (INT32)SendDlgItemMessage32W( hwnd, id, WM_GETTEXT,
1083                                          len, (LPARAM)str );
1084 }
1085
1086
1087 /*******************************************************************
1088  *           SetDlgItemInt16   (USER.94)
1089  */
1090 void SetDlgItemInt16( HWND16 hwnd, INT16 id, UINT16 value, BOOL16 fSigned )
1091 {
1092     char *str = (char *)SEGPTR_ALLOC( 20 * sizeof(char) );
1093
1094     if (!str) return;
1095     if (fSigned) sprintf( str, "%d", (INT32)(INT16)value );
1096     else sprintf( str, "%u", value );
1097     SendDlgItemMessage16( hwnd, id, WM_SETTEXT, 0, (LPARAM)SEGPTR_GET(str) );
1098     SEGPTR_FREE(str);
1099 }
1100
1101
1102 /*******************************************************************
1103  *           SetDlgItemInt32   (USER32.476)
1104  */
1105 void SetDlgItemInt32( HWND32 hwnd, INT32 id, UINT32 value, BOOL32 fSigned )
1106 {
1107     char str[20];
1108
1109     if (fSigned) sprintf( str, "%d", (INT32)value );
1110     else sprintf( str, "%u", value );
1111     SendDlgItemMessage32A( hwnd, id, WM_SETTEXT, 0, (LPARAM)str );
1112 }
1113
1114
1115 /***********************************************************************
1116  *           GetDlgItemInt   (USER.95)
1117  */
1118 WORD GetDlgItemInt( HWND hwnd, WORD id, BOOL * translated, BOOL fSigned )
1119 {
1120     char *str;
1121     long result = 0;
1122     
1123     if (translated) *translated = FALSE;
1124     if (!(str = (char *)SEGPTR_ALLOC( 30 * sizeof(char) ))) return 0;
1125     if (SendDlgItemMessage16( hwnd, id, WM_GETTEXT, 30, (LPARAM)SEGPTR_GET(str)))
1126     {
1127         char * endptr;
1128         result = strtol( str, &endptr, 10 );
1129         if (endptr && (endptr != str))  /* Conversion was successful */
1130         {
1131             if (fSigned)
1132             {
1133                 if ((result < -32767) || (result > 32767)) result = 0;
1134                 else if (translated) *translated = TRUE;
1135             }
1136             else
1137             {
1138                 if ((result < 0) || (result > 65535)) result = 0;
1139                 else if (translated) *translated = TRUE;
1140             }
1141         }
1142     }
1143     SEGPTR_FREE(str);
1144     return (WORD)result;
1145 }
1146
1147
1148 /***********************************************************************
1149  *           CheckDlgButton   (USER.97) (USER32.44)
1150  */
1151 BOOL16 CheckDlgButton( HWND32 hwnd, INT32 id, UINT32 check )
1152 {
1153     SendDlgItemMessage32A( hwnd, id, BM_SETCHECK32, check, 0 );
1154     return TRUE;
1155 }
1156
1157
1158 /***********************************************************************
1159  *           IsDlgButtonChecked   (USER.98)
1160  */
1161 WORD IsDlgButtonChecked( HWND hwnd, WORD id )
1162 {
1163     return (WORD)SendDlgItemMessage16( hwnd, id, BM_GETCHECK16, 0, 0 );
1164 }
1165
1166
1167 /***********************************************************************
1168  *           CheckRadioButton   (USER.96) (USER32.47)
1169  */
1170 BOOL16 CheckRadioButton( HWND32 hwndDlg, UINT32 firstID, UINT32 lastID,
1171                          UINT32 checkID )
1172 {
1173     WND *pWnd = WIN_FindWndPtr( hwndDlg );
1174     if (!pWnd) return FALSE;
1175
1176     for (pWnd = pWnd->child; pWnd; pWnd = pWnd->next)
1177         if ((pWnd->wIDmenu == firstID) || (pWnd->wIDmenu == lastID)) break;
1178     if (!pWnd) return FALSE;
1179
1180     if (pWnd->wIDmenu == lastID)
1181         lastID = firstID;  /* Buttons are in reverse order */
1182     while (pWnd)
1183     {
1184         SendMessage32A( pWnd->hwndSelf, BM_SETCHECK32,
1185                         (pWnd->wIDmenu == checkID), 0 );
1186         if (pWnd->wIDmenu == lastID) break;
1187         pWnd = pWnd->next;
1188     }
1189     return TRUE;
1190 }
1191
1192
1193 /***********************************************************************
1194  *           GetDialogBaseUnits   (USER.243)
1195  */
1196 DWORD GetDialogBaseUnits()
1197 {
1198     return MAKELONG( xBaseUnit, yBaseUnit );
1199 }
1200
1201
1202 /***********************************************************************
1203  *           MapDialogRect16   (USER.103)
1204  */
1205 void MapDialogRect16( HWND16 hwnd, LPRECT16 rect )
1206 {
1207     DIALOGINFO * dlgInfo;
1208     WND * wndPtr = WIN_FindWndPtr( hwnd );
1209     if (!wndPtr) return;
1210     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
1211     rect->left   = (rect->left * dlgInfo->xBaseUnit) / 4;
1212     rect->right  = (rect->right * dlgInfo->xBaseUnit) / 4;
1213     rect->top    = (rect->top * dlgInfo->yBaseUnit) / 8;
1214     rect->bottom = (rect->bottom * dlgInfo->yBaseUnit) / 8;
1215 }
1216
1217
1218 /***********************************************************************
1219  *           MapDialogRect32   (USER32.381)
1220  */
1221 void MapDialogRect32( HWND32 hwnd, LPRECT32 rect )
1222 {
1223     DIALOGINFO * dlgInfo;
1224     WND * wndPtr = WIN_FindWndPtr( hwnd );
1225     if (!wndPtr) return;
1226     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
1227     rect->left   = (rect->left * dlgInfo->xBaseUnit) / 4;
1228     rect->right  = (rect->right * dlgInfo->xBaseUnit) / 4;
1229     rect->top    = (rect->top * dlgInfo->yBaseUnit) / 8;
1230     rect->bottom = (rect->bottom * dlgInfo->yBaseUnit) / 8;
1231 }
1232
1233
1234 /***********************************************************************
1235  *           GetNextDlgGroupItem   (USER.227)
1236  */
1237 HWND GetNextDlgGroupItem( HWND hwndDlg, HWND hwndCtrl, BOOL fPrevious )
1238 {
1239     WND *pWnd, *pWndStart, *pWndCtrl, *pWndDlg;
1240
1241     if (!(pWndDlg = WIN_FindWndPtr( hwndDlg ))) return 0;
1242     if (!(pWndCtrl = WIN_FindWndPtr( hwndCtrl ))) return 0;
1243     if (pWndCtrl->parent != pWndDlg) return 0;
1244
1245     if (!fPrevious && pWndCtrl->next)  /* Check if next control is in group */
1246     {
1247         if (!(pWndCtrl->next->dwStyle & WS_GROUP))
1248             return pWndCtrl->next->hwndSelf;
1249     }
1250
1251       /* Now we will have to find the start of the group */
1252
1253     for (pWnd = pWndStart = pWndDlg->child; pWnd; pWnd = pWnd->next)
1254     {
1255         if (pWnd->dwStyle & WS_GROUP) pWndStart = pWnd;  /* Start of a group */
1256         if (pWnd == pWndCtrl) break;
1257     }
1258
1259     if (!pWnd) fprintf(stderr, "GetNextDlgGroupItem: hwnd not in dialog!\n");
1260
1261       /* only case left for forward search: wraparound */
1262     if (!fPrevious) return pWndStart->hwndSelf;
1263
1264     pWnd = pWndStart->next;
1265     while (pWnd && (pWnd != pWndCtrl))
1266     {
1267         if (pWnd->dwStyle & WS_GROUP) break;
1268         pWndStart = pWnd;
1269         pWnd = pWnd->next;
1270     }
1271     return pWndStart->hwndSelf;
1272 }
1273
1274
1275 /***********************************************************************
1276  *           GetNextDlgTabItem   (USER.228)
1277  */
1278 HWND GetNextDlgTabItem( HWND hwndDlg, HWND hwndCtrl, BOOL fPrevious )
1279 {
1280     WND *pWnd, *pWndLast, *pWndCtrl, *pWndDlg;
1281
1282     if (!(pWndDlg = WIN_FindWndPtr( hwndDlg ))) return 0;
1283     if (!(pWndCtrl = WIN_FindWndPtr( hwndCtrl ))) return 0;
1284     if (pWndCtrl->parent != pWndDlg) return 0;
1285
1286     pWndLast = pWndCtrl;
1287     pWnd = pWndCtrl->next;
1288     while (1)
1289     {
1290         if (!pWnd) pWnd = pWndDlg->child;
1291         if (pWnd == pWndCtrl) break;
1292         if ((pWnd->dwStyle & WS_TABSTOP) && (pWnd->dwStyle & WS_VISIBLE))
1293         {
1294             pWndLast = pWnd;
1295             if (!fPrevious) break;
1296         }
1297         pWnd = pWnd->next;
1298     }
1299     return pWndLast->hwndSelf;
1300 }