[undocuser.h]
[reactos.git] / reactos / dll / win32 / user32 / windows / dialog.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * PROJECT: ReactOS user32.dll
21 * FILE: lib/user32/windows/dialog.c
22 * PURPOSE: Input
23 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
24 * Thomas Weidenmueller (w3seek@users.sourceforge.net)
25 * Steven Edwards (Steven_Ed4153@yahoo.com)
26 * UPDATE HISTORY:
27 * 07-26-2003 Code ported from wine
28 * 09-05-2001 CSH Created
29 */
30
31 /* INCLUDES ******************************************************************/
32
33 #include <user32.h>
34
35 #include <wine/debug.h>
36 WINE_DEFAULT_DEBUG_CHANNEL(user32);
37
38 /* MACROS/DEFINITIONS ********************************************************/
39
40 #define DF_END 0x0001
41 #define DF_OWNERENABLED 0x0002
42 #define DWLP_ROS_DIALOGINFO (DWLP_USER+sizeof(ULONG_PTR))
43 #define GETDLGINFO(hwnd) DIALOG_get_info(hwnd, FALSE)
44 #define SETDLGINFO(hwnd, info) SetWindowLongPtrW((hwnd), DWLP_ROS_DIALOGINFO, (LONG_PTR)(info))
45 #define GET_WORD(ptr) (*(WORD *)(ptr))
46 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
47 void WINAPI WinPosActivateOtherWindow(HWND hwnd);
48
49 /* INTERNAL STRUCTS **********************************************************/
50
51 /* Dialog info structure */
52 typedef struct
53 {
54 HWND hwndFocus; /* Current control with focus */
55 HFONT hUserFont; /* Dialog font */
56 HMENU hMenu; /* Dialog menu */
57 UINT xBaseUnit; /* Dialog units (depends on the font) */
58 UINT yBaseUnit;
59 INT idResult; /* EndDialog() result / default pushbutton ID */
60 UINT flags; /* EndDialog() called for this dialog */
61 } DIALOGINFO;
62
63 /* Dialog control information */
64 typedef struct
65 {
66 DWORD style;
67 DWORD exStyle;
68 DWORD helpId;
69 short x;
70 short y;
71 short cx;
72 short cy;
73 UINT id;
74 LPCWSTR className;
75 LPCWSTR windowName;
76 BOOL windowNameFree;
77 LPCVOID data;
78 } DLG_CONTROL_INFO;
79
80 /* Dialog template */
81 typedef struct
82 {
83 DWORD style;
84 DWORD exStyle;
85 DWORD helpId;
86 WORD nbItems;
87 short x;
88 short y;
89 short cx;
90 short cy;
91 LPCWSTR menuName;
92 LPCWSTR className;
93 LPCWSTR caption;
94 WORD pointSize;
95 WORD weight;
96 BOOL italic;
97 LPCWSTR faceName;
98 BOOL dialogEx;
99 } DLG_TEMPLATE;
100
101 /* CheckRadioButton structure */
102 typedef struct
103 {
104 UINT firstID;
105 UINT lastID;
106 UINT checkID;
107 } RADIOGROUP;
108
109
110 /*********************************************************************
111 * dialog class descriptor
112 */
113 const struct builtin_class_descr DIALOG_builtin_class =
114 {
115 WC_DIALOG, /* name */
116 CS_SAVEBITS | CS_DBLCLKS, /* style */
117 (WNDPROC) DefDlgProcA, /* procA */
118 (WNDPROC) DefDlgProcW, /* procW */
119 DLGWINDOWEXTRA, /* extra */
120 (LPCWSTR) IDC_ARROW, /* cursor */
121 0 /* brush */
122 };
123
124
125 /* INTERNAL FUNCTIONS ********************************************************/
126
127 /***********************************************************************
128 * DIALOG_get_info
129 *
130 * Get the DIALOGINFO structure of a window, allocating it if needed
131 * and 'create' is TRUE.
132 *
133 * ReactOS
134 */
135 DIALOGINFO * DIALOG_get_info( HWND hWnd, BOOL create )
136 {
137 PWND pWindow;
138 DIALOGINFO* dlgInfo = (DIALOGINFO *)GetWindowLongPtrW( hWnd, DWLP_ROS_DIALOGINFO );
139
140 if(!dlgInfo && create)
141 {
142 pWindow = ValidateHwnd( hWnd );
143 if (!pWindow)
144 {
145 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
146 return NULL;
147 }
148
149 if (pWindow && pWindow->cbwndExtra >= DLGWINDOWEXTRA && hWnd != GetDesktopWindow())
150 {
151 if (!(dlgInfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dlgInfo) )))
152 return NULL;
153
154 SETDLGINFO( hWnd, dlgInfo );
155
156 NtUserCallHwndParam( hWnd, (DWORD_PTR)dlgInfo, HWNDPARAM_ROUTINE_SETDIALOGPOINTER );
157 }
158 else
159 {
160 return NULL;
161 }
162 }
163 return dlgInfo;
164 }
165
166 /***********************************************************************
167 * DIALOG_EnableOwner
168 *
169 * Helper function for modal dialogs to enable again the
170 * owner of the dialog box.
171 */
172 void DIALOG_EnableOwner( HWND hOwner )
173 {
174 /* Owner must be a top-level window */
175 if (hOwner)
176 hOwner = GetAncestor( hOwner, GA_ROOT );
177 if (!hOwner) return;
178 EnableWindow( hOwner, TRUE );
179 }
180
181
182 /***********************************************************************
183 * DIALOG_DisableOwner
184 *
185 * Helper function for modal dialogs to disable the
186 * owner of the dialog box. Returns TRUE if owner was enabled.
187 */
188 BOOL DIALOG_DisableOwner( HWND hOwner )
189 {
190 /* Owner must be a top-level window */
191 if (hOwner)
192 hOwner = GetAncestor( hOwner, GA_ROOT );
193 if (!hOwner) return FALSE;
194 if (IsWindowEnabled( hOwner ))
195 {
196 EnableWindow( hOwner, FALSE );
197 return TRUE;
198 }
199 else
200 return FALSE;
201 }
202
203 /***********************************************************************
204 * DIALOG_GetControl32
205 *
206 * Return the class and text of the control pointed to by ptr,
207 * fill the header structure and return a pointer to the next control.
208 */
209 static const WORD *DIALOG_GetControl32( const WORD *p, DLG_CONTROL_INFO *info,
210 BOOL dialogEx )
211 {
212 if (dialogEx)
213 {
214 info->helpId = GET_DWORD(p); p += 2;
215 info->exStyle = GET_DWORD(p); p += 2;
216 info->style = GET_DWORD(p); p += 2;
217 }
218 else
219 {
220 info->helpId = 0;
221 info->style = GET_DWORD(p); p += 2;
222 info->exStyle = GET_DWORD(p); p += 2;
223 }
224 info->x = GET_WORD(p); p++;
225 info->y = GET_WORD(p); p++;
226 info->cx = GET_WORD(p); p++;
227 info->cy = GET_WORD(p); p++;
228
229 if (dialogEx)
230 {
231 /* id is a DWORD for DIALOGEX */
232 info->id = GET_DWORD(p);
233 p += 2;
234 }
235 else
236 {
237 info->id = GET_WORD(p);
238 p++;
239 }
240
241 if (GET_WORD(p) == 0xffff)
242 {
243 static const WCHAR class_names[6][10] =
244 {
245 { 'B','u','t','t','o','n', }, /* 0x80 */
246 { 'E','d','i','t', }, /* 0x81 */
247 { 'S','t','a','t','i','c', }, /* 0x82 */
248 { 'L','i','s','t','B','o','x', }, /* 0x83 */
249 { 'S','c','r','o','l','l','B','a','r', }, /* 0x84 */
250 { 'C','o','m','b','o','B','o','x', } /* 0x85 */
251 };
252 WORD id = GET_WORD(p+1);
253 /* Windows treats dialog control class ids 0-5 same way as 0x80-0x85 */
254 if ((id >= 0x80) && (id <= 0x85)) id -= 0x80;
255 if (id <= 5)
256 info->className = class_names[id];
257 else
258 {
259 info->className = NULL;
260 /* FIXME: load other classes here? */
261 }
262 p += 2;
263 }
264 else
265 {
266 info->className = (LPCWSTR)p;
267 p += strlenW( info->className ) + 1;
268 }
269
270 if (GET_WORD(p) == 0xffff) /* Is it an integer id? */
271 {
272 //// ReactOS Rev 6478
273 info->windowName = HeapAlloc( GetProcessHeap(), 0, sizeof(L"#65535") );
274 if (info->windowName != NULL)
275 {
276 swprintf((LPWSTR)info->windowName, L"#%d", GET_WORD(p + 1));
277 info->windowNameFree = TRUE;
278 }
279 else
280 {
281 info->windowNameFree = FALSE;
282 }
283 p += 2;
284 }
285 else
286 {
287 info->windowName = (LPCWSTR)p;
288 info->windowNameFree = FALSE;
289 p += strlenW( info->windowName ) + 1;
290 }
291
292 if (GET_WORD(p))
293 {
294 info->data = p + 1;
295 p += GET_WORD(p) / sizeof(WORD);
296 }
297 else info->data = NULL;
298 p++;
299
300 /* Next control is on dword boundary */
301 return (const WORD *)(((UINT_PTR)p + 3) & ~3);
302 }
303
304
305 /***********************************************************************
306 * DIALOG_CreateControls32
307 *
308 * Create the control windows for a dialog.
309 */
310 static BOOL DIALOG_CreateControls32( HWND hwnd, LPCSTR template, const DLG_TEMPLATE *dlgTemplate,
311 HINSTANCE hInst, BOOL unicode )
312 {
313 DIALOGINFO * dlgInfo;
314 DLG_CONTROL_INFO info;
315 HWND hwndCtrl, hwndDefButton = 0;
316 INT items = dlgTemplate->nbItems;
317
318 if (!(dlgInfo = GETDLGINFO(hwnd))) return FALSE;
319
320 while (items--)
321 {
322 template = (LPCSTR)DIALOG_GetControl32( (const WORD *)template, &info,
323 dlgTemplate->dialogEx );
324 /* Is this it? */
325 if (info.style & WS_BORDER)
326 {
327 info.style &= ~WS_BORDER;
328 info.exStyle |= WS_EX_CLIENTEDGE;
329 }
330 if (unicode)
331 {
332 hwndCtrl = CreateWindowExW( info.exStyle | WS_EX_NOPARENTNOTIFY,
333 info.className, info.windowName,
334 info.style | WS_CHILD,
335 MulDiv(info.x, dlgInfo->xBaseUnit, 4),
336 MulDiv(info.y, dlgInfo->yBaseUnit, 8),
337 MulDiv(info.cx, dlgInfo->xBaseUnit, 4),
338 MulDiv(info.cy, dlgInfo->yBaseUnit, 8),
339 hwnd, (HMENU)(ULONG_PTR)info.id,
340 hInst, (LPVOID)info.data );
341 }
342 else
343 {
344 LPSTR class = (LPSTR)info.className;
345 LPSTR caption = (LPSTR)info.windowName;
346
347 if (HIWORD(class))
348 {
349 DWORD len = WideCharToMultiByte( CP_ACP, 0, info.className, -1, NULL, 0, NULL, NULL );
350 class = HeapAlloc( GetProcessHeap(), 0, len );
351 if (class != NULL)
352 WideCharToMultiByte( CP_ACP, 0, info.className, -1, class, len, NULL, NULL );
353 }
354 if (HIWORD(caption))
355 {
356 DWORD len = WideCharToMultiByte( CP_ACP, 0, info.windowName, -1, NULL, 0, NULL, NULL );
357 caption = HeapAlloc( GetProcessHeap(), 0, len );
358 if (caption != NULL)
359 WideCharToMultiByte( CP_ACP, 0, info.windowName, -1, caption, len, NULL, NULL );
360 }
361
362 if (class != NULL && caption != NULL)
363 {
364 hwndCtrl = CreateWindowExA( info.exStyle | WS_EX_NOPARENTNOTIFY,
365 class, caption, info.style | WS_CHILD,
366 MulDiv(info.x, dlgInfo->xBaseUnit, 4),
367 MulDiv(info.y, dlgInfo->yBaseUnit, 8),
368 MulDiv(info.cx, dlgInfo->xBaseUnit, 4),
369 MulDiv(info.cy, dlgInfo->yBaseUnit, 8),
370 hwnd, (HMENU)(ULONG_PTR)info.id,
371 hInst, (LPVOID)info.data );
372 }
373 else
374 hwndCtrl = NULL;
375 if (HIWORD(class)) HeapFree( GetProcessHeap(), 0, class );
376 if (HIWORD(caption)) HeapFree( GetProcessHeap(), 0, caption );
377 }
378
379 if (info.windowNameFree)
380 {
381 HeapFree( GetProcessHeap(), 0, (LPVOID)info.windowName );
382 }
383
384 if (!hwndCtrl)
385 {
386 if (dlgTemplate->style & DS_NOFAILCREATE) continue;
387 return FALSE;
388 }
389
390 /* Send initialisation messages to the control */
391 if (dlgInfo->hUserFont) SendMessageW( hwndCtrl, WM_SETFONT,
392 (WPARAM)dlgInfo->hUserFont, 0 );
393 if (SendMessageW(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
394 {
395 /* If there's already a default push-button, set it back */
396 /* to normal and use this one instead. */
397 if (hwndDefButton)
398 SendMessageW( hwndDefButton, BM_SETSTYLE, BS_PUSHBUTTON, FALSE );
399 hwndDefButton = hwndCtrl;
400 dlgInfo->idResult = GetWindowLongPtrA( hwndCtrl, GWLP_ID );
401 }
402 }
403 return TRUE;
404 }
405
406 /***********************************************************************
407 * DIALOG_FindMsgDestination
408 *
409 * The messages that IsDialogMessage sends may not go to the dialog
410 * calling IsDialogMessage if that dialog is a child, and it has the
411 * DS_CONTROL style set.
412 * We propagate up until we hit one that does not have DS_CONTROL, or
413 * whose parent is not a dialog.
414 *
415 * This is undocumented behaviour.
416 */
417 static HWND DIALOG_FindMsgDestination( HWND hwndDlg )
418 {
419 while (GetWindowLongA(hwndDlg, GWL_STYLE) & DS_CONTROL)
420 {
421 PWND pWnd;
422 HWND hParent = GetParent(hwndDlg);
423 if (!hParent) break;
424 // ReactOS
425 if (!IsWindow(hParent)) break;
426
427 pWnd = ValidateHwnd(hParent);
428 // FIXME: Use pWnd->fnid == FNID_DESKTOP
429 if (!pWnd || hParent == GetDesktopWindow()) break;
430
431 if (!(pWnd->state & WNDS_DIALOGWINDOW))
432 {
433 break;
434 }
435
436 hwndDlg = hParent;
437 }
438
439 return hwndDlg;
440 }
441
442 /***********************************************************************
443 * DIALOG_IsAccelerator
444 */
445 static BOOL DIALOG_IsAccelerator( HWND hwnd, HWND hwndDlg, WPARAM wParam )
446 {
447 HWND hwndControl = hwnd;
448 HWND hwndNext;
449 INT dlgCode;
450 WCHAR buffer[128];
451
452 do
453 {
454 DWORD style = GetWindowLongPtrW( hwndControl, GWL_STYLE );
455 if ((style & (WS_VISIBLE | WS_DISABLED)) == WS_VISIBLE)
456 {
457 dlgCode = SendMessageA( hwndControl, WM_GETDLGCODE, 0, 0 );
458 if ( (dlgCode & (DLGC_BUTTON | DLGC_STATIC)) &&
459 GetWindowTextW( hwndControl, buffer, sizeof(buffer)/sizeof(WCHAR) ))
460 {
461 /* find the accelerator key */
462 LPWSTR p = buffer - 2;
463
464 do
465 {
466 p = wcschr( p + 2, '&' );
467 }
468 while (p != NULL && p[1] == '&');
469
470 /* and check if it's the one we're looking for */
471 if (p != NULL && toupperW( p[1] ) == toupperW( wParam ) )
472 {
473 if ((dlgCode & DLGC_STATIC) || (style & 0x0f) == BS_GROUPBOX )
474 {
475 /* set focus to the control */
476 SendMessageW( hwndDlg, WM_NEXTDLGCTL, (WPARAM)hwndControl, 1);
477 /* and bump it on to next */
478 SendMessageW( hwndDlg, WM_NEXTDLGCTL, 0, 0);
479 }
480 else if (dlgCode & DLGC_BUTTON)
481 {
482 /* send BM_CLICK message to the control */
483 SendMessageW( hwndControl, BM_CLICK, 0, 0 );
484 }
485 return TRUE;
486 }
487 }
488 hwndNext = GetWindow( hwndControl, GW_CHILD );
489 }
490 else hwndNext = 0;
491
492 if (!hwndNext) hwndNext = GetWindow( hwndControl, GW_HWNDNEXT );
493
494 while (!hwndNext && hwndControl)
495 {
496 hwndControl = GetParent( hwndControl );
497 if (hwndControl == hwndDlg)
498 {
499 if(hwnd==hwndDlg) /* prevent endless loop */
500 {
501 hwndNext=hwnd;
502 break;
503 }
504 hwndNext = GetWindow( hwndDlg, GW_CHILD );
505 }
506 else
507 hwndNext = GetWindow( hwndControl, GW_HWNDNEXT );
508 }
509 hwndControl = hwndNext;
510 }
511 while (hwndControl && (hwndControl != hwnd));
512
513 return FALSE;
514 }
515
516 /***********************************************************************
517 * DIALOG_DoDialogBox
518 */
519 INT DIALOG_DoDialogBox( HWND hwnd, HWND owner )
520 {
521 DIALOGINFO * dlgInfo;
522 MSG msg;
523 INT retval;
524 HWND ownerMsg = GetAncestor( owner, GA_ROOT );
525 BOOL bFirstEmpty;
526
527 if (!(dlgInfo = GETDLGINFO(hwnd))) return -1;
528
529 bFirstEmpty = TRUE;
530 if (!(dlgInfo->flags & DF_END)) /* was EndDialog called in WM_INITDIALOG ? */
531 {
532 for (;;)
533 {
534 if (!PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ))
535 {
536 if (bFirstEmpty)
537 {
538 /* ShowWindow the first time the queue goes empty */
539 ShowWindow( hwnd, SW_SHOWNORMAL );
540 bFirstEmpty = FALSE;
541 }
542 if (!(GetWindowLongPtrW( hwnd, GWL_STYLE ) & DS_NOIDLEMSG))
543 {
544 /* No message present -> send ENTERIDLE and wait */
545 SendMessageW( ownerMsg, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)hwnd );
546 }
547 if (!GetMessageW( &msg, 0, 0, 0 )) break;
548 }
549
550 if (!IsWindow( hwnd )) return 0;
551 if (!(dlgInfo->flags & DF_END) && !IsDialogMessageW( hwnd, &msg))
552 {
553 TranslateMessage( &msg );
554 DispatchMessageW( &msg );
555 }
556 if (dlgInfo->flags & DF_END) break;
557
558 if (bFirstEmpty && msg.message == WM_TIMER)
559 {
560 ShowWindow( hwnd, SW_SHOWNORMAL );
561 bFirstEmpty = FALSE;
562 }
563 }
564 }
565 if (dlgInfo->flags & DF_OWNERENABLED) DIALOG_EnableOwner( owner );
566 retval = dlgInfo->idResult;
567 DestroyWindow( hwnd );
568 return retval;
569 }
570
571 /***********************************************************************
572 * DIALOG_ParseTemplate32
573 *
574 * Fill a DLG_TEMPLATE structure from the dialog template, and return
575 * a pointer to the first control.
576 */
577 static LPCSTR DIALOG_ParseTemplate32( LPCSTR template, DLG_TEMPLATE * result )
578 {
579 const WORD *p = (const WORD *)template;
580 WORD signature;
581 WORD dlgver;
582
583 dlgver = GET_WORD(p); p++;
584 signature = GET_WORD(p); p++;
585
586 if (dlgver == 1 && signature == 0xffff) /* DIALOGEX resource */
587 {
588 result->dialogEx = TRUE;
589 result->helpId = GET_DWORD(p); p += 2;
590 result->exStyle = GET_DWORD(p); p += 2;
591 result->style = GET_DWORD(p); p += 2;
592 }
593 else
594 {
595 result->style = GET_DWORD(p - 2);
596 result->dialogEx = FALSE;
597 result->helpId = 0;
598 result->exStyle = GET_DWORD(p); p += 2;
599 }
600 result->nbItems = GET_WORD(p); p++;
601 result->x = GET_WORD(p); p++;
602 result->y = GET_WORD(p); p++;
603 result->cx = GET_WORD(p); p++;
604 result->cy = GET_WORD(p); p++;
605
606 /* Get the menu name */
607
608 switch(GET_WORD(p))
609 {
610 case 0x0000:
611 result->menuName = NULL;
612 p++;
613 break;
614 case 0xffff:
615 result->menuName = (LPCWSTR)(UINT_PTR)GET_WORD( p + 1 );
616 p += 2;
617 break;
618 default:
619 result->menuName = (LPCWSTR)p;
620 p += strlenW( result->menuName ) + 1;
621 break;
622 }
623
624 /* Get the class name */
625
626 switch(GET_WORD(p))
627 {
628 case 0x0000:
629 result->className = WC_DIALOG;
630 p++;
631 break;
632 case 0xffff:
633 result->className = (LPCWSTR)(UINT_PTR)GET_WORD( p + 1 );
634 p += 2;
635 break;
636 default:
637 result->className = (LPCWSTR)p;
638 p += strlenW( result->className ) + 1;
639 break;
640 }
641
642 /* Get the window caption */
643
644 result->caption = (LPCWSTR)p;
645 p += strlenW( result->caption ) + 1;
646
647 /* Get the font name */
648
649 result->pointSize = 0;
650 result->faceName = NULL;
651 result->weight = FW_DONTCARE;
652 result->italic = FALSE;
653
654 if (result->style & DS_SETFONT)
655 {
656 result->pointSize = GET_WORD(p);
657 p++;
658
659 /* If pointSize is 0x7fff, it means that we need to use the font
660 * in NONCLIENTMETRICSW.lfMessageFont, and NOT read the weight,
661 * italic, and facename from the dialog template.
662 */
663 if (result->pointSize == 0x7fff)
664 {
665 /* We could call SystemParametersInfo here, but then we'd have
666 * to convert from pixel size to point size (which can be
667 * imprecise).
668 */
669 TRACE(" FONT: Using message box font\n");
670 }
671 else
672 {
673 if (result->dialogEx)
674 {
675 result->weight = GET_WORD(p); p++;
676 result->italic = LOBYTE(GET_WORD(p)); p++;
677 }
678 result->faceName = (LPCWSTR)p;
679 p += strlenW( result->faceName ) + 1;
680 }
681 }
682
683 /* First control is on dword boundary */
684 return (LPCSTR)((((UINT_PTR)p) + 3) & ~3);
685 }
686
687 /***********************************************************************
688 * DEFDLG_SetFocus
689 *
690 * Set the focus to a control of the dialog, selecting the text if
691 * the control is an edit dialog.
692 */
693 static void DEFDLG_SetFocus( HWND hwndDlg, HWND hwndCtrl )
694 {
695 if (SendMessageW( hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
696 SendMessageW( hwndCtrl, EM_SETSEL, 0, -1 );
697 SetFocus( hwndCtrl );
698 }
699
700
701 /***********************************************************************
702 * DEFDLG_SaveFocus
703 */
704 static void DEFDLG_SaveFocus( HWND hwnd )
705 {
706 DIALOGINFO *infoPtr;
707 HWND hwndFocus = GetFocus();
708
709 if (!hwndFocus || !IsChild( hwnd, hwndFocus )) return;
710 if (!(infoPtr = GETDLGINFO(hwnd))) return;
711 infoPtr->hwndFocus = hwndFocus;
712 /* Remove default button */
713 }
714
715
716 /***********************************************************************
717 * DEFDLG_RestoreFocus
718 */
719 static void DEFDLG_RestoreFocus( HWND hwnd )
720 {
721 DIALOGINFO *infoPtr;
722
723 if (IsIconic( hwnd )) return;
724 if (!(infoPtr = GETDLGINFO(hwnd))) return;
725 /* Don't set the focus back to controls if EndDialog is already called.*/
726 if (infoPtr->flags & DF_END) return;
727 if (!IsWindow(infoPtr->hwndFocus) || infoPtr->hwndFocus == hwnd) {
728 /* If no saved focus control exists, set focus to the first visible,
729 non-disabled, WS_TABSTOP control in the dialog */
730 infoPtr->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE );
731 if (!IsWindow( infoPtr->hwndFocus )) return;
732 }
733 DEFDLG_SetFocus( hwnd, infoPtr->hwndFocus );
734
735 /* This used to set infoPtr->hwndFocus to NULL for no apparent reason,
736 sometimes losing focus when receiving WM_SETFOCUS messages. */
737 }
738
739 /***********************************************************************
740 * DIALOG_CreateIndirect
741 * Creates a dialog box window
742 *
743 * modal = TRUE if we are called from a modal dialog box.
744 * (it's more compatible to do it here, as under Windows the owner
745 * is never disabled if the dialog fails because of an invalid template)
746 */
747 static HWND DIALOG_CreateIndirect( HINSTANCE hInst, LPCVOID dlgTemplate,
748 HWND owner, DLGPROC dlgProc, LPARAM param,
749 BOOL unicode, BOOL modal )
750 {
751 HWND hwnd;
752 RECT rect;
753 POINT pos;
754 SIZE size;
755 DLG_TEMPLATE template;
756 DIALOGINFO * dlgInfo = NULL;
757 DWORD units = GetDialogBaseUnits();
758 BOOL ownerEnabled = TRUE;
759 HMENU hMenu = 0;
760 HFONT hUserFont = 0;
761 UINT flags = 0;
762 UINT xBaseUnit = LOWORD(units);
763 UINT yBaseUnit = HIWORD(units);
764
765 /* Parse dialog template */
766
767 if (!dlgTemplate) return 0;
768 dlgTemplate = DIALOG_ParseTemplate32( dlgTemplate, &template );
769
770 /* Load menu */
771
772 if (template.menuName) hMenu = LoadMenuW( hInst, template.menuName );
773
774 /* Create custom font if needed */
775
776 if (template.style & DS_SETFONT)
777 {
778 HDC dc = GetDC(0);
779
780 if (template.pointSize == 0x7fff)
781 {
782 /* We get the message font from the non-client metrics */
783 NONCLIENTMETRICSW ncMetrics;
784
785 ncMetrics.cbSize = sizeof(NONCLIENTMETRICSW);
786 if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
787 sizeof(NONCLIENTMETRICSW), &ncMetrics, 0))
788 {
789 hUserFont = CreateFontIndirectW( &ncMetrics.lfMessageFont );
790 }
791 }
792 else
793 {
794 /* We convert the size to pixels and then make it -ve. This works
795 * for both +ve and -ve template.pointSize */
796 int pixels = MulDiv(template.pointSize, GetDeviceCaps(dc , LOGPIXELSY), 72);
797 hUserFont = CreateFontW( -pixels, 0, 0, 0, template.weight,
798 template.italic, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
799 PROOF_QUALITY, FF_DONTCARE,
800 template.faceName );
801 }
802
803 if (hUserFont)
804 {
805 SIZE charSize;
806 HFONT hOldFont = SelectObject( dc, hUserFont );
807 charSize.cx = GdiGetCharDimensions( dc, NULL, &charSize.cy );
808 if (charSize.cx)
809 {
810 xBaseUnit = charSize.cx;
811 yBaseUnit = charSize.cy;
812 }
813 SelectObject( dc, hOldFont );
814 }
815 ReleaseDC(0, dc);
816 TRACE("units = %d,%d\n", xBaseUnit, yBaseUnit );
817 }
818
819 /* Create dialog main window */
820
821 rect.left = rect.top = 0;
822 rect.right = MulDiv(template.cx, xBaseUnit, 4);
823 rect.bottom = MulDiv(template.cy, yBaseUnit, 8);
824 if (template.style & WS_CHILD)
825 template.style &= ~(WS_CAPTION|WS_SYSMENU);
826 if (template.style & DS_MODALFRAME)
827 template.exStyle |= WS_EX_DLGMODALFRAME;
828 if (template.style & DS_CONTROL)
829 template.exStyle |= WS_EX_CONTROLPARENT;
830 AdjustWindowRectEx( &rect, template.style, (hMenu != 0), template.exStyle );
831 pos.x = rect.left;
832 pos.y = rect.top;
833 size.cx = rect.right - rect.left;
834 size.cy = rect.bottom - rect.top;
835
836 if (template.x == CW_USEDEFAULT16)
837 {
838 pos.x = pos.y = CW_USEDEFAULT;
839 }
840 else
841 {
842 HMONITOR monitor = 0;
843 MONITORINFO mon_info;
844
845 mon_info.cbSize = sizeof(mon_info);
846 if (template.style & DS_CENTER)
847 {
848 monitor = MonitorFromWindow( owner ? owner : GetActiveWindow(), MONITOR_DEFAULTTOPRIMARY );
849 GetMonitorInfoW( monitor, &mon_info );
850 pos.x = (mon_info.rcWork.left + mon_info.rcWork.right - size.cx) / 2;
851 pos.y = (mon_info.rcWork.top + mon_info.rcWork.bottom - size.cy) / 2;
852 }
853 else if (template.style & DS_CENTERMOUSE)
854 {
855 GetCursorPos( &pos );
856 monitor = MonitorFromPoint( pos, MONITOR_DEFAULTTOPRIMARY );
857 GetMonitorInfoW( monitor, &mon_info );
858 }
859 else
860 {
861 pos.x += MulDiv(template.x, xBaseUnit, 4);
862 pos.y += MulDiv(template.y, yBaseUnit, 8);
863 if (!(template.style & (WS_CHILD|DS_ABSALIGN))) ClientToScreen( owner, &pos );
864 }
865 if ( !(template.style & WS_CHILD) )
866 {
867 INT dX, dY;
868
869 /* try to fit it into the desktop */
870
871 if (!monitor)
872 {
873 SetRect( &rect, pos.x, pos.y, pos.x + size.cx, pos.y + size.cy );
874 monitor = MonitorFromRect( &rect, MONITOR_DEFAULTTOPRIMARY );
875 GetMonitorInfoW( monitor, &mon_info );
876 }
877 if ((dX = pos.x + size.cx + GetSystemMetrics(SM_CXDLGFRAME) - mon_info.rcWork.right) > 0)
878 pos.x -= dX;
879 if ((dY = pos.y + size.cy + GetSystemMetrics(SM_CYDLGFRAME) - mon_info.rcWork.bottom) > 0)
880 pos.y -= dY;
881 if( pos.x < mon_info.rcWork.left ) pos.x = mon_info.rcWork.left;
882 if( pos.y < mon_info.rcWork.top ) pos.y = mon_info.rcWork.top;
883 }
884 }
885
886 if (modal)
887 {
888 ownerEnabled = DIALOG_DisableOwner( owner );
889 if (ownerEnabled) flags |= DF_OWNERENABLED;
890 }
891
892 if (unicode)
893 {
894 hwnd = CreateWindowExW(template.exStyle, template.className, template.caption,
895 template.style & ~WS_VISIBLE, pos.x, pos.y, size.cx, size.cy,
896 owner, hMenu, hInst, NULL );
897 }
898 else
899 {
900 LPCSTR class = (LPCSTR)template.className;
901 LPCSTR caption = (LPCSTR)template.caption;
902 LPSTR class_tmp = NULL;
903 LPSTR caption_tmp = NULL;
904
905 if (HIWORD(class))
906 {
907 DWORD len = WideCharToMultiByte( CP_ACP, 0, template.className, -1, NULL, 0, NULL, NULL );
908 class_tmp = HeapAlloc( GetProcessHeap(), 0, len );
909 WideCharToMultiByte( CP_ACP, 0, template.className, -1, class_tmp, len, NULL, NULL );
910 class = class_tmp;
911 }
912 if (HIWORD(caption))
913 {
914 DWORD len = WideCharToMultiByte( CP_ACP, 0, template.caption, -1, NULL, 0, NULL, NULL );
915 caption_tmp = HeapAlloc( GetProcessHeap(), 0, len );
916 WideCharToMultiByte( CP_ACP, 0, template.caption, -1, caption_tmp, len, NULL, NULL );
917 caption = caption_tmp;
918 }
919 hwnd = CreateWindowExA(template.exStyle, class, caption,
920 template.style & ~WS_VISIBLE, pos.x, pos.y, size.cx, size.cy,
921 owner, hMenu, hInst, NULL );
922 HeapFree( GetProcessHeap(), 0, class_tmp );
923 HeapFree( GetProcessHeap(), 0, caption_tmp );
924 }
925
926 if (!hwnd)
927 {
928 if (hUserFont) DeleteObject( hUserFont );
929 if (hMenu) DestroyMenu( hMenu );
930 if (modal && (flags & DF_OWNERENABLED)) DIALOG_EnableOwner(owner);
931 return 0;
932 }
933
934 /* moved this from the top of the method to here as DIALOGINFO structure
935 will be valid only after WM_CREATE message has been handled in DefDlgProc
936 All the members of the structure get filled here using temp variables */
937 dlgInfo = DIALOG_get_info( hwnd, TRUE );
938 if (dlgInfo == NULL)
939 {
940 if (hUserFont) DeleteObject( hUserFont );
941 if (hMenu) DestroyMenu( hMenu );
942 if (modal && (flags & DF_OWNERENABLED)) DIALOG_EnableOwner(owner);
943 return 0;
944 }
945
946 dlgInfo->hwndFocus = 0;
947 dlgInfo->hUserFont = hUserFont;
948 dlgInfo->hMenu = hMenu;
949 dlgInfo->xBaseUnit = xBaseUnit;
950 dlgInfo->yBaseUnit = yBaseUnit;
951 dlgInfo->idResult = IDOK;
952 dlgInfo->flags = flags;
953
954 if (template.helpId) SetWindowContextHelpId( hwnd, template.helpId );
955
956 if (unicode) SetWindowLongPtrW( hwnd, DWLP_DLGPROC, (ULONG_PTR)dlgProc );
957 else SetWindowLongPtrA( hwnd, DWLP_DLGPROC, (ULONG_PTR)dlgProc );
958
959 if (dlgProc && dlgInfo->hUserFont)
960 SendMessageW( hwnd, WM_SETFONT, (WPARAM)dlgInfo->hUserFont, 0 );
961
962 /* Create controls */
963
964 if (DIALOG_CreateControls32( hwnd, dlgTemplate, &template, hInst, unicode ))
965 {
966 /* Send initialisation messages and set focus */
967
968 if (dlgProc)
969 {
970 HWND focus = GetNextDlgTabItem( hwnd, 0, FALSE );
971 if (SendMessageW( hwnd, WM_INITDIALOG, (WPARAM)focus, param ) &&
972 ((~template.style & DS_CONTROL) || (template.style & WS_VISIBLE)))
973 {
974 /* By returning TRUE, app has requested a default focus assignment.
975 * WM_INITDIALOG may have changed the tab order, so find the first
976 * tabstop control again. */
977 dlgInfo->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE);
978 if( dlgInfo->hwndFocus )
979 SetFocus( dlgInfo->hwndFocus );
980 }
981 //// ReactOS
982 DEFDLG_SaveFocus( hwnd );
983 ////
984 }
985 //// ReactOS Rev 30613 & 30644
986 if (!(GetWindowLongPtrW( hwnd, GWL_STYLE ) & WS_CHILD))
987 SendMessageW( hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, 0), 0);
988 ////
989 if (template.style & WS_VISIBLE && !(GetWindowLongPtrW( hwnd, GWL_STYLE ) & WS_VISIBLE))
990 {
991 ShowWindow( hwnd, SW_SHOWNORMAL ); /* SW_SHOW doesn't always work */
992 }
993 return hwnd;
994 }
995 if (modal && ownerEnabled) DIALOG_EnableOwner(owner);
996 if( IsWindow(hwnd) ) DestroyWindow( hwnd );
997 return 0;
998 }
999
1000
1001 /***********************************************************************
1002 * DEFDLG_FindDefButton
1003 *
1004 * Find the current default push-button.
1005 */
1006 static HWND DEFDLG_FindDefButton( HWND hwndDlg )
1007 {
1008 HWND hwndChild, hwndTmp;
1009
1010 hwndChild = GetWindow( hwndDlg, GW_CHILD );
1011 while (hwndChild)
1012 {
1013 if (SendMessageW( hwndChild, WM_GETDLGCODE, 0, 0 ) & DLGC_DEFPUSHBUTTON)
1014 break;
1015
1016 /* Recurse into WS_EX_CONTROLPARENT controls */
1017 if (GetWindowLongPtrW( hwndChild, GWL_EXSTYLE ) & WS_EX_CONTROLPARENT)
1018 {
1019 LONG dsStyle = GetWindowLongPtrW( hwndChild, GWL_STYLE );
1020 if ((dsStyle & WS_VISIBLE) && !(dsStyle & WS_DISABLED) &&
1021 (hwndTmp = DEFDLG_FindDefButton(hwndChild)) != NULL)
1022 return hwndTmp;
1023 }
1024 hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
1025 }
1026 return hwndChild;
1027 }
1028
1029
1030 /***********************************************************************
1031 * DEFDLG_SetDefId
1032 *
1033 * Set the default button id.
1034 */
1035 static BOOL DEFDLG_SetDefId( HWND hwndDlg, DIALOGINFO *dlgInfo, WPARAM wParam)
1036 {
1037 DWORD dlgcode=0; /* initialize just to avoid a warning */
1038 HWND hwndOld, hwndNew = GetDlgItem(hwndDlg, wParam);
1039 INT old_id = dlgInfo->idResult;
1040
1041 dlgInfo->idResult = wParam;
1042 if (hwndNew &&
1043 !((dlgcode=SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 ))
1044 & (DLGC_UNDEFPUSHBUTTON | DLGC_BUTTON)))
1045 return FALSE; /* Destination is not a push button */
1046
1047 /* Make sure the old default control is a valid push button ID */
1048 hwndOld = GetDlgItem( hwndDlg, old_id );
1049 if (!hwndOld || !(SendMessageW( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON))
1050 hwndOld = DEFDLG_FindDefButton( hwndDlg );
1051 if (hwndOld && hwndOld != hwndNew)
1052 SendMessageW( hwndOld, BM_SETSTYLE, BS_PUSHBUTTON, TRUE );
1053
1054 if (hwndNew)
1055 {
1056 if(dlgcode & DLGC_UNDEFPUSHBUTTON)
1057 SendMessageW( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
1058 }
1059 return TRUE;
1060 }
1061
1062
1063 /***********************************************************************
1064 * DEFDLG_SetDefButton
1065 *
1066 * Set the new default button to be hwndNew.
1067 */
1068 static BOOL DEFDLG_SetDefButton( HWND hwndDlg, DIALOGINFO *dlgInfo, HWND hwndNew )
1069 {
1070 DWORD dlgcode=0; /* initialize just to avoid a warning */
1071 HWND hwndOld = GetDlgItem( hwndDlg, dlgInfo->idResult );
1072
1073 if (hwndNew &&
1074 !((dlgcode=SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 ))
1075 & (DLGC_UNDEFPUSHBUTTON | DLGC_DEFPUSHBUTTON)))
1076 {
1077 /**
1078 * Need to draw only default push button rectangle.
1079 * Since the next control is not a push button, need to draw the push
1080 * button rectangle for the default control.
1081 */
1082 hwndNew = hwndOld;
1083 dlgcode = SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 );
1084 }
1085
1086 /* Make sure the old default control is a valid push button ID */
1087 if (!hwndOld || !(SendMessageW( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON))
1088 hwndOld = DEFDLG_FindDefButton( hwndDlg );
1089 if (hwndOld && hwndOld != hwndNew)
1090 SendMessageW( hwndOld, BM_SETSTYLE, BS_PUSHBUTTON, TRUE );
1091
1092 if (hwndNew)
1093 {
1094 if(dlgcode & DLGC_UNDEFPUSHBUTTON)
1095 SendMessageW( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
1096 }
1097 return TRUE;
1098 }
1099
1100
1101 /***********************************************************************
1102 * DEFDLG_Proc
1103 *
1104 * Implementation of DefDlgProc(). Only handle messages that need special
1105 * handling for dialogs.
1106 */
1107 static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
1108 LPARAM lParam, DIALOGINFO *dlgInfo )
1109 {
1110 switch(msg)
1111 {
1112 case WM_ERASEBKGND:
1113 {
1114 HBRUSH brush = (HBRUSH)SendMessageW( hwnd, WM_CTLCOLORDLG, wParam, (LPARAM)hwnd );
1115 if (!brush) brush = (HBRUSH)DefWindowProcW( hwnd, WM_CTLCOLORDLG, wParam, (LPARAM)hwnd );
1116 if (brush)
1117 {
1118 RECT rect;
1119 HDC hdc = (HDC)wParam;
1120 GetClientRect( hwnd, &rect );
1121 DPtoLP( hdc, (LPPOINT)&rect, 2 );
1122 FillRect( hdc, &rect, brush );
1123 }
1124 return 1;
1125 }
1126 case WM_NCDESTROY:
1127 //// ReactOS
1128 if ((dlgInfo = (DIALOGINFO *)SetWindowLongPtrW( hwnd, DWLP_ROS_DIALOGINFO, 0 )))
1129 {
1130 if (dlgInfo->hUserFont) DeleteObject( dlgInfo->hUserFont );
1131 if (dlgInfo->hMenu) DestroyMenu( dlgInfo->hMenu );
1132 HeapFree( GetProcessHeap(), 0, dlgInfo );
1133 NtUserCallHwndParam( hwnd, 0, HWNDPARAM_ROUTINE_SETDIALOGPOINTER );
1134 }
1135 /* Window clean-up */
1136 return DefWindowProcA( hwnd, msg, wParam, lParam );
1137
1138 case WM_SHOWWINDOW:
1139 if (!wParam) DEFDLG_SaveFocus( hwnd );
1140 return DefWindowProcA( hwnd, msg, wParam, lParam );
1141
1142 case WM_ACTIVATE:
1143 if (wParam) DEFDLG_RestoreFocus( hwnd );
1144 else DEFDLG_SaveFocus( hwnd );
1145 return 0;
1146
1147 case WM_SETFOCUS:
1148 DEFDLG_RestoreFocus( hwnd );
1149 return 0;
1150
1151 case DM_SETDEFID:
1152 if (dlgInfo && !(dlgInfo->flags & DF_END))
1153 DEFDLG_SetDefId( hwnd, dlgInfo, wParam );
1154 return 1;
1155
1156 case DM_GETDEFID:
1157 if (dlgInfo && !(dlgInfo->flags & DF_END))
1158 {
1159 HWND hwndDefId;
1160 if (dlgInfo->idResult)
1161 return MAKELONG( dlgInfo->idResult, DC_HASDEFID );
1162 if ((hwndDefId = DEFDLG_FindDefButton( hwnd )))
1163 return MAKELONG( GetDlgCtrlID( hwndDefId ), DC_HASDEFID);
1164 }
1165 return 0;
1166
1167 case WM_NEXTDLGCTL:
1168 if (dlgInfo)
1169 {
1170 HWND hwndDest = (HWND)wParam;
1171 if (!lParam)
1172 hwndDest = GetNextDlgTabItem(hwnd, GetFocus(), wParam);
1173 if (hwndDest) DEFDLG_SetFocus( hwnd, hwndDest );
1174 DEFDLG_SetDefButton( hwnd, dlgInfo, hwndDest );
1175 }
1176 return 0;
1177
1178 case WM_ENTERMENULOOP:
1179 case WM_LBUTTONDOWN:
1180 case WM_NCLBUTTONDOWN:
1181 {
1182 HWND hwndFocus = GetFocus();
1183 if (hwndFocus)
1184 {
1185 /* always make combo box hide its listbox control */
1186 if (!SendMessageW( hwndFocus, CB_SHOWDROPDOWN, FALSE, 0 ))
1187 SendMessageW( GetParent(hwndFocus), CB_SHOWDROPDOWN, FALSE, 0 );
1188 }
1189 }
1190 return DefWindowProcA( hwnd, msg, wParam, lParam );
1191
1192 case WM_GETFONT:
1193 return dlgInfo ? (LRESULT)dlgInfo->hUserFont : 0;
1194
1195 case WM_CLOSE:
1196 PostMessageA( hwnd, WM_COMMAND, MAKEWPARAM(IDCANCEL, BN_CLICKED),
1197 (LPARAM)GetDlgItem( hwnd, IDCANCEL ) );
1198 return 0;
1199 }
1200 return 0;
1201 }
1202
1203 /***********************************************************************
1204 * DEFDLG_Epilog
1205 */
1206 static LRESULT DEFDLG_Epilog(HWND hwnd, UINT msg, BOOL fResult)
1207 {
1208
1209 // TODO: where's wine's WM_CTLCOLOR from?
1210 if ((msg >= WM_CTLCOLORMSGBOX && msg <= WM_CTLCOLORSTATIC) ||
1211 msg == WM_CTLCOLOR || msg == WM_COMPAREITEM ||
1212 msg == WM_VKEYTOITEM || msg == WM_CHARTOITEM ||
1213 msg == WM_QUERYDRAGICON || msg == WM_INITDIALOG)
1214 return fResult;
1215
1216 return GetWindowLongPtrW( hwnd, DWLP_MSGRESULT );
1217 }
1218
1219 /***********************************************************************
1220 * DIALOG_GetNextTabItem
1221 *
1222 * Helper for GetNextDlgTabItem
1223 */
1224 static HWND DIALOG_GetNextTabItem( HWND hwndMain, HWND hwndDlg, HWND hwndCtrl, BOOL fPrevious )
1225 {
1226 LONG dsStyle;
1227 LONG exStyle;
1228 UINT wndSearch = fPrevious ? GW_HWNDPREV : GW_HWNDNEXT;
1229 HWND retWnd = 0;
1230 HWND hChildFirst = 0;
1231
1232 if(!hwndCtrl)
1233 {
1234 hChildFirst = GetWindow(hwndDlg,GW_CHILD);
1235 if(fPrevious) hChildFirst = GetWindow(hChildFirst,GW_HWNDLAST);
1236 }
1237 else if (IsChild( hwndMain, hwndCtrl ))
1238 {
1239 hChildFirst = GetWindow(hwndCtrl,wndSearch);
1240 if(!hChildFirst)
1241 {
1242 if(GetParent(hwndCtrl) != hwndMain)
1243 /* i.e. if we are not at the top level of the recursion */
1244 hChildFirst = GetWindow(GetParent(hwndCtrl),wndSearch);
1245 else
1246 hChildFirst = GetWindow(hwndCtrl, fPrevious ? GW_HWNDLAST : GW_HWNDFIRST);
1247 }
1248 }
1249
1250 while(hChildFirst)
1251 {
1252 dsStyle = GetWindowLongPtrA(hChildFirst,GWL_STYLE);
1253 exStyle = GetWindowLongPtrA(hChildFirst,GWL_EXSTYLE);
1254 if( (exStyle & WS_EX_CONTROLPARENT) && (dsStyle & WS_VISIBLE) && !(dsStyle & WS_DISABLED))
1255 {
1256 HWND retWnd;
1257 retWnd = DIALOG_GetNextTabItem(hwndMain,hChildFirst,NULL,fPrevious );
1258 if (retWnd) return (retWnd);
1259 }
1260 else if( (dsStyle & WS_TABSTOP) && (dsStyle & WS_VISIBLE) && !(dsStyle & WS_DISABLED))
1261 {
1262 return (hChildFirst);
1263 }
1264 hChildFirst = GetWindow(hChildFirst,wndSearch);
1265 }
1266 if(hwndCtrl)
1267 {
1268 HWND hParent = GetParent(hwndCtrl);
1269 while(hParent)
1270 {
1271 if(hParent == hwndMain) break;
1272 retWnd = DIALOG_GetNextTabItem(hwndMain,GetParent(hParent),hParent,fPrevious );
1273 if(retWnd) break;
1274 hParent = GetParent(hParent);
1275 }
1276 if(!retWnd)
1277 retWnd = DIALOG_GetNextTabItem(hwndMain,hwndMain,NULL,fPrevious );
1278 }
1279 return retWnd ? retWnd : hwndCtrl;
1280 }
1281
1282 /**********************************************************************
1283 * DIALOG_DlgDirListW
1284 *
1285 * Helper function for DlgDirList*W
1286 */
1287 static INT DIALOG_DlgDirListW( HWND hDlg, LPWSTR spec, INT idLBox,
1288 INT idStatic, UINT attrib, BOOL combo )
1289 {
1290 HWND hwnd;
1291 LPWSTR orig_spec = spec;
1292 WCHAR any[] = {'*','.','*',0};
1293
1294 #define SENDMSG(msg,wparam,lparam) \
1295 ((attrib & DDL_POSTMSGS) ? PostMessageW( hwnd, msg, wparam, lparam ) \
1296 : SendMessageW( hwnd, msg, wparam, lparam ))
1297
1298 // TRACE("%p '%s' %d %d %04x\n",
1299 // hDlg, spec ? spec : "NULL", idLBox, idStatic, attrib );
1300
1301 /* If the path exists and is a directory, chdir to it */
1302 if (!spec || !spec[0] || SetCurrentDirectoryW( spec )) spec = any;
1303 else
1304 {
1305 WCHAR *p, *p2;
1306 p = spec;
1307 if ((p2 = strchrW( p, ':' ))) p = p2 + 1;
1308 if ((p2 = strrchrW( p, '\\' ))) p = p2;
1309 if ((p2 = strrchrW( p, '/' ))) p = p2;
1310 if (p != spec)
1311 {
1312 WCHAR sep = *p;
1313 *p = 0;
1314 if (!SetCurrentDirectoryW( spec ))
1315 {
1316 *p = sep; /* Restore the original spec */
1317 return FALSE;
1318 }
1319 spec = p + 1;
1320 }
1321 }
1322
1323 TRACE( "mask=%s\n", spec );
1324
1325 if (idLBox && ((hwnd = GetDlgItem( hDlg, idLBox )) != 0))
1326 {
1327 if (attrib == DDL_DRIVES) attrib |= DDL_EXCLUSIVE;
1328
1329 SENDMSG( combo ? CB_RESETCONTENT : LB_RESETCONTENT, 0, 0 );
1330 if (attrib & DDL_DIRECTORY)
1331 {
1332 if (!(attrib & DDL_EXCLUSIVE))
1333 {
1334 SENDMSG( combo ? CB_DIR : LB_DIR,
1335 attrib & ~(DDL_DIRECTORY | DDL_DRIVES),
1336 (LPARAM)spec );
1337 }
1338 SENDMSG( combo ? CB_DIR : LB_DIR,
1339 (attrib & (DDL_DIRECTORY | DDL_DRIVES)) | DDL_EXCLUSIVE,
1340 (LPARAM)any );
1341 }
1342 else
1343 {
1344 SENDMSG( combo ? CB_DIR : LB_DIR, attrib, (LPARAM)spec );
1345 }
1346 }
1347
1348 /* Convert path specification to uppercase */
1349 if (spec) CharUpperW(spec);
1350
1351 if (idStatic && ((hwnd = GetDlgItem( hDlg, idStatic )) != 0))
1352 {
1353 WCHAR temp[MAX_PATH];
1354 GetCurrentDirectoryW( sizeof(temp)/sizeof(WCHAR), temp );
1355 CharLowerW( temp );
1356 /* Can't use PostMessage() here, because the string is on the stack */
1357 SetDlgItemTextW( hDlg, idStatic, temp );
1358 }
1359
1360 if (orig_spec && (spec != orig_spec))
1361 {
1362 /* Update the original file spec */
1363 WCHAR *p = spec;
1364 while ((*orig_spec++ = *p++));
1365 }
1366
1367 return TRUE;
1368 #undef SENDMSG
1369 }
1370
1371 /**********************************************************************
1372 * DIALOG_DlgDirListA
1373 *
1374 * Helper function for DlgDirList*A
1375 */
1376 static INT DIALOG_DlgDirListA( HWND hDlg, LPSTR spec, INT idLBox,
1377 INT idStatic, UINT attrib, BOOL combo )
1378 {
1379 if (spec)
1380 {
1381 INT ret, len = MultiByteToWideChar( CP_ACP, 0, spec, -1, NULL, 0 );
1382 LPWSTR specW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1383 if (specW == NULL)
1384 return FALSE;
1385 MultiByteToWideChar( CP_ACP, 0, spec, -1, specW, len );
1386 ret = DIALOG_DlgDirListW( hDlg, specW, idLBox, idStatic, attrib, combo );
1387 WideCharToMultiByte( CP_ACP, 0, specW, -1, spec, 0x7fffffff, NULL, NULL );
1388 HeapFree( GetProcessHeap(), 0, specW );
1389 return ret;
1390 }
1391 return DIALOG_DlgDirListW( hDlg, NULL, idLBox, idStatic, attrib, combo );
1392 }
1393
1394 /**********************************************************************
1395 * DIALOG_DlgDirSelect
1396 *
1397 * Helper function for DlgDirSelect*
1398 */
1399 static BOOL DIALOG_DlgDirSelect( HWND hwnd, LPWSTR str, INT len,
1400 INT id, BOOL unicode, BOOL combo )
1401 {
1402 WCHAR *buffer, *ptr;
1403 INT item, size;
1404 BOOL ret;
1405 HWND listbox = GetDlgItem( hwnd, id );
1406
1407 TRACE("%p %s %d\n", hwnd, unicode ? debugstr_w(str) : debugstr_a((LPSTR)str), id );
1408 if (!listbox) return FALSE;
1409
1410 item = SendMessageW(listbox, combo ? CB_GETCURSEL : LB_GETCURSEL, 0, 0 );
1411 if (item == LB_ERR) return FALSE;
1412
1413 size = SendMessageW(listbox, combo ? CB_GETLBTEXTLEN : LB_GETTEXTLEN, item, 0 );
1414 if (size == LB_ERR) return FALSE;
1415
1416 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size+2) * sizeof(WCHAR) ))) return FALSE;
1417
1418 SendMessageW( listbox, combo ? CB_GETLBTEXT : LB_GETTEXT, item, (LPARAM)buffer );
1419
1420 if ((ret = (buffer[0] == '['))) /* drive or directory */
1421 {
1422 if (buffer[1] == '-') /* drive */
1423 {
1424 buffer[3] = ':';
1425 buffer[4] = 0;
1426 ptr = buffer + 2;
1427 }
1428 else
1429 {
1430 buffer[strlenW(buffer)-1] = '\\';
1431 ptr = buffer + 1;
1432 }
1433 }
1434 else
1435 {
1436 /* Filenames without a dot extension must have one tacked at the end */
1437 if (strchrW(buffer, '.') == NULL)
1438 {
1439 buffer[strlenW(buffer)+1] = '\0';
1440 buffer[strlenW(buffer)] = '.';
1441 }
1442 ptr = buffer;
1443 }
1444
1445 if (!unicode)
1446 {
1447 if (len > 0 && !WideCharToMultiByte( CP_ACP, 0, ptr, -1, (LPSTR)str, len, 0, 0 ))
1448 ((LPSTR)str)[len-1] = 0;
1449 }
1450 else lstrcpynW( str, ptr, len );
1451 HeapFree( GetProcessHeap(), 0, buffer );
1452 TRACE("Returning %d %s\n", ret, unicode ? debugstr_w(str) : debugstr_a((LPSTR)str) );
1453 return ret;
1454 }
1455
1456
1457 /* FUNCTIONS *****************************************************************/
1458
1459 /*
1460 * @implemented
1461 */
1462 HWND
1463 WINAPI
1464 CreateDialogIndirectParamAorW(
1465 HINSTANCE hInstance,
1466 LPCDLGTEMPLATE lpTemplate,
1467 HWND hWndParent,
1468 DLGPROC lpDialogFunc,
1469 LPARAM lParamInit,
1470 DWORD Flags)
1471 {
1472 /* FIXME:
1473 * This function might be obsolete since I don't think it is exported by NT
1474 * Also wine has one more parameter identifying weather it should call
1475 * the function with unicode or not
1476 */
1477 return DIALOG_CreateIndirect( hInstance, lpTemplate, hWndParent, lpDialogFunc, lParamInit , !Flags, FALSE );
1478 }
1479
1480
1481 /*
1482 * @implemented
1483 */
1484 HWND
1485 WINAPI
1486 CreateDialogIndirectParamA(
1487 HINSTANCE hInstance,
1488 LPCDLGTEMPLATE lpTemplate,
1489 HWND hWndParent,
1490 DLGPROC lpDialogFunc,
1491 LPARAM lParamInit)
1492 {
1493 return CreateDialogIndirectParamAorW( hInstance, lpTemplate, hWndParent, lpDialogFunc, lParamInit, 2 );
1494 }
1495
1496
1497 /*
1498 * @implemented
1499 */
1500 HWND
1501 WINAPI
1502 CreateDialogIndirectParamW(
1503 HINSTANCE hInstance,
1504 LPCDLGTEMPLATE lpTemplate,
1505 HWND hWndParent,
1506 DLGPROC lpDialogFunc,
1507 LPARAM lParamInit)
1508 {
1509 return CreateDialogIndirectParamAorW( hInstance, lpTemplate, hWndParent, lpDialogFunc, lParamInit, 0);
1510 }
1511
1512
1513 /*
1514 * @implemented
1515 */
1516 HWND
1517 WINAPI
1518 CreateDialogParamA(
1519 HINSTANCE hInstance,
1520 LPCSTR lpTemplateName,
1521 HWND hWndParent,
1522 DLGPROC lpDialogFunc,
1523 LPARAM dwInitParam)
1524 {
1525 HRSRC hrsrc;
1526 LPCDLGTEMPLATE ptr;
1527
1528 if (!(hrsrc = FindResourceA( hInstance, lpTemplateName, (LPCSTR)RT_DIALOG ))) return 0;
1529 if (!(ptr = (LPCDLGTEMPLATE)LoadResource(hInstance, hrsrc))) return 0;
1530 return CreateDialogIndirectParamA( hInstance, ptr, hWndParent, lpDialogFunc, dwInitParam );
1531 }
1532
1533
1534 /*
1535 * @implemented
1536 */
1537 HWND
1538 WINAPI
1539 CreateDialogParamW(
1540 HINSTANCE hInstance,
1541 LPCWSTR lpTemplateName,
1542 HWND hWndParent,
1543 DLGPROC lpDialogFunc,
1544 LPARAM dwInitParam)
1545 {
1546 HRSRC hrsrc;
1547 LPCDLGTEMPLATE ptr;
1548
1549 if (!(hrsrc = FindResourceW( hInstance, lpTemplateName, (LPCWSTR)RT_DIALOG ))) return 0;
1550 if (!(ptr = (LPCDLGTEMPLATE)LoadResource(hInstance, hrsrc))) return 0;
1551 return CreateDialogIndirectParamW( hInstance, ptr, hWndParent, lpDialogFunc, dwInitParam );
1552 }
1553
1554
1555 /*
1556 * @implemented
1557 */
1558 LRESULT
1559 WINAPI
1560 DefDlgProcA(
1561 HWND hDlg,
1562 UINT Msg,
1563 WPARAM wParam,
1564 LPARAM lParam)
1565 {
1566 DIALOGINFO *dlgInfo;
1567 WNDPROC dlgproc;
1568 BOOL result = FALSE;
1569
1570 /* Perform DIALOGINFO initialization if not done */
1571 if(!(dlgInfo = DIALOG_get_info( hDlg, TRUE ))) return 0;
1572
1573 SetWindowLongPtrW( hDlg, DWLP_MSGRESULT, 0 );
1574
1575 if ((dlgproc = (WNDPROC)GetWindowLongPtrW( hDlg, DWLP_DLGPROC )))
1576 {
1577 /* Call dialog procedure */
1578 result = CallWindowProcA( dlgproc, hDlg, Msg, wParam, lParam );
1579 }
1580
1581 if (!result && IsWindow(hDlg))
1582 {
1583 /* callback didn't process this message */
1584
1585 switch(Msg)
1586 {
1587 case WM_ERASEBKGND:
1588 case WM_SHOWWINDOW:
1589 case WM_ACTIVATE:
1590 case WM_SETFOCUS:
1591 case DM_SETDEFID:
1592 case DM_GETDEFID:
1593 case WM_NEXTDLGCTL:
1594 case WM_GETFONT:
1595 case WM_CLOSE:
1596 case WM_NCDESTROY:
1597 case WM_ENTERMENULOOP:
1598 case WM_LBUTTONDOWN:
1599 case WM_NCLBUTTONDOWN:
1600 return DEFDLG_Proc( hDlg, Msg, wParam, lParam, dlgInfo );
1601 case WM_INITDIALOG:
1602 case WM_VKEYTOITEM:
1603 case WM_COMPAREITEM:
1604 case WM_CHARTOITEM:
1605 break;
1606
1607 default:
1608 return DefWindowProcA( hDlg, Msg, wParam, lParam );
1609 }
1610 }
1611 return DEFDLG_Epilog(hDlg, Msg, result);
1612 }
1613
1614
1615 /*
1616 * @implemented
1617 */
1618 LRESULT
1619 WINAPI
1620 DefDlgProcW(
1621 HWND hDlg,
1622 UINT Msg,
1623 WPARAM wParam,
1624 LPARAM lParam)
1625 {
1626 DIALOGINFO *dlgInfo;
1627 WNDPROC dlgproc;
1628 BOOL result = FALSE;
1629
1630 /* Perform DIALOGINFO initialization if not done */
1631 if(!(dlgInfo = DIALOG_get_info( hDlg, TRUE ))) return 0;
1632
1633 SetWindowLongPtrW( hDlg, DWLP_MSGRESULT, 0 );
1634
1635 if ((dlgproc = (WNDPROC)GetWindowLongPtrW( hDlg, DWLP_DLGPROC )))
1636 {
1637 /* Call dialog procedure */
1638 result = CallWindowProcW( dlgproc, hDlg, Msg, wParam, lParam );
1639 }
1640
1641 if (!result && IsWindow(hDlg))
1642 {
1643 /* callback didn't process this message */
1644
1645 switch(Msg)
1646 {
1647 case WM_ERASEBKGND:
1648 case WM_SHOWWINDOW:
1649 case WM_ACTIVATE:
1650 case WM_SETFOCUS:
1651 case DM_SETDEFID:
1652 case DM_GETDEFID:
1653 case WM_NEXTDLGCTL:
1654 case WM_GETFONT:
1655 case WM_CLOSE:
1656 case WM_NCDESTROY:
1657 case WM_ENTERMENULOOP:
1658 case WM_LBUTTONDOWN:
1659 case WM_NCLBUTTONDOWN:
1660 return DEFDLG_Proc( hDlg, Msg, wParam, lParam, dlgInfo );
1661 case WM_INITDIALOG:
1662 case WM_VKEYTOITEM:
1663 case WM_COMPAREITEM:
1664 case WM_CHARTOITEM:
1665 break;
1666
1667 default:
1668 return DefWindowProcW( hDlg, Msg, wParam, lParam );
1669 }
1670 }
1671 return DEFDLG_Epilog(hDlg, Msg, result);
1672 }
1673
1674
1675 /*
1676 * @implemented
1677 */
1678 INT_PTR
1679 WINAPI
1680 DialogBoxIndirectParamAorW(
1681 HINSTANCE hInstance,
1682 LPCDLGTEMPLATE hDialogTemplate,
1683 HWND hWndParent,
1684 DLGPROC lpDialogFunc,
1685 LPARAM dwInitParam,
1686 DWORD Flags)
1687 {
1688 /* FIXME:
1689 * This function might be obsolete since I don't think it is exported by NT
1690 * Also wine has one more parameter identifying weather it should call
1691 * the function with unicode or not
1692 */
1693 HWND hWnd = DIALOG_CreateIndirect( hInstance, hDialogTemplate, hWndParent, lpDialogFunc, dwInitParam, !Flags, TRUE );
1694 if (hWnd) return DIALOG_DoDialogBox( hWnd, hWndParent );
1695 return -1;
1696 }
1697
1698
1699 /*
1700 * @implemented
1701 */
1702 INT_PTR
1703 WINAPI
1704 DialogBoxIndirectParamA(
1705 HINSTANCE hInstance,
1706 LPCDLGTEMPLATE hDialogTemplate,
1707 HWND hWndParent,
1708 DLGPROC lpDialogFunc,
1709 LPARAM dwInitParam)
1710 {
1711 return DialogBoxIndirectParamAorW( hInstance, hDialogTemplate, hWndParent, lpDialogFunc, dwInitParam, 2);
1712 }
1713
1714
1715 /*
1716 * @implemented
1717 */
1718 INT_PTR
1719 WINAPI
1720 DialogBoxIndirectParamW(
1721 HINSTANCE hInstance,
1722 LPCDLGTEMPLATE hDialogTemplate,
1723 HWND hWndParent,
1724 DLGPROC lpDialogFunc,
1725 LPARAM dwInitParam)
1726 {
1727 return DialogBoxIndirectParamAorW( hInstance, hDialogTemplate, hWndParent, lpDialogFunc, dwInitParam, 0);
1728 }
1729
1730
1731 /*
1732 * @implemented
1733 */
1734 INT_PTR
1735 WINAPI
1736 DialogBoxParamA(
1737 HINSTANCE hInstance,
1738 LPCSTR lpTemplateName,
1739 HWND hWndParent,
1740 DLGPROC lpDialogFunc,
1741 LPARAM dwInitParam)
1742 {
1743 HWND hwnd;
1744 HRSRC hrsrc;
1745 LPCDLGTEMPLATE ptr;
1746 //// ReactOS rev 33532
1747 if (!(hrsrc = FindResourceA( hInstance, lpTemplateName, (LPCSTR)RT_DIALOG )) ||
1748 !(ptr = LoadResource(hInstance, hrsrc)))
1749 {
1750 SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
1751 return -1;
1752 }
1753 if (hWndParent != NULL && !IsWindow(hWndParent))
1754 {
1755 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1756 return 0;
1757 }
1758 hwnd = DIALOG_CreateIndirect(hInstance, ptr, hWndParent, lpDialogFunc, dwInitParam, FALSE, TRUE);
1759 if (hwnd) return DIALOG_DoDialogBox(hwnd, hWndParent);
1760 return -1;
1761 }
1762
1763
1764 /*
1765 * @implemented
1766 */
1767 INT_PTR
1768 WINAPI
1769 DialogBoxParamW(
1770 HINSTANCE hInstance,
1771 LPCWSTR lpTemplateName,
1772 HWND hWndParent,
1773 DLGPROC lpDialogFunc,
1774 LPARAM dwInitParam)
1775 {
1776 HWND hwnd;
1777 HRSRC hrsrc;
1778 LPCDLGTEMPLATE ptr;
1779 //// ReactOS rev 33532
1780 if (!(hrsrc = FindResourceW( hInstance, lpTemplateName, (LPCWSTR)RT_DIALOG )) ||
1781 !(ptr = LoadResource(hInstance, hrsrc)))
1782 {
1783 SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
1784 return -1;
1785 }
1786 if (hWndParent != NULL && !IsWindow(hWndParent))
1787 {
1788 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1789 return 0;
1790 }
1791 hwnd = DIALOG_CreateIndirect(hInstance, ptr, hWndParent, lpDialogFunc, dwInitParam, TRUE, TRUE);
1792 if (hwnd) return DIALOG_DoDialogBox(hwnd, hWndParent);
1793 return -1;
1794 }
1795
1796
1797 /*
1798 * @implemented
1799 */
1800 int
1801 WINAPI
1802 DlgDirListA(
1803 HWND hDlg,
1804 LPSTR lpPathSpec,
1805 int nIDListBox,
1806 int nIDStaticPath,
1807 UINT uFileType)
1808 {
1809 return DIALOG_DlgDirListA( hDlg, lpPathSpec, nIDListBox, nIDStaticPath, uFileType, FALSE );
1810 }
1811
1812
1813 /*
1814 * @implemented
1815 */
1816 int
1817 WINAPI
1818 DlgDirListComboBoxA(
1819 HWND hDlg,
1820 LPSTR lpPathSpec,
1821 int nIDComboBox,
1822 int nIDStaticPath,
1823 UINT uFiletype)
1824 {
1825 return DIALOG_DlgDirListA( hDlg, lpPathSpec, nIDComboBox, nIDStaticPath, uFiletype, TRUE );
1826 }
1827
1828
1829 /*
1830 * @implemented
1831 */
1832 int
1833 WINAPI
1834 DlgDirListComboBoxW(
1835 HWND hDlg,
1836 LPWSTR lpPathSpec,
1837 int nIDComboBox,
1838 int nIDStaticPath,
1839 UINT uFiletype)
1840 {
1841 return DIALOG_DlgDirListW( hDlg, lpPathSpec, nIDComboBox, nIDStaticPath, uFiletype, TRUE );
1842 }
1843
1844
1845 /*
1846 * @implemented
1847 */
1848 int
1849 WINAPI
1850 DlgDirListW(
1851 HWND hDlg,
1852 LPWSTR lpPathSpec,
1853 int nIDListBox,
1854 int nIDStaticPath,
1855 UINT uFileType)
1856 {
1857 return DIALOG_DlgDirListW( hDlg, lpPathSpec, nIDListBox, nIDStaticPath, uFileType, FALSE );
1858 }
1859
1860
1861 /*
1862 * @implemented
1863 */
1864 BOOL
1865 WINAPI
1866 DlgDirSelectComboBoxExA(
1867 HWND hDlg,
1868 LPSTR lpString,
1869 int nCount,
1870 int nIDComboBox)
1871 {
1872 return DIALOG_DlgDirSelect( hDlg, (LPWSTR)lpString, nCount, nIDComboBox, FALSE, TRUE );
1873 }
1874
1875
1876 /*
1877 * @implemented
1878 */
1879 BOOL
1880 WINAPI
1881 DlgDirSelectComboBoxExW(
1882 HWND hDlg,
1883 LPWSTR lpString,
1884 int nCount,
1885 int nIDComboBox)
1886 {
1887 return DIALOG_DlgDirSelect( hDlg, (LPWSTR)lpString, nCount, nIDComboBox, TRUE, TRUE );
1888 }
1889
1890
1891 /*
1892 * @implemented
1893 */
1894 BOOL
1895 WINAPI
1896 DlgDirSelectExA(
1897 HWND hDlg,
1898 LPSTR lpString,
1899 int nCount,
1900 int nIDListBox)
1901 {
1902 return DIALOG_DlgDirSelect( hDlg, (LPWSTR)lpString, nCount, nIDListBox, FALSE, FALSE );
1903 }
1904
1905
1906 /*
1907 * @implemented
1908 */
1909 BOOL
1910 WINAPI
1911 DlgDirSelectExW(
1912 HWND hDlg,
1913 LPWSTR lpString,
1914 int nCount,
1915 int nIDListBox)
1916 {
1917 return DIALOG_DlgDirSelect( hDlg, lpString, nCount, nIDListBox, TRUE, FALSE );
1918 }
1919
1920
1921 /*
1922 * @implemented
1923 */
1924 BOOL
1925 WINAPI
1926 EndDialog(
1927 HWND hDlg,
1928 INT_PTR nResult)
1929 {
1930 BOOL wasEnabled = TRUE;
1931 DIALOGINFO * dlgInfo;
1932 HWND owner;
1933
1934 if (!(dlgInfo = GETDLGINFO(hDlg))) return FALSE;
1935
1936 dlgInfo->idResult = nResult;
1937 dlgInfo->flags |= DF_END;
1938 wasEnabled = (dlgInfo->flags & DF_OWNERENABLED);
1939
1940 if (wasEnabled && (owner = GetWindow( hDlg, GW_OWNER )))
1941 DIALOG_EnableOwner( owner );
1942
1943 /* Windows sets the focus to the dialog itself in EndDialog */
1944
1945 if (IsChild(hDlg, GetFocus()))
1946 SetFocus( hDlg );
1947
1948 /* Don't have to send a ShowWindow(SW_HIDE), just do
1949 SetWindowPos with SWP_HIDEWINDOW as done in Windows */
1950
1951 SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE
1952 | SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW);
1953
1954 if (hDlg == GetActiveWindow()) WinPosActivateOtherWindow( hDlg );
1955
1956 /* unblock dialog loop */
1957 PostMessageA(hDlg, WM_NULL, 0, 0);
1958 return TRUE;
1959 }
1960
1961
1962 /*
1963 * @implemented
1964 */
1965 LONG
1966 WINAPI
1967 GetDialogBaseUnits(VOID)
1968 {
1969 static DWORD units;
1970
1971 if (!units)
1972 {
1973 HDC hdc;
1974 SIZE size;
1975
1976 if ((hdc = GetDC(0)))
1977 {
1978 size.cx = GdiGetCharDimensions( hdc, NULL, &size.cy );
1979 if (size.cx) units = MAKELONG( size.cx, size.cy );
1980 ReleaseDC( 0, hdc );
1981 }
1982 }
1983 return units;
1984 }
1985
1986
1987 /*
1988 * @implemented
1989 */
1990 int
1991 WINAPI
1992 GetDlgCtrlID(
1993 HWND hwndCtl)
1994 {
1995 return GetWindowLongPtrW( hwndCtl, GWLP_ID );
1996 }
1997
1998
1999 /*
2000 * @implemented
2001 */
2002 HWND
2003 WINAPI
2004 GetDlgItem(
2005 HWND hDlg,
2006 int nIDDlgItem)
2007 {
2008 int i;
2009 HWND *list = WIN_ListChildren(hDlg);
2010 HWND ret = 0;
2011
2012 if (!list) return 0;
2013
2014 for (i = 0; list[i]; i++) if (GetWindowLongPtrW(list[i], GWLP_ID) == nIDDlgItem) break;
2015 ret = list[i];
2016 HeapFree(GetProcessHeap(), 0, list);
2017 return ret;
2018 }
2019
2020
2021 /*
2022 * @implemented
2023 */
2024 UINT
2025 WINAPI
2026 GetDlgItemInt(
2027 HWND hDlg,
2028 int nIDDlgItem,
2029 BOOL *lpTranslated,
2030 BOOL bSigned)
2031 {
2032 char str[30];
2033 char * endptr;
2034 long result = 0;
2035
2036 if (lpTranslated) *lpTranslated = FALSE;
2037 if (!SendDlgItemMessageA(hDlg, nIDDlgItem, WM_GETTEXT, sizeof(str), (LPARAM)str))
2038 return 0;
2039 if (bSigned)
2040 {
2041 result = strtol( str, &endptr, 10 );
2042 if (!endptr || (endptr == str)) /* Conversion was unsuccessful */
2043 return 0;
2044 /* FIXME: errno? */
2045 if (((result == 0) || (result == 0xFFFFFFFF))/* && (errno == ERANGE) */)
2046 return 0;
2047 }
2048 else
2049 {
2050 result = strtoul( str, &endptr, 10 );
2051 if (!endptr || (endptr == str)) /* Conversion was unsuccessful */
2052 return 0;
2053 /* FIXME: errno? */
2054 if ((result == 0xFFFFFFFF)/* && (errno == ERANGE) */) return 0;
2055 }
2056 if (lpTranslated) *lpTranslated = TRUE;
2057 return (UINT)result;
2058 }
2059
2060
2061 /*
2062 * @implemented
2063 */
2064 UINT
2065 WINAPI
2066 GetDlgItemTextA(
2067 HWND hDlg,
2068 int nIDDlgItem,
2069 LPSTR lpString,
2070 int nMaxCount)
2071 {
2072 if (lpString && (nMaxCount > 0)) lpString[0] = '\0';
2073 return (UINT)SendDlgItemMessageA( hDlg, nIDDlgItem, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2074 }
2075
2076
2077 /*
2078 * @implemented
2079 */
2080 UINT
2081 WINAPI
2082 GetDlgItemTextW(
2083 HWND hDlg,
2084 int nIDDlgItem,
2085 LPWSTR lpString,
2086 int nMaxCount)
2087 {
2088 if (lpString && (nMaxCount > 0)) lpString[0] = '\0';
2089 return (UINT)SendDlgItemMessageW( hDlg, nIDDlgItem, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2090 }
2091
2092 /*
2093 * @implemented
2094 */
2095 HWND
2096 WINAPI
2097 GetNextDlgGroupItem(
2098 HWND hDlg,
2099 HWND hCtl,
2100 BOOL bPrevious)
2101 {
2102 HWND hwnd, hwndNext, retvalue, hwndLastGroup = 0;
2103 BOOL fLooped=FALSE;
2104 BOOL fSkipping=FALSE;
2105
2106 if (hDlg == hCtl) hCtl = NULL;
2107 if (!hCtl && bPrevious) return 0;
2108
2109 /* if the hwndCtrl is the child of the control in the hwndDlg,
2110 * then the hwndDlg has to be the parent of the hwndCtrl */
2111
2112 if (hCtl)
2113 {
2114 if (!IsChild (hDlg, hCtl)) return 0;
2115 /* Make sure hwndCtrl is a top-level child */
2116
2117 }
2118 else
2119 {
2120 /* No ctrl specified -> start from the beginning */
2121 if (!(hCtl = GetWindow( hDlg, GW_CHILD ))) return 0;
2122 /* MSDN is wrong. fPrevious does not result in the last child */
2123
2124 /* No ctrl specified -> start from the beginning */
2125 if (!(hCtl = GetWindow( hDlg, GW_CHILD ))) return 0;
2126
2127 /* MSDN is wrong. fPrevious does not result in the last child */
2128
2129 /* Maybe that first one is valid. If so then we don't want to skip it*/
2130 if ((GetWindowLongPtrW( hCtl, GWL_STYLE ) & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE)
2131 {
2132 return hCtl;
2133 }
2134
2135 }
2136
2137 /* Always go forward around the group and list of controls; for the
2138 * previous control keep track; for the next break when you find one
2139 */
2140 retvalue = hCtl;
2141 hwnd = hCtl;
2142 while (hwndNext = GetWindow (hwnd, GW_HWNDNEXT),
2143 1)
2144 {
2145 while (!hwndNext)
2146 {
2147 /* Climb out until there is a next sibling of the ancestor or we
2148 * reach the top (in which case we loop back to the start)
2149 */
2150 if (hDlg == GetParent (hwnd))
2151 {
2152 /* Wrap around to the beginning of the list, within the same
2153 * group. (Once only)
2154 */
2155 if (fLooped) goto end;
2156 fLooped = TRUE;
2157 hwndNext = GetWindow (hDlg, GW_CHILD);
2158 }
2159 else
2160 {
2161 hwnd = GetParent (hwnd);
2162 hwndNext = GetWindow (hwnd, GW_HWNDNEXT);
2163 }
2164 }
2165 hwnd = hwndNext;
2166
2167 /* Wander down the leading edge of controlparents */
2168 while ( (GetWindowLongPtrW (hwnd, GWL_EXSTYLE) & WS_EX_CONTROLPARENT) &&
2169 ((GetWindowLongPtrW (hwnd, GWL_STYLE) & (WS_VISIBLE | WS_DISABLED)) == WS_VISIBLE) &&
2170 (hwndNext = GetWindow (hwnd, GW_CHILD)))
2171 hwnd = hwndNext;
2172 /* Question. If the control is a control parent but either has no
2173 * children or is not visible/enabled then if it has a WS_GROUP does
2174 * it count? For that matter does it count anyway?
2175 * I believe it doesn't count.
2176 */
2177
2178 if ((GetWindowLongPtrW (hwnd, GWL_STYLE) & WS_GROUP))
2179 {
2180 hwndLastGroup = hwnd;
2181 if (!fSkipping)
2182 {
2183 /* Look for the beginning of the group */
2184 fSkipping = TRUE;
2185 }
2186 }
2187
2188 if (hwnd == hCtl)
2189 {
2190 if (!fSkipping) break;
2191 if (hwndLastGroup == hwnd) break;
2192 hwnd = hwndLastGroup;
2193 fSkipping = FALSE;
2194 fLooped = FALSE;
2195 }
2196
2197 if (!fSkipping &&
2198 (GetWindowLongPtrW (hwnd, GWL_STYLE) & (WS_VISIBLE|WS_DISABLED)) ==
2199 WS_VISIBLE)
2200 {
2201 retvalue = hwnd;
2202 if (!bPrevious) break;
2203 }
2204 }
2205 end:
2206 return retvalue;
2207 }
2208
2209
2210 /*
2211 * @implemented
2212 */
2213 HWND
2214 WINAPI
2215 GetNextDlgTabItem(
2216 HWND hDlg,
2217 HWND hCtl,
2218 BOOL bPrevious)
2219 {
2220 /* Undocumented but tested under Win2000 and WinME */
2221 if (hDlg == hCtl) hCtl = NULL;
2222
2223 /* Contrary to MSDN documentation, tested under Win2000 and WinME
2224 * NB GetLastError returns whatever was set before the function was
2225 * called.
2226 */
2227 if (!hCtl && bPrevious) return 0;
2228
2229 return DIALOG_GetNextTabItem(hDlg, hDlg, hCtl, bPrevious);
2230 }
2231
2232
2233 #if 0
2234 BOOL
2235 WINAPI
2236 IsDialogMessage(
2237 HWND hDlg,
2238 LPMSG lpMsg)
2239 {
2240 return IsDialogMessageW(hDlg, lpMsg);
2241 }
2242 #endif
2243
2244 /***********************************************************************
2245 * DIALOG_FixOneChildOnChangeFocus
2246 *
2247 * Callback helper for DIALOG_FixChildrenOnChangeFocus
2248 */
2249
2250 static BOOL CALLBACK DIALOG_FixOneChildOnChangeFocus (HWND hwndChild,
2251 LPARAM lParam)
2252 {
2253 /* If a default pushbutton then no longer default */
2254 if (DLGC_DEFPUSHBUTTON & SendMessageW (hwndChild, WM_GETDLGCODE, 0, 0))
2255 SendMessageW (hwndChild, BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
2256 return TRUE;
2257 }
2258
2259 /***********************************************************************
2260 * DIALOG_FixChildrenOnChangeFocus
2261 *
2262 * Following the change of focus that occurs for example after handling
2263 * a WM_KEYDOWN VK_TAB in IsDialogMessage, some tidying of the dialog's
2264 * children may be required.
2265 */
2266 static void DIALOG_FixChildrenOnChangeFocus (HWND hwndDlg, HWND hwndNext)
2267 {
2268 INT dlgcode_next = SendMessageW (hwndNext, WM_GETDLGCODE, 0, 0);
2269 /* INT dlgcode_dlg = SendMessageW (hwndDlg, WM_GETDLGCODE, 0, 0); */
2270 /* Windows does ask for this. I don't know why yet */
2271
2272 EnumChildWindows (hwndDlg, DIALOG_FixOneChildOnChangeFocus, 0);
2273
2274 /* If the button that is getting the focus WAS flagged as the default
2275 * pushbutton then ask the dialog what it thinks the default is and
2276 * set that in the default style.
2277 */
2278 if (dlgcode_next & DLGC_DEFPUSHBUTTON)
2279 {
2280 DWORD def_id = SendMessageW (hwndDlg, DM_GETDEFID, 0, 0);
2281 if (HIWORD(def_id) == DC_HASDEFID)
2282 {
2283 HWND hwndDef;
2284 def_id = LOWORD(def_id);
2285 hwndDef = GetDlgItem (hwndDlg, def_id);
2286 if (hwndDef)
2287 {
2288 INT dlgcode_def = SendMessageW (hwndDef, WM_GETDLGCODE, 0, 0);
2289 /* I know that if it is a button then it should already be a
2290 * UNDEFPUSHBUTTON, since we have just told the buttons to
2291 * change style. But maybe they ignored our request
2292 */
2293 if ((dlgcode_def & DLGC_BUTTON) &&
2294 (dlgcode_def & DLGC_UNDEFPUSHBUTTON))
2295 {
2296 SendMessageW (hwndDef, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE);
2297 }
2298 }
2299 }
2300 }
2301 else if ((dlgcode_next & DLGC_BUTTON) && (dlgcode_next & DLGC_UNDEFPUSHBUTTON))
2302 {
2303 SendMessageW (hwndNext, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE);
2304 /* I wonder why it doesn't send a DM_SETDEFID */
2305 }
2306 }
2307
2308 /*
2309 * @implemented
2310 */
2311 BOOL
2312 WINAPI
2313 IsDialogMessageW(
2314 HWND hDlg,
2315 LPMSG lpMsg)
2316 {
2317 INT dlgCode = 0;
2318
2319 if (CallMsgFilterW( lpMsg, MSGF_DIALOGBOX )) return TRUE;
2320
2321 if (hDlg == GetDesktopWindow()) return FALSE;
2322 if ((hDlg != lpMsg->hwnd) && !IsChild( hDlg, lpMsg->hwnd )) return FALSE;
2323
2324 hDlg = DIALOG_FindMsgDestination(hDlg);
2325
2326 switch(lpMsg->message)
2327 {
2328 case WM_KEYDOWN:
2329 dlgCode = SendMessageW( lpMsg->hwnd, WM_GETDLGCODE, lpMsg->wParam, (LPARAM)lpMsg );
2330 if (dlgCode & DLGC_WANTMESSAGE) break;
2331
2332 switch(lpMsg->wParam)
2333 {
2334 case VK_TAB:
2335 if (!(dlgCode & DLGC_WANTTAB))
2336 {
2337 SendMessageW(hDlg, WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0);
2338
2339 /* I am not sure under which circumstances the TAB is handled
2340 * each way. All I do know is that it does not always simply
2341 * send WM_NEXTDLGCTL. (Personally I have never yet seen it
2342 * do so but I presume someone has)
2343 */
2344 if (GETDLGINFO(hDlg))
2345 SendMessageW( hDlg, WM_NEXTDLGCTL, (GetKeyState(VK_SHIFT) & 0x8000), 0 );
2346 else
2347 {
2348 /* It would appear that GetNextDlgTabItem can handle being
2349 * passed hwndDlg rather than NULL but that is undocumented
2350 * so let's do it properly
2351 */
2352 HWND hwndFocus = GetFocus();
2353 HWND hwndNext = GetNextDlgTabItem (hDlg,
2354 hwndFocus == hDlg ? NULL : hwndFocus,
2355 GetKeyState (VK_SHIFT) & 0x8000);
2356 if (hwndNext)
2357 {
2358 dlgCode = SendMessageW (hwndNext, WM_GETDLGCODE,
2359 lpMsg->wParam, (LPARAM)lpMsg);
2360 if (dlgCode & DLGC_HASSETSEL)
2361 {
2362 INT maxlen = 1 + SendMessageW (hwndNext, WM_GETTEXTLENGTH, 0, 0);
2363 WCHAR *buffer = HeapAlloc (GetProcessHeap(), 0, maxlen * sizeof(WCHAR));
2364 if (buffer)
2365 {
2366 INT length;
2367 SendMessageW (hwndNext, WM_GETTEXT, maxlen, (LPARAM) buffer);
2368 length = strlenW (buffer);
2369 HeapFree (GetProcessHeap(), 0, buffer);
2370 SendMessageW (hwndNext, EM_SETSEL, 0, length);
2371 }
2372 }
2373 SetFocus (hwndNext);
2374 DIALOG_FixChildrenOnChangeFocus (hDlg, hwndNext);
2375 }
2376 else
2377 return FALSE;
2378 }
2379 return TRUE;
2380 }
2381 break;
2382
2383 case VK_RIGHT:
2384 case VK_DOWN:
2385 case VK_LEFT:
2386 case VK_UP:
2387 if (!(dlgCode & DLGC_WANTARROWS))
2388 {
2389 BOOL fPrevious = (lpMsg->wParam == VK_LEFT || lpMsg->wParam == VK_UP);
2390 HWND hwndNext = GetNextDlgGroupItem (hDlg, GetFocus(), fPrevious );
2391 SendMessageW( hDlg, WM_NEXTDLGCTL, (WPARAM)hwndNext, 1 );
2392 return TRUE;
2393 }
2394 break;
2395
2396 case VK_CANCEL:
2397 case VK_ESCAPE:
2398 SendMessageW( hDlg, WM_COMMAND, IDCANCEL, (LPARAM)GetDlgItem( hDlg, IDCANCEL ) );
2399 return TRUE;
2400
2401 case VK_EXECUTE:
2402 case VK_RETURN:
2403 {
2404 DWORD dw;
2405 if ((GetFocus() == lpMsg->hwnd) &&
2406 (SendMessageW (lpMsg->hwnd, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON))
2407 {
2408 SendMessageW (hDlg, WM_COMMAND, MAKEWPARAM (GetDlgCtrlID(lpMsg->hwnd),BN_CLICKED), (LPARAM)lpMsg->hwnd);
2409 }
2410 else if (DC_HASDEFID == HIWORD(dw = SendMessageW (hDlg, DM_GETDEFID, 0, 0)))
2411 {
2412 HWND hwndDef = GetDlgItem(hDlg, LOWORD(dw));
2413 if (hwndDef ? IsWindowEnabled(hwndDef) : LOWORD(dw)==IDOK)
2414 SendMessageW( hDlg, WM_COMMAND, MAKEWPARAM( LOWORD(dw), BN_CLICKED ), (LPARAM)hwndDef);
2415 }
2416 else
2417 {
2418 SendMessageW( hDlg, WM_COMMAND, IDOK, (LPARAM)GetDlgItem( hDlg, IDOK ) );
2419
2420 }
2421 }
2422 return TRUE;
2423 }
2424 break;
2425
2426 case WM_CHAR:
2427 /* FIXME Under what circumstances does WM_GETDLGCODE get sent?
2428 * It does NOT get sent in the test program I have
2429 */
2430 dlgCode = SendMessageW( lpMsg->hwnd, WM_GETDLGCODE, lpMsg->wParam, (LPARAM)lpMsg );
2431 if (dlgCode & (DLGC_WANTCHARS|DLGC_WANTMESSAGE)) break;
2432 if (lpMsg->wParam == '\t' && (dlgCode & DLGC_WANTTAB)) break;
2433 /* drop through */
2434
2435 case WM_SYSCHAR:
2436 if (DIALOG_IsAccelerator( lpMsg->hwnd, hDlg, lpMsg->wParam ))
2437 {
2438 /* don't translate or dispatch */
2439 return TRUE;
2440 }
2441 break;
2442 //// ReactOS
2443 case WM_SYSKEYDOWN:
2444 /* If the ALT key is being pressed display the keyboard cues */
2445 if (lpMsg->lParam & (1 << 29))
2446 SendMessageW(hDlg, WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0);
2447 break;
2448
2449 case WM_SYSCOMMAND:
2450 /* If the ALT key is being pressed display the keyboard cues */
2451 if (lpMsg->wParam == SC_KEYMENU)
2452 {
2453 SendMessageW(hDlg, WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0);
2454 }
2455 break;
2456 }
2457
2458 TranslateMessage( lpMsg );
2459 DispatchMessageW( lpMsg );
2460 return TRUE;
2461 }
2462
2463
2464 /*
2465 * @implemented
2466 */
2467 UINT
2468 WINAPI
2469 IsDlgButtonChecked(
2470 HWND hDlg,
2471 int nIDButton)
2472 {
2473 return (UINT)SendDlgItemMessageW( hDlg, nIDButton, BM_GETCHECK, 0, 0 );
2474 }
2475
2476
2477 /*
2478 * @implemented
2479 */
2480 BOOL
2481 WINAPI
2482 MapDialogRect(
2483 HWND hDlg,
2484 LPRECT lpRect)
2485 {
2486 DIALOGINFO * dlgInfo;
2487 if (!(dlgInfo = GETDLGINFO(hDlg))) return FALSE;
2488 lpRect->left = MulDiv(lpRect->left, dlgInfo->xBaseUnit, 4);
2489 lpRect->right = MulDiv(lpRect->right, dlgInfo->xBaseUnit, 4);
2490 lpRect->top = MulDiv(lpRect->top, dlgInfo->yBaseUnit, 8);
2491 lpRect->bottom = MulDiv(lpRect->bottom, dlgInfo->yBaseUnit, 8);
2492 return TRUE;
2493 }
2494
2495
2496 /*
2497 * @implemented
2498 */
2499 LRESULT
2500 WINAPI
2501 SendDlgItemMessageA(
2502 HWND hDlg,
2503 int nIDDlgItem,
2504 UINT Msg,
2505 WPARAM wParam,
2506 LPARAM lParam)
2507 {
2508 HWND hwndCtrl = GetDlgItem( hDlg, nIDDlgItem );
2509 if (hwndCtrl) return SendMessageA( hwndCtrl, Msg, wParam, lParam );
2510 else return 0;
2511 }
2512
2513
2514 /*
2515 * @implemented
2516 */
2517 LRESULT
2518 WINAPI
2519 SendDlgItemMessageW(
2520 HWND hDlg,
2521 int nIDDlgItem,
2522 UINT Msg,
2523 WPARAM wParam,
2524 LPARAM lParam)
2525 {
2526 HWND hwndCtrl = GetDlgItem( hDlg, nIDDlgItem );
2527 if (hwndCtrl) return SendMessageW( hwndCtrl, Msg, wParam, lParam );
2528 else return 0;
2529 }
2530
2531
2532 /*
2533 * @implemented
2534 */
2535 BOOL
2536 WINAPI
2537 SetDlgItemInt(
2538 HWND hDlg,
2539 int nIDDlgItem,
2540 UINT uValue,
2541 BOOL bSigned)
2542 {
2543 char str[20];
2544
2545 if (bSigned) sprintf( str, "%d", (INT)uValue );
2546 else sprintf( str, "%u", uValue );
2547 SendDlgItemMessageA( hDlg, nIDDlgItem, WM_SETTEXT, 0, (LPARAM)str );
2548 return TRUE;
2549 }
2550
2551
2552 /*
2553 * @implemented
2554 */
2555 BOOL
2556 WINAPI
2557 SetDlgItemTextA(
2558 HWND hDlg,
2559 int nIDDlgItem,
2560 LPCSTR lpString)
2561 {
2562 return SendDlgItemMessageA( hDlg, nIDDlgItem, WM_SETTEXT, 0, (LPARAM)lpString );
2563 }
2564
2565
2566 /*
2567 * @implemented
2568 */
2569 BOOL
2570 WINAPI
2571 SetDlgItemTextW(
2572 HWND hDlg,
2573 int nIDDlgItem,
2574 LPCWSTR lpString)
2575 {
2576 return SendDlgItemMessageW( hDlg, nIDDlgItem, WM_SETTEXT, 0, (LPARAM)lpString );
2577 }
2578
2579
2580 /*
2581 * @implemented
2582 */
2583 BOOL
2584 WINAPI
2585 CheckDlgButton(
2586 HWND hDlg,
2587 int nIDButton,
2588 UINT uCheck)
2589 {
2590 SendDlgItemMessageW( hDlg, nIDButton, BM_SETCHECK, uCheck, 0 );
2591 return TRUE;
2592 }
2593
2594 static BOOL CALLBACK CheckRB(HWND hwnd, LPARAM lParam)
2595 {
2596 LONG lChildID = GetWindowLongPtrW(hwnd, GWLP_ID);
2597 RADIOGROUP *lpRadioGroup = (RADIOGROUP *)lParam;
2598
2599 if((lChildID >= lpRadioGroup->firstID) &&
2600 (lChildID <= lpRadioGroup->lastID))
2601 {
2602 if (lChildID == lpRadioGroup->checkID)
2603 {
2604 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
2605 }
2606 else
2607 {
2608 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
2609 }
2610 }
2611
2612 return TRUE;
2613 }
2614
2615 /*
2616 * @implemented
2617 */
2618 BOOL
2619 WINAPI
2620 CheckRadioButton(
2621 HWND hDlg,
2622 int nIDFirstButton,
2623 int nIDLastButton,
2624 int nIDCheckButton)
2625 {
2626 RADIOGROUP radioGroup;
2627
2628 radioGroup.firstID = nIDFirstButton;
2629 radioGroup.lastID = nIDLastButton;
2630 radioGroup.checkID = nIDCheckButton;
2631
2632 return EnumChildWindows(hDlg, CheckRB, (LPARAM)&radioGroup);
2633 }