Release 960712
[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 "resource32.h"
16 #include "stackframe.h"
17 #include "string32.h"
18 #include "user.h"
19 #include "winproc.h"
20 #include "message.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 BOOL DIALOG_Init()
67 {
68     TEXTMETRIC16 tm;
69     HDC hdc;
70     
71       /* Calculate the dialog base units */
72
73     if (!(hdc = CreateDC( "DISPLAY", NULL, NULL, NULL ))) return FALSE;
74     GetTextMetrics16( hdc, &tm );
75     DeleteDC( 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) xBaseUnit = xBaseUnit * 5 / 4;
82
83     dprintf_dialog( stddeb, "DIALOG_Init: base units = %d,%d\n",
84                     xBaseUnit, yBaseUnit );
85     return TRUE;
86 }
87
88
89 /***********************************************************************
90  *           DIALOG_GetFirstTabItem
91  *
92  * Return the first item of the dialog that has the WS_TABSTOP style.
93  */
94 HWND DIALOG_GetFirstTabItem( HWND hwndDlg )
95 {
96     WND *pWnd = WIN_FindWndPtr( hwndDlg );
97     for (pWnd = pWnd->child; pWnd; pWnd = pWnd->next)
98         if (pWnd->dwStyle & WS_TABSTOP) return pWnd->hwndSelf;
99     return 0;
100 }
101
102
103 /***********************************************************************
104  *           DIALOG_GetControl16
105  *
106  * Return the class and text of the control pointed to by ptr,
107  * fill the header structure and return a pointer to the next control.
108  */
109 static LPCSTR DIALOG_GetControl16( LPCSTR p, DLG_CONTROL_INFO *info )
110 {
111     static char buffer[10];
112
113     info->x       = GET_WORD(p);  p += sizeof(WORD);
114     info->y       = GET_WORD(p);  p += sizeof(WORD);
115     info->cx      = GET_WORD(p);  p += sizeof(WORD);
116     info->cy      = GET_WORD(p);  p += sizeof(WORD);
117     info->id      = GET_WORD(p);  p += sizeof(WORD);
118     info->style   = GET_DWORD(p); p += sizeof(DWORD);
119     info->exStyle = 0;
120
121     if (*p & 0x80)
122     {
123         switch((BYTE)*p)
124         {
125             case 0x80: strcpy( buffer, "BUTTON" ); break;
126             case 0x81: strcpy( buffer, "EDIT" ); break;
127             case 0x82: strcpy( buffer, "STATIC" ); break;
128             case 0x83: strcpy( buffer, "LISTBOX" ); break;
129             case 0x84: strcpy( buffer, "SCROLLBAR" ); break;
130             case 0x85: strcpy( buffer, "COMBOBOX" ); break;
131             default:   buffer[0] = '\0'; break;
132         }
133         info->className = buffer;
134         p++;
135     }
136     else 
137     {
138         info->className = p;
139         p += strlen(p) + 1;
140     }
141     dprintf_dialog(stddeb, "   %s ", info->className );
142
143     if ((BYTE)*p == 0xff)
144     {
145           /* Integer id, not documented (?). Only works for SS_ICON controls */
146         info->windowName = (LPCSTR)(UINT32)GET_WORD(p+1);
147         p += 3;
148         dprintf_dialog( stddeb,"%04x", LOWORD(info->windowName) );
149     }
150     else
151     {
152         info->windowName = p;
153         p += strlen(p) + 1;
154         dprintf_dialog(stddeb,"'%s'", info->windowName );
155     }
156
157     info->data = (LPVOID)(*p ? p + 1 : NULL);  /* FIXME: should be a segptr */
158     p += *p + 1;
159
160     dprintf_dialog( stddeb," %d, %d, %d, %d, %d, %08lx, %08lx\n", 
161                     info->id, info->x, info->y, info->cx, info->cy,
162                     info->style, (DWORD)info->data);
163     return p;
164 }
165
166
167 /***********************************************************************
168  *           DIALOG_GetControl32
169  *
170  * Return the class and text of the control pointed to by ptr,
171  * fill the header structure and return a pointer to the next control.
172  */
173 static const WORD *DIALOG_GetControl32( const WORD *p, DLG_CONTROL_INFO *info )
174 {
175     static WCHAR buffer[10];
176
177     info->style   = GET_DWORD(p); p += 2;
178     info->exStyle = GET_DWORD(p); p += 2;
179     info->x       = GET_WORD(p); p++;
180     info->y       = GET_WORD(p); p++;
181     info->cx      = GET_WORD(p); p++;
182     info->cy      = GET_WORD(p); p++;
183     info->id      = GET_WORD(p); p++;
184
185     if (GET_WORD(p) == 0xffff)
186     {
187         switch(GET_WORD(p+1))
188         {
189             case 0x80: STRING32_AnsiToUni( buffer, "BUTTON" ); break;
190             case 0x81: STRING32_AnsiToUni( buffer, "EDIT" ); break;
191             case 0x82: STRING32_AnsiToUni( buffer, "STATIC" ); break;
192             case 0x83: STRING32_AnsiToUni( buffer, "LISTBOX" ); break;
193             case 0x84: STRING32_AnsiToUni( buffer, "SCROLLBAR" ); break;
194             case 0x85: STRING32_AnsiToUni( buffer, "COMBOBOX" ); break;
195             default:   buffer[0] = '\0'; break;
196         }
197         info->className = (LPCSTR)buffer;
198         p += 2;
199     }
200     else
201     {
202         info->className = (LPCSTR)p;
203         p += lstrlen32W( (LPCWSTR)p ) + 1;
204     }
205     dprintf_dialog(stddeb, "   %p ", info->className );
206
207     if (GET_WORD(p) == 0xffff)
208     {
209         info->windowName = (LPCSTR)(p + 1);
210         p += 2;
211         dprintf_dialog( stddeb,"%04x", LOWORD(info->windowName) );
212     }
213     else
214     {
215         info->windowName = (LPCSTR)p;
216         p += lstrlen32W( (LPCWSTR)p ) + 1;
217         dprintf_dialog(stddeb,"'%p'", info->windowName );
218     }
219
220     if (GET_WORD(p))
221     {
222         info->data = (LPVOID)(p + 1);
223         p += GET_WORD(p) / sizeof(WORD);
224     }
225     else info->data = NULL;
226     p++;
227
228     dprintf_dialog( stddeb," %d, %d, %d, %d, %d, %08lx, %08lx, %08lx\n", 
229                     info->id, info->x, info->y, info->cx, info->cy,
230                     info->style, info->exStyle, (DWORD)info->data);
231     /* Next control is on dword boundary */
232     return (const WORD *)((((int)p) + 3) & ~3);
233 }
234
235
236 /***********************************************************************
237  *           DIALOG_CreateControls
238  *
239  * Create the control windows for a dialog.
240  */
241 static BOOL32 DIALOG_CreateControls( WND *pWnd, LPCSTR template, INT32 items,
242                                      HINSTANCE32 hInst, BOOL win32 )
243 {
244     DIALOGINFO *dlgInfo = (DIALOGINFO *)pWnd->wExtra;
245     DLG_CONTROL_INFO info;
246     HWND32 hwndCtrl, hwndDefButton = 0;
247
248     dprintf_dialog(stddeb, " BEGIN\n" );
249     while (items--)
250     {
251         if (!win32)
252         {
253             HINSTANCE16 instance;
254             template = DIALOG_GetControl16( template, &info );
255             if (HIWORD(info.className) && !strcmp( info.className, "EDIT") &&
256                 ((info.style & DS_LOCALEDIT) != DS_LOCALEDIT))
257             {
258                 if (!dlgInfo->hDialogHeap)
259                 {
260                     dlgInfo->hDialogHeap = GlobalAlloc16(GMEM_FIXED, 0x10000);
261                     if (!dlgInfo->hDialogHeap)
262                     {
263                         fprintf( stderr, "CreateDialogIndirectParam: Insufficient memory to create heap for edit control\n" );
264                         continue;
265                     }
266                     LocalInit(dlgInfo->hDialogHeap, 0, 0xffff);
267                 }
268                 instance = dlgInfo->hDialogHeap;
269             }
270             else instance = (HINSTANCE16)hInst;
271
272             hwndCtrl = CreateWindowEx16( info.exStyle | WS_EX_NOPARENTNOTIFY,
273                                          info.className, info.windowName,
274                                          info.style | WS_CHILD,
275                                          info.x * dlgInfo->xBaseUnit / 4,
276                                          info.y * dlgInfo->yBaseUnit / 8,
277                                          info.cx * dlgInfo->xBaseUnit / 4,
278                                          info.cy * dlgInfo->yBaseUnit / 8,
279                                          pWnd->hwndSelf, (HMENU)info.id,
280                                          instance, info.data );
281         }
282         else
283         {
284             template = (LPCSTR)DIALOG_GetControl32( (WORD *)template, &info );
285             hwndCtrl = CreateWindowEx32W( info.exStyle | WS_EX_NOPARENTNOTIFY,
286                                           (LPCWSTR)info.className,
287                                           (LPCWSTR)info.windowName,
288                                           info.style | WS_CHILD,
289                                           info.x * dlgInfo->xBaseUnit / 4,
290                                           info.y * dlgInfo->yBaseUnit / 8,
291                                           info.cx * dlgInfo->xBaseUnit / 4,
292                                           info.cy * dlgInfo->yBaseUnit / 8,
293                                           pWnd->hwndSelf, (HMENU)info.id,
294                                           hInst, info.data );
295         }
296         if (!hwndCtrl) return FALSE;
297
298             /* Send initialisation messages to the control */
299         if (dlgInfo->hUserFont) SendMessage32A( hwndCtrl, WM_SETFONT,
300                                                (WPARAM)dlgInfo->hUserFont, 0 );
301         if (SendMessage32A(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
302         {
303               /* If there's already a default push-button, set it back */
304               /* to normal and use this one instead. */
305             if (hwndDefButton)
306                 SendMessage32A( hwndDefButton, BM_SETSTYLE32,
307                                 BS_PUSHBUTTON,FALSE );
308             hwndDefButton = hwndCtrl;
309             dlgInfo->msgResult = GetWindowWord( hwndCtrl, GWW_ID );
310         }
311     }    
312     dprintf_dialog(stddeb, " END\n" );
313     return TRUE;
314 }
315
316
317 /***********************************************************************
318  *           DIALOG_ParseTemplate16
319  *
320  * Fill a DLG_TEMPLATE structure from the dialog template, and return
321  * a pointer to the first control.
322  */
323 static LPCSTR DIALOG_ParseTemplate16( LPCSTR p, DLG_TEMPLATE * result )
324 {
325     result->style   = GET_DWORD(p); p += sizeof(DWORD);
326     result->exStyle = 0;
327     result->nbItems = *p++;
328     result->x       = GET_WORD(p);  p += sizeof(WORD);
329     result->y       = GET_WORD(p);  p += sizeof(WORD);
330     result->cx      = GET_WORD(p);  p += sizeof(WORD);
331     result->cy      = GET_WORD(p);  p += sizeof(WORD);
332     dprintf_dialog( stddeb, "DIALOG %d, %d, %d, %d\n",
333                     result->x, result->y, result->cx, result->cy );
334     dprintf_dialog( stddeb, " STYLE %08lx\n", result->style );
335
336     /* Get the menu name */
337
338     switch( (BYTE)*p )
339     {
340     case 0:
341         result->menuName = 0;
342         p++;
343         break;
344     case 0xff:
345         result->menuName = (LPCSTR)(UINT32)GET_WORD( p + 1 );
346         p += 3;
347         dprintf_dialog(stddeb, " MENU %04x\n", LOWORD(result->menuName) );
348         break;
349     default:
350         result->menuName = p;
351         dprintf_dialog( stddeb, " MENU '%s'\n", p );
352         p += strlen(p) + 1;
353         break;
354     }
355
356     /* Get the class name */
357
358     if (*p)
359     {
360         result->className = p;
361         dprintf_dialog( stddeb, " CLASS '%s'\n", result->className );
362     }
363     else result->className = DIALOG_CLASS_ATOM;
364     p += strlen(p) + 1;
365
366     /* Get the window caption */
367
368     result->caption = p;
369     p += strlen(p) + 1;
370     dprintf_dialog( stddeb, " CAPTION '%s'\n", result->caption );
371
372     /* Get the font name */
373
374     if (result->style & DS_SETFONT)
375     {
376         result->pointSize = GET_WORD(p);
377         p += sizeof(WORD);
378         result->faceName = p;
379         p += strlen(p) + 1;
380         dprintf_dialog( stddeb, " FONT %d,'%s'\n",
381                         result->pointSize, result->faceName );
382     }
383     return p;
384 }
385
386
387 /***********************************************************************
388  *           DIALOG_ParseTemplate32
389  *
390  * Fill a DLG_TEMPLATE structure from the dialog template, and return
391  * a pointer to the first control.
392  */
393 static LPCSTR DIALOG_ParseTemplate32( LPCSTR template, DLG_TEMPLATE * result )
394 {
395     const WORD *p = (const WORD *)template;
396
397     result->style   = GET_DWORD(p); p += 2;
398     result->exStyle = GET_DWORD(p); p += 2;
399     result->nbItems = GET_WORD(p); p++;
400     result->x       = GET_WORD(p); p++;
401     result->y       = GET_WORD(p); p++;
402     result->cx      = GET_WORD(p); p++;
403     result->cy      = GET_WORD(p); p++;
404     dprintf_dialog( stddeb, "DIALOG %d, %d, %d, %d\n",
405                     result->x, result->y, result->cx, result->cy );
406     dprintf_dialog( stddeb, " STYLE %08lx\n", result->style );
407     dprintf_dialog( stddeb, " EXSTYLE %08lx\n", result->exStyle );
408
409     /* Get the menu name */
410
411     switch(GET_WORD(p))
412     {
413     case 0x0000:
414         result->menuName = NULL;
415         p++;
416         break;
417     case 0xffff:
418         result->menuName = (LPCSTR)(UINT32)GET_WORD( p + 1 );
419         p += 2;
420         dprintf_dialog(stddeb, " MENU %04x\n", LOWORD(result->menuName) );
421         break;
422     default:
423         result->menuName = (LPCSTR)p;
424         dprintf_dialog( stddeb, " MENU '%p'\n", p );
425         p += lstrlen32W( (LPCWSTR)p ) + 1;
426         break;
427     }
428
429     /* Get the class name */
430
431     switch(GET_WORD(p))
432     {
433     case 0x0000:
434         result->className = DIALOG_CLASS_ATOM;
435         p++;
436         break;
437     case 0xffff:
438         result->className = (LPCSTR)(UINT32)GET_WORD( p + 1 );
439         p += 2;
440         dprintf_dialog(stddeb, " CLASS %04x\n", LOWORD(result->className) );
441         break;
442     default:
443         result->className = (LPCSTR)p;
444         dprintf_dialog( stddeb, " CLASS '%p'\n", p );
445         p += lstrlen32W( (LPCWSTR)p ) + 1;
446         break;
447     }
448
449     /* Get the window caption */
450
451     result->caption = (LPCSTR)p;
452     p += lstrlen32W( (LPCWSTR)p ) + 1;
453     dprintf_dialog( stddeb, " CAPTION '%p'\n", result->caption );
454
455     /* Get the font name */
456
457     if (result->style & DS_SETFONT)
458     {
459         result->pointSize = GET_WORD(p);
460         p++;
461         result->faceName = (LPCSTR)p;
462         p += lstrlen32W( (LPCWSTR)p ) + 1;
463         dprintf_dialog( stddeb, " FONT %d,'%p'\n",
464                         result->pointSize, result->faceName );
465     }
466     /* First control is on dword boundary */
467     return (LPCSTR)((((int)p) + 3) & ~3);
468 }
469
470
471 /***********************************************************************
472  *           DIALOG_CreateIndirect
473  */
474 static HWND DIALOG_CreateIndirect( HINSTANCE hInst, LPCSTR dlgTemplate,
475                                    HWND owner, DLGPROC16 dlgProc,
476                                    LPARAM param, WINDOWPROCTYPE procType )
477 {
478     HMENU hMenu = 0;
479     HFONT hFont = 0;
480     HWND hwnd;
481     RECT16 rect;
482     WND * wndPtr;
483     DLG_TEMPLATE template;
484     DIALOGINFO * dlgInfo;
485     WORD xUnit = xBaseUnit;
486     WORD yUnit = yBaseUnit;
487
488       /* Parse dialog template */
489
490     if (!dlgTemplate) return 0;
491     if (procType != WIN_PROC_16)
492         dlgTemplate = DIALOG_ParseTemplate32( dlgTemplate, &template );
493     else
494         dlgTemplate = DIALOG_ParseTemplate16( dlgTemplate, &template );
495
496       /* Load menu */
497
498     if (template.menuName)
499     {
500         LPSTR str = SEGPTR_STRDUP( template.menuName );  /* FIXME: win32 */
501         hMenu = LoadMenu( hInst, SEGPTR_GET(str) );
502         SEGPTR_FREE( str );
503     }
504
505       /* Create custom font if needed */
506
507     if (template.style & DS_SETFONT)
508     {
509           /* The font height must be negative as it is a point size */
510           /* (see CreateFont() documentation in the Windows SDK).   */
511         hFont = CreateFont( -template.pointSize, 0, 0, 0, FW_DONTCARE,
512                             FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
513                             DEFAULT_QUALITY, FF_DONTCARE,
514                             template.faceName );  /* FIXME: win32 */
515         if (hFont)
516         {
517             TEXTMETRIC16 tm;
518             HFONT oldFont;
519             HDC hdc;
520
521             hdc = GetDC(0);
522             oldFont = SelectObject( hdc, hFont );
523             GetTextMetrics16( hdc, &tm );
524             SelectObject( hdc, oldFont );
525             ReleaseDC( 0, hdc );
526             xUnit = tm.tmAveCharWidth;
527             yUnit = tm.tmHeight;
528             if (tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
529                 xBaseUnit = xBaseUnit * 5 / 4;  /* See DIALOG_Init() */
530         }
531     }
532     
533     /* Create dialog main window */
534
535     rect.left = rect.top = 0;
536     rect.right = template.cx * xUnit / 4;
537     rect.bottom = template.cy * yUnit / 8;
538     if (template.style & DS_MODALFRAME)
539         template.exStyle |= WS_EX_DLGMODALFRAME;
540     AdjustWindowRectEx16( &rect, template.style, 
541                           hMenu ? TRUE : FALSE , template.exStyle );
542     rect.right -= rect.left;
543     rect.bottom -= rect.top;
544
545     if ((INT16)template.x == CW_USEDEFAULT16)
546     {
547         rect.left = rect.top = (procType == WIN_PROC_16) ? CW_USEDEFAULT16
548                                                          : CW_USEDEFAULT32;
549     }
550     else
551     {
552         rect.left += template.x * xUnit / 4;
553         rect.top += template.y * yUnit / 8;
554         if (!(template.style & DS_ABSALIGN))
555             ClientToScreen16( owner, (POINT16 *)&rect );
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) DeleteObject( 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     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     WINPROC_SetProc( &dlgInfo->dlgProc, dlgProc, procType );
600     dlgInfo->hwndFocus = DIALOG_GetFirstTabItem( hwnd );
601     if (dlgInfo->hUserFont)
602         SendMessage32A( hwnd, WM_SETFONT, (WPARAM)dlgInfo->hUserFont, 0 );
603     if (SendMessage32A(hwnd, WM_INITDIALOG, (WPARAM)dlgInfo->hwndFocus, param))
604         SetFocus( dlgInfo->hwndFocus );
605     if (template.style & WS_VISIBLE) ShowWindow( hwnd, SW_SHOW );
606     return hwnd;
607 }
608
609
610 /***********************************************************************
611  *           CreateDialog16   (USER.89)
612  */
613 HWND16 CreateDialog16( HINSTANCE16 hInst, SEGPTR dlgTemplate,
614                        HWND16 owner, DLGPROC16 dlgProc )
615 {
616     return CreateDialogParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
617 }
618
619
620 /***********************************************************************
621  *           CreateDialogParam16   (USER.241)
622  */
623 HWND16 CreateDialogParam16( HINSTANCE16 hInst, SEGPTR dlgTemplate,
624                             HWND16 owner, DLGPROC16 dlgProc, LPARAM param )
625 {
626     HWND16 hwnd = 0;
627     HRSRC hRsrc;
628     HGLOBAL16 hmem;
629     LPCVOID data;
630
631     dprintf_dialog(stddeb, "CreateDialogParam16: %04x,%08lx,%04x,%08lx,%ld\n",
632                    hInst, (DWORD)dlgTemplate, owner, (DWORD)dlgProc, param );
633
634     if (!(hRsrc = FindResource( hInst, dlgTemplate, RT_DIALOG ))) return 0;
635     if (!(hmem = LoadResource( hInst, hRsrc ))) return 0;
636     if (!(data = LockResource( hmem ))) hwnd = 0;
637     else hwnd = CreateDialogIndirectParam16( hInst, data, owner,
638                                              dlgProc, param );
639     FreeResource( hmem );
640     return hwnd;
641 }
642
643
644 /***********************************************************************
645  *           CreateDialogParam32A   (USER32.72)
646  */
647 HWND32 CreateDialogParam32A( HINSTANCE32 hInst, LPCSTR name,
648                              HWND32 owner, DLGPROC32 dlgProc, LPARAM param )
649 {
650     if (HIWORD(name))
651     {
652         LPWSTR str = STRING32_DupAnsiToUni( name );
653         HWND32 hwnd = CreateDialogParam32W( hInst, str, owner, dlgProc, param);
654         free( str );
655         return hwnd;
656     }
657     return CreateDialogParam32W( hInst, (LPCWSTR)name, owner, dlgProc, param );
658 }
659
660
661 /***********************************************************************
662  *           CreateDialogParam32W   (USER32.73)
663  */
664 HWND32 CreateDialogParam32W( HINSTANCE32 hInst, LPCWSTR name,
665                              HWND32 owner, DLGPROC32 dlgProc, LPARAM param )
666 {
667     HANDLE32 hrsrc = FindResource32W( hInst, name, (LPWSTR)RT_DIALOG );
668     if (!hrsrc) return 0;
669     return CreateDialogIndirectParam32W( hInst, 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 }