3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
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.
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.
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.
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/dialog.c
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Thomas Weidenmueller (w3seek@users.sourceforge.net)
26 * Steven Edwards (Steven_Ed4153@yahoo.com)
28 * 07-26-2003 Code ported from wine
29 * 09-05-2001 CSH Created
32 /* INCLUDES ******************************************************************/
36 #include <wine/debug.h>
38 /* MACROS/DEFINITIONS ********************************************************/
41 #define DF_OWNERENABLED 0x0002
42 #define CW_USEDEFAULT16 ((short)0x8000)
43 #define DWLP_ROS_DIALOGINFO (DWLP_USER+sizeof(ULONG_PTR))
44 #define GETDLGINFO(hwnd) (DIALOGINFO*)GetWindowLongPtrW((hwnd),DWLP_ROS_DIALOGINFO)
45 #define SETDLGINFO(hwnd, info) SetWindowLongPtrW((hwnd), DWLP_ROS_DIALOGINFO, (LONG_PTR)(info))
46 #define GET_WORD(ptr) (*(WORD *)(ptr))
47 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
48 #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
49 #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
50 #define DIALOG_CLASS_ATOMA MAKEINTATOMA(32770) /* Dialog */
51 #define DIALOG_CLASS_ATOMW MAKEINTATOMW(32770) /* Dialog */
53 void STDCALL
WinPosActivateOtherWindow(HWND hwnd
);
55 /* INTERNAL STRUCTS **********************************************************/
57 /* Dialog info structure */
60 HWND hwndFocus
; /* Current control with focus */
61 HFONT hUserFont
; /* Dialog font */
62 HMENU hMenu
; /* Dialog menu */
63 UINT xBaseUnit
; /* Dialog units (depends on the font) */
65 INT idResult
; /* EndDialog() result / default pushbutton ID */
66 UINT flags
; /* EndDialog() called for this dialog */
69 /* Dialog control information */
107 /* GetDlgItem structure */
114 /* CheckRadioButton structure */
123 /*********************************************************************
124 * dialog class descriptor
126 const struct builtin_class_descr DIALOG_builtin_class
=
128 DIALOG_CLASS_ATOMW
, /* name */
129 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
130 (WNDPROC
) DefDlgProcW
, /* procW */
131 (WNDPROC
) DefDlgProcA
, /* procA */
132 DLGWINDOWEXTRA
, /* extra */
133 (LPCWSTR
) IDC_ARROW
, /* cursor */
138 /* INTERNAL FUNCTIONS ********************************************************/
140 /***********************************************************************
143 * Helper function for modal dialogs to enable again the
144 * owner of the dialog box.
146 void DIALOG_EnableOwner( HWND hOwner
)
148 /* Owner must be a top-level window */
150 hOwner
= GetAncestor( hOwner
, GA_ROOT
);
152 EnableWindow( hOwner
, TRUE
);
155 /***********************************************************************
156 * DIALOG_DisableOwner
158 * Helper function for modal dialogs to disable the
159 * owner of the dialog box. Returns TRUE if owner was enabled.
161 BOOL
DIALOG_DisableOwner( HWND hOwner
)
163 /* Owner must be a top-level window */
165 hOwner
= GetAncestor( hOwner
, GA_ROOT
);
166 if (!hOwner
) return FALSE
;
167 if (IsWindowEnabled( hOwner
))
169 EnableWindow( hOwner
, FALSE
);
176 /***********************************************************************
177 * DIALOG_GetControl32
179 * Return the class and text of the control pointed to by ptr,
180 * fill the header structure and return a pointer to the next control.
182 static const WORD
*DIALOG_GetControl32( const WORD
*p
, DLG_CONTROL_INFO
*info
,
187 info
->helpId
= GET_DWORD(p
); p
+= 2;
188 info
->exStyle
= GET_DWORD(p
); p
+= 2;
189 info
->style
= GET_DWORD(p
); p
+= 2;
194 info
->style
= GET_DWORD(p
); p
+= 2;
195 info
->exStyle
= GET_DWORD(p
); p
+= 2;
197 info
->x
= GET_WORD(p
); p
++;
198 info
->y
= GET_WORD(p
); p
++;
199 info
->cx
= GET_WORD(p
); p
++;
200 info
->cy
= GET_WORD(p
); p
++;
204 /* id is a DWORD for DIALOGEX */
205 info
->id
= GET_DWORD(p
);
210 info
->id
= GET_WORD(p
);
214 if (GET_WORD(p
) == 0xffff)
216 static const WCHAR class_names
[6][10] =
218 { 'B','u','t','t','o','n', }, /* 0x80 */
219 { 'E','d','i','t', }, /* 0x81 */
220 { 'S','t','a','t','i','c', }, /* 0x82 */
221 { 'L','i','s','t','B','o','x', }, /* 0x83 */
222 { 'S','c','r','o','l','l','B','a','r', }, /* 0x84 */
223 { 'C','o','m','b','o','B','o','x', } /* 0x85 */
225 WORD id
= GET_WORD(p
+1);
226 /* Windows treats dialog control class ids 0-5 same way as 0x80-0x85 */
227 if ((id
>= 0x80) && (id
<= 0x85)) id
-= 0x80;
229 info
->className
= class_names
[id
];
232 info
->className
= NULL
;
233 /* FIXME: load other classes here? */
239 info
->className
= (LPCWSTR
)p
;
240 p
+= wcslen( info
->className
) + 1;
243 if (GET_WORD(p
) == 0xffff) /* Is it an integer id? */
245 info
->windowName
= HeapAlloc( GetProcessHeap(), 0, sizeof(L
"#65535") );
246 swprintf((LPWSTR
)info
->windowName
, L
"#%d", GET_WORD(p
+ 1));
247 info
->windowNameFree
= TRUE
;
252 info
->windowName
= (LPCWSTR
)p
;
253 info
->windowNameFree
= FALSE
;
254 p
+= wcslen( info
->windowName
) + 1;
260 p
+= GET_WORD(p
) / sizeof(WORD
);
262 else info
->data
= NULL
;
265 /* Next control is on dword boundary */
266 return (const WORD
*)((((int)p
) + 3) & ~3);
269 /***********************************************************************
270 * DIALOG_CreateControls32
272 * Create the control windows for a dialog.
274 static BOOL
DIALOG_CreateControls32( HWND hwnd
, LPCSTR
template, const DLG_TEMPLATE
*dlgTemplate
,
275 HINSTANCE hInst
, BOOL unicode
)
277 DIALOGINFO
* dlgInfo
;
278 DLG_CONTROL_INFO info
;
279 HWND hwndCtrl
, hwndDefButton
= 0;
280 INT items
= dlgTemplate
->nbItems
;
282 if (!(dlgInfo
= GETDLGINFO(hwnd
))) return -1;
286 template = (LPCSTR
)DIALOG_GetControl32( (WORD
*)template, &info
,
287 dlgTemplate
->dialogEx
);
289 if (info
.style
& WS_BORDER
)
291 info
.style
&= ~WS_BORDER
;
292 info
.exStyle
|= WS_EX_CLIENTEDGE
;
296 hwndCtrl
= CreateWindowExW( info
.exStyle
| WS_EX_NOPARENTNOTIFY
,
297 info
.className
, info
.windowName
,
298 info
.style
| WS_CHILD
,
299 MulDiv(info
.x
, dlgInfo
->xBaseUnit
, 4),
300 MulDiv(info
.y
, dlgInfo
->yBaseUnit
, 8),
301 MulDiv(info
.cx
, dlgInfo
->xBaseUnit
, 4),
302 MulDiv(info
.cy
, dlgInfo
->yBaseUnit
, 8),
303 hwnd
, (HMENU
)info
.id
,
304 hInst
, (LPVOID
)info
.data
);
308 LPSTR
class = (LPSTR
)info
.className
;
309 LPSTR caption
= (LPSTR
)info
.windowName
;
313 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, info
.className
, -1, NULL
, 0, NULL
, NULL
);
314 class = HeapAlloc( GetProcessHeap(), 0, len
);
315 WideCharToMultiByte( CP_ACP
, 0, info
.className
, -1, class, len
, NULL
, NULL
);
319 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, info
.windowName
, -1, NULL
, 0, NULL
, NULL
);
320 caption
= HeapAlloc( GetProcessHeap(), 0, len
);
321 WideCharToMultiByte( CP_ACP
, 0, info
.windowName
, -1, caption
, len
, NULL
, NULL
);
323 hwndCtrl
= CreateWindowExA( info
.exStyle
| WS_EX_NOPARENTNOTIFY
,
324 class, caption
, info
.style
| WS_CHILD
,
325 MulDiv(info
.x
, dlgInfo
->xBaseUnit
, 4),
326 MulDiv(info
.y
, dlgInfo
->yBaseUnit
, 8),
327 MulDiv(info
.cx
, dlgInfo
->xBaseUnit
, 4),
328 MulDiv(info
.cy
, dlgInfo
->yBaseUnit
, 8),
329 hwnd
, (HMENU
)info
.id
,
330 hInst
, (LPVOID
)info
.data
);
331 if (HIWORD(class)) HeapFree( GetProcessHeap(), 0, class );
332 if (HIWORD(caption
)) HeapFree( GetProcessHeap(), 0, caption
);
335 if (info
.windowNameFree
)
337 HeapFree( GetProcessHeap(), 0, (LPVOID
)info
.windowName
);
342 if (dlgTemplate
->style
& DS_NOFAILCREATE
) continue;
346 /* Send initialisation messages to the control */
347 if (dlgInfo
->hUserFont
) SendMessageW( hwndCtrl
, WM_SETFONT
,
348 (WPARAM
)dlgInfo
->hUserFont
, 0 );
349 if (SendMessageW(hwndCtrl
, WM_GETDLGCODE
, 0, 0) & DLGC_DEFPUSHBUTTON
)
351 /* If there's already a default push-button, set it back */
352 /* to normal and use this one instead. */
354 SendMessageW( hwndDefButton
, BM_SETSTYLE
, BS_PUSHBUTTON
, FALSE
);
355 hwndDefButton
= hwndCtrl
;
356 dlgInfo
->idResult
= GetWindowLongPtrA( hwndCtrl
, GWLP_ID
);
362 /***********************************************************************
363 * DIALOG_FindMsgDestination
365 * The messages that IsDialogMessage sends may not go to the dialog
366 * calling IsDialogMessage if that dialog is a child, and it has the
367 * DS_CONTROL style set.
368 * We propagate up until we hit one that does not have DS_CONTROL, or
369 * whose parent is not a dialog.
371 * This is undocumented behaviour.
373 static HWND
DIALOG_FindMsgDestination( HWND hwndDlg
)
375 while (GetWindowLongA(hwndDlg
, GWL_STYLE
) & DS_CONTROL
)
377 HWND hParent
= GetParent(hwndDlg
);
380 if (!IsWindow(hParent
)) break;
382 if (!GETDLGINFO(hParent
)) /* TODO: Correct? */
393 /***********************************************************************
394 * DIALOG_IsAccelerator
396 static BOOL
DIALOG_IsAccelerator( HWND hwnd
, HWND hwndDlg
, WPARAM wParam
)
398 HWND hwndControl
= hwnd
;
405 DWORD style
= GetWindowLongW( hwndControl
, GWL_STYLE
);
406 if ((style
& (WS_VISIBLE
| WS_DISABLED
)) == WS_VISIBLE
)
408 dlgCode
= SendMessageA( hwndControl
, WM_GETDLGCODE
, 0, 0 );
409 if ( (dlgCode
& (DLGC_BUTTON
| DLGC_STATIC
)) &&
410 GetWindowTextW( hwndControl
, buffer
, sizeof(buffer
)/sizeof(WCHAR
) ))
412 /* find the accelerator key */
413 LPWSTR p
= buffer
- 2;
417 p
= wcschr( p
+ 2, '&' );
419 while (p
!= NULL
&& p
[1] == '&');
421 /* and check if it's the one we're looking for */
422 /* FIXME: usage of towupper correct? */
423 if (p
!= NULL
&& towupper( p
[1] ) == towupper( wParam
) )
425 if ((dlgCode
& DLGC_STATIC
) || (style
& 0x0f) == BS_GROUPBOX
)
427 /* set focus to the control */
428 SendMessageW( hwndDlg
, WM_NEXTDLGCTL
, (WPARAM
)hwndControl
, 1);
429 /* and bump it on to next */
430 SendMessageW( hwndDlg
, WM_NEXTDLGCTL
, 0, 0);
432 else if (dlgCode
& DLGC_BUTTON
)
434 /* send BM_CLICK message to the control */
435 SendMessageW( hwndControl
, BM_CLICK
, 0, 0 );
440 hwndNext
= GetWindow( hwndControl
, GW_CHILD
);
444 if (!hwndNext
) hwndNext
= GetWindow( hwndControl
, GW_HWNDNEXT
);
446 while (!hwndNext
&& hwndControl
)
448 hwndControl
= GetParent( hwndControl
);
449 if (hwndControl
== hwndDlg
)
451 if(hwnd
==hwndDlg
) /* prevent endless loop */
456 hwndNext
= GetWindow( hwndDlg
, GW_CHILD
);
459 hwndNext
= GetWindow( hwndControl
, GW_HWNDNEXT
);
461 hwndControl
= hwndNext
;
463 while (hwndControl
&& (hwndControl
!= hwnd
));
468 /***********************************************************************
471 INT
DIALOG_DoDialogBox( HWND hwnd
, HWND owner
)
473 DIALOGINFO
* dlgInfo
;
476 HWND ownerMsg
= GetAncestor( owner
, GA_ROOT
);
479 if (!(dlgInfo
= GETDLGINFO(hwnd
))) return -1;
482 if (!(dlgInfo
->flags
& DF_END
)) /* was EndDialog called in WM_INITDIALOG ? */
486 if (!PeekMessageW( &msg
, 0, 0, 0, PM_REMOVE
))
490 /* ShowWindow the first time the queue goes empty */
491 ShowWindow( hwnd
, SW_SHOWNORMAL
);
494 if (!(GetWindowLongW( hwnd
, GWL_STYLE
) & DS_NOIDLEMSG
))
496 /* No message present -> send ENTERIDLE and wait */
497 SendMessageW( ownerMsg
, WM_ENTERIDLE
, MSGF_DIALOGBOX
, (LPARAM
)hwnd
);
499 if (!GetMessageW( &msg
, 0, 0, 0 )) break;
502 if (!IsWindow( hwnd
)) return -1;
503 if (!(dlgInfo
->flags
& DF_END
) && !IsDialogMessageW( hwnd
, &msg
))
505 TranslateMessage( &msg
);
506 DispatchMessageW( &msg
);
508 if (dlgInfo
->flags
& DF_END
) break;
511 if (dlgInfo
->flags
& DF_OWNERENABLED
) DIALOG_EnableOwner( owner
);
512 retval
= dlgInfo
->idResult
;
513 DestroyWindow( hwnd
);
517 /***********************************************************************
518 * DIALOG_ParseTemplate32
520 * Fill a DLG_TEMPLATE structure from the dialog template, and return
521 * a pointer to the first control.
523 static LPCSTR
DIALOG_ParseTemplate32( LPCSTR
template, DLG_TEMPLATE
* result
)
525 const WORD
*p
= (const WORD
*)template;
529 signature
= GET_WORD(p
); p
++;
530 dlgver
= GET_WORD(p
); p
++;
532 if (signature
== 1 && dlgver
== 0xffff) /* DIALOGEX resource */
534 result
->dialogEx
= TRUE
;
535 result
->helpId
= GET_DWORD(p
); p
+= 2;
536 result
->exStyle
= GET_DWORD(p
); p
+= 2;
537 result
->style
= GET_DWORD(p
); p
+= 2;
541 result
->style
= GET_DWORD(p
- 2);
542 result
->dialogEx
= FALSE
;
544 result
->exStyle
= GET_DWORD(p
); p
+= 2;
546 result
->nbItems
= GET_WORD(p
); p
++;
547 result
->x
= GET_WORD(p
); p
++;
548 result
->y
= GET_WORD(p
); p
++;
549 result
->cx
= GET_WORD(p
); p
++;
550 result
->cy
= GET_WORD(p
); p
++;
552 /* Get the menu name */
557 result
->menuName
= NULL
;
561 result
->menuName
= (LPCWSTR
)(UINT
)GET_WORD( p
+ 1 );
565 result
->menuName
= (LPCWSTR
)p
;
566 p
+= wcslen( result
->menuName
) + 1;
570 /* Get the class name */
575 result
->className
= DIALOG_CLASS_ATOMW
;
579 result
->className
= (LPCWSTR
)(UINT
)GET_WORD( p
+ 1 );
583 result
->className
= (LPCWSTR
)p
;
584 p
+= wcslen( result
->className
) + 1;
588 /* Get the window caption */
590 result
->caption
= (LPCWSTR
)p
;
591 p
+= wcslen( result
->caption
) + 1;
593 /* Get the font name */
595 result
->pointSize
= 0;
596 result
->weight
= FW_DONTCARE
;
597 result
->italic
= FALSE
;
598 result
->faceName
= NULL
;
600 if (result
->style
& DS_SETFONT
)
602 result
->pointSize
= GET_WORD(p
);
604 if (result
->dialogEx
)
606 result
->weight
= GET_WORD(p
); p
++;
607 result
->italic
= LOBYTE(GET_WORD(p
)); p
++;
609 result
->faceName
= (LPCWSTR
)p
;
610 p
+= wcslen( result
->faceName
) + 1;
613 /* First control is on dword boundary */
614 return (LPCSTR
)((((int)p
) + 3) & ~3);
617 /***********************************************************************
618 * DIALOG_CreateIndirect
619 * Creates a dialog box window
621 * modal = TRUE if we are called from a modal dialog box.
622 * (it's more compatible to do it here, as under Windows the owner
623 * is never disabled if the dialog fails because of an invalid template)
625 static HWND
DIALOG_CreateIndirect( HINSTANCE hInst
, LPCVOID dlgTemplate
,
626 HWND owner
, DLGPROC dlgProc
, LPARAM param
,
627 BOOL unicode
, BOOL modal
)
631 DLG_TEMPLATE
template;
632 DIALOGINFO
* dlgInfo
= NULL
;
633 DWORD units
= GetDialogBaseUnits();
634 BOOL ownerEnabled
= TRUE
;
638 UINT xBaseUnit
= LOWORD(units
);
639 UINT yBaseUnit
= HIWORD(units
);
641 /* Parse dialog template */
643 if (!dlgTemplate
) return 0;
644 dlgTemplate
= DIALOG_ParseTemplate32( dlgTemplate
, &template );
648 if (template.menuName
) hMenu
= LoadMenuW( hInst
, template.menuName
);
650 /* Create custom font if needed */
652 if (template.style
& DS_SETFONT
)
654 /* We convert the size to pixels and then make it -ve. This works
655 * for both +ve and -ve template.pointSize */
659 pixels
= MulDiv(template.pointSize
, GetDeviceCaps(dc
, LOGPIXELSY
), 72);
660 hUserFont
= CreateFontW( -pixels
, 0, 0, 0, template.weight
,
661 template.italic
, FALSE
, FALSE
, DEFAULT_CHARSET
, 0, 0,
662 PROOF_QUALITY
, FF_DONTCARE
,
667 HFONT hOldFont
= SelectObject( dc
, hUserFont
);
668 charSize
.cx
= GdiGetCharDimensions( dc
, NULL
, &charSize
.cy
);
671 xBaseUnit
= charSize
.cx
;
672 yBaseUnit
= charSize
.cy
;
674 SelectObject( dc
, hOldFont
);
677 TRACE("units = %d,%d\n", xBaseUnit
, yBaseUnit
);
680 /* Create dialog main window */
682 rect
.left
= rect
.top
= 0;
683 rect
.right
= MulDiv(template.cx
, xBaseUnit
, 4);
684 rect
.bottom
= MulDiv(template.cy
, yBaseUnit
, 8);
685 if (template.style
& WS_CHILD
)
686 template.style
&= ~(WS_CAPTION
|WS_SYSMENU
);
687 if (template.style
& DS_MODALFRAME
)
688 template.exStyle
|= WS_EX_DLGMODALFRAME
;
689 if (template.style
& DS_CONTROL
)
690 template.exStyle
|= WS_EX_CONTROLPARENT
;
691 AdjustWindowRectEx( &rect
, template.style
, (hMenu
!= 0), template.exStyle
);
692 rect
.right
-= rect
.left
;
693 rect
.bottom
-= rect
.top
;
695 if (template.x
== CW_USEDEFAULT16
)
697 rect
.left
= rect
.top
= CW_USEDEFAULT
;
701 if (template.style
& DS_CENTER
)
703 rect
.left
= (GetSystemMetrics(SM_CXSCREEN
) - rect
.right
) / 2;
704 rect
.top
= (GetSystemMetrics(SM_CYSCREEN
) - rect
.bottom
) / 2;
708 rect
.left
+= MulDiv(template.x
, xBaseUnit
, 4);
709 rect
.top
+= MulDiv(template.y
, yBaseUnit
, 8);
711 if ( !(template.style
& WS_CHILD
) )
715 if( !(template.style
& DS_ABSALIGN
) )
716 ClientToScreen( owner
, (POINT
*)&rect
);
718 /* try to fit it into the desktop */
720 if( (dX
= rect
.left
+ rect
.right
+ GetSystemMetrics(SM_CXDLGFRAME
)
721 - GetSystemMetrics(SM_CXSCREEN
)) > 0 ) rect
.left
-= dX
;
722 if( (dY
= rect
.top
+ rect
.bottom
+ GetSystemMetrics(SM_CYDLGFRAME
)
723 - GetSystemMetrics(SM_CYSCREEN
)) > 0 ) rect
.top
-= dY
;
724 if( rect
.left
< 0 ) rect
.left
= 0;
725 if( rect
.top
< 0 ) rect
.top
= 0;
731 ownerEnabled
= DIALOG_DisableOwner( owner
);
732 if (ownerEnabled
) flags
|= DF_OWNERENABLED
;
737 hwnd
= CreateWindowExW(template.exStyle
, template.className
, template.caption
,
738 template.style
& ~WS_VISIBLE
,
739 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
,
740 owner
, hMenu
, hInst
, NULL
);
744 LPSTR
class = (LPSTR
)template.className
;
745 LPSTR caption
= (LPSTR
)template.caption
;
749 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, template.className
, -1, NULL
, 0, NULL
, NULL
);
750 class = HeapAlloc( GetProcessHeap(), 0, len
);
751 WideCharToMultiByte( CP_ACP
, 0, template.className
, -1, class, len
, NULL
, NULL
);
755 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, template.caption
, -1, NULL
, 0, NULL
, NULL
);
756 caption
= HeapAlloc( GetProcessHeap(), 0, len
);
757 WideCharToMultiByte( CP_ACP
, 0, template.caption
, -1, caption
, len
, NULL
, NULL
);
759 hwnd
= CreateWindowExA(template.exStyle
, class, caption
,
760 template.style
& ~WS_VISIBLE
,
761 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
,
762 owner
, hMenu
, hInst
, NULL
);
763 if (HIWORD(class)) HeapFree( GetProcessHeap(), 0, class );
764 if (HIWORD(caption
)) HeapFree( GetProcessHeap(), 0, caption
);
769 if (hUserFont
) DeleteObject( hUserFont
);
770 if (hMenu
) DestroyMenu( hMenu
);
771 if (modal
&& (flags
& DF_OWNERENABLED
)) DIALOG_EnableOwner(owner
);
775 /* moved this from the top of the method to here as DIALOGINFO structure
776 will be valid only after WM_CREATE message has been handled in DefDlgProc
777 All the members of the structure get filled here using temp variables */
779 // dlgInfo = DIALOG_get_info( hwnd, TRUE );
781 if (!(dlgInfo
= HeapAlloc( GetProcessHeap(), 0, sizeof(*dlgInfo
) ))) return 0;
782 SETDLGINFO(hwnd
, dlgInfo
);
784 dlgInfo
->hwndFocus
= 0;
785 dlgInfo
->hUserFont
= hUserFont
;
786 dlgInfo
->hMenu
= hMenu
;
787 dlgInfo
->xBaseUnit
= xBaseUnit
;
788 dlgInfo
->yBaseUnit
= yBaseUnit
;
789 dlgInfo
->idResult
= 0;
790 dlgInfo
->flags
= flags
;
791 // dlgInfo->hDialogHeap = 0;
793 if (template.helpId
) SetWindowContextHelpId( hwnd
, template.helpId
);
795 if (unicode
) SetWindowLongPtrW( hwnd
, DWLP_DLGPROC
, (ULONG_PTR
)dlgProc
);
796 else SetWindowLongPtrA( hwnd
, DWLP_DLGPROC
, (ULONG_PTR
)dlgProc
);
798 if (dlgInfo
->hUserFont
)
799 SendMessageW( hwnd
, WM_SETFONT
, (WPARAM
)dlgInfo
->hUserFont
, 0 );
801 /* Create controls */
803 if (DIALOG_CreateControls32( hwnd
, dlgTemplate
, &template, hInst
, unicode
))
805 /* Send initialisation messages and set focus */
807 if (SendMessageW( hwnd
, WM_INITDIALOG
, (WPARAM
)dlgInfo
->hwndFocus
, param
) &&
808 ((~template.style
& DS_CONTROL
) || (template.style
& WS_VISIBLE
)))
810 /* By returning TRUE, app has requested a default focus assignment */
811 dlgInfo
->hwndFocus
= GetNextDlgTabItem( hwnd
, 0, FALSE
);
812 if( dlgInfo
->hwndFocus
)
813 SetFocus( dlgInfo
->hwndFocus
);
816 if (template.style
& WS_VISIBLE
&& !(GetWindowLongW( hwnd
, GWL_STYLE
) & WS_VISIBLE
))
818 ShowWindow( hwnd
, SW_SHOWNORMAL
); /* SW_SHOW doesn't always work */
822 if (modal
&& ownerEnabled
) DIALOG_EnableOwner(owner
);
823 if( IsWindow(hwnd
) ) DestroyWindow( hwnd
);
827 /***********************************************************************
830 * Set the focus to a control of the dialog, selecting the text if
831 * the control is an edit dialog.
833 static void DEFDLG_SetFocus( HWND hwndDlg
, HWND hwndCtrl
)
835 HWND hwndPrev
= GetFocus();
837 if (IsChild( hwndDlg
, hwndPrev
))
839 if (SendMessageW( hwndPrev
, WM_GETDLGCODE
, 0, 0 ) & DLGC_HASSETSEL
)
840 SendMessageW( hwndPrev
, EM_SETSEL
, -1, 0 );
842 if (SendMessageW( hwndCtrl
, WM_GETDLGCODE
, 0, 0 ) & DLGC_HASSETSEL
)
843 SendMessageW( hwndCtrl
, EM_SETSEL
, 0, -1 );
844 SetFocus( hwndCtrl
);
847 /***********************************************************************
850 static void DEFDLG_SaveFocus( HWND hwnd
)
853 HWND hwndFocus
= GetFocus();
855 if (!hwndFocus
|| !IsChild( hwnd
, hwndFocus
)) return;
856 if (!(infoPtr
= GETDLGINFO(hwnd
))) return;
857 infoPtr
->hwndFocus
= hwndFocus
;
858 /* Remove default button */
861 /***********************************************************************
862 * DEFDLG_RestoreFocus
864 static void DEFDLG_RestoreFocus( HWND hwnd
)
868 if (IsIconic( hwnd
)) return;
869 if (!(infoPtr
= GETDLGINFO(hwnd
))) return;
870 /* Don't set the focus back to controls if EndDialog is already called.*/
871 if (infoPtr
->flags
& DF_END
) return;
872 if (!IsWindow(infoPtr
->hwndFocus
) || infoPtr
->hwndFocus
== hwnd
) {
873 /* If no saved focus control exists, set focus to the first visible,
874 non-disabled, WS_TABSTOP control in the dialog */
875 infoPtr
->hwndFocus
= GetNextDlgTabItem( hwnd
, 0, FALSE
);
876 if (!IsWindow( infoPtr
->hwndFocus
)) return;
878 SetFocus( infoPtr
->hwndFocus
);
880 /* This used to set infoPtr->hwndFocus to NULL for no apparent reason,
881 sometimes losing focus when receiving WM_SETFOCUS messages. */
884 /***********************************************************************
885 * DEFDLG_FindDefButton
887 * Find the current default push-button.
889 static HWND
DEFDLG_FindDefButton( HWND hwndDlg
)
891 HWND hwndChild
, hwndTmp
;
893 hwndChild
= GetWindow( hwndDlg
, GW_CHILD
);
896 if (SendMessageW( hwndChild
, WM_GETDLGCODE
, 0, 0 ) & DLGC_DEFPUSHBUTTON
)
899 /* Recurse into WS_EX_CONTROLPARENT controls */
900 if (GetWindowLongW( hwndChild
, GWL_EXSTYLE
) & WS_EX_CONTROLPARENT
)
902 LONG dsStyle
= GetWindowLongW( hwndChild
, GWL_STYLE
);
903 if ((dsStyle
& WS_VISIBLE
) && !(dsStyle
& WS_DISABLED
) &&
904 (hwndTmp
= DEFDLG_FindDefButton(hwndChild
)) != NULL
)
907 hwndChild
= GetWindow( hwndChild
, GW_HWNDNEXT
);
912 /***********************************************************************
915 * Set the default button id.
917 static BOOL
DEFDLG_SetDefId( HWND hwndDlg
, DIALOGINFO
*dlgInfo
, WPARAM wParam
)
919 DWORD dlgcode
=0; /* initialize just to avoid a warning */
920 HWND hwndOld
, hwndNew
= GetDlgItem(hwndDlg
, wParam
);
921 INT old_id
= dlgInfo
->idResult
;
923 dlgInfo
->idResult
= wParam
;
925 !((dlgcode
=SendMessageW(hwndNew
, WM_GETDLGCODE
, 0, 0 ))
926 & (DLGC_UNDEFPUSHBUTTON
| DLGC_BUTTON
)))
927 return FALSE
; /* Destination is not a push button */
929 /* Make sure the old default control is a valid push button ID */
930 hwndOld
= GetDlgItem( hwndDlg
, old_id
);
931 if (!hwndOld
|| !(SendMessageW( hwndOld
, WM_GETDLGCODE
, 0, 0) & DLGC_DEFPUSHBUTTON
))
932 hwndOld
= DEFDLG_FindDefButton( hwndDlg
);
933 if (hwndOld
&& hwndOld
!= hwndNew
)
934 SendMessageW( hwndOld
, BM_SETSTYLE
, BS_PUSHBUTTON
, TRUE
);
938 if(dlgcode
& DLGC_UNDEFPUSHBUTTON
)
939 SendMessageW( hwndNew
, BM_SETSTYLE
, BS_DEFPUSHBUTTON
, TRUE
);
944 /***********************************************************************
945 * DEFDLG_SetDefButton
947 * Set the new default button to be hwndNew.
949 static BOOL
DEFDLG_SetDefButton( HWND hwndDlg
, DIALOGINFO
*dlgInfo
, HWND hwndNew
)
951 DWORD dlgcode
=0; /* initialize just to avoid a warning */
952 HWND hwndOld
= GetDlgItem( hwndDlg
, dlgInfo
->idResult
);
955 !((dlgcode
=SendMessageW(hwndNew
, WM_GETDLGCODE
, 0, 0 ))
956 & (DLGC_UNDEFPUSHBUTTON
| DLGC_DEFPUSHBUTTON
)))
959 * Need to draw only default push button rectangle.
960 * Since the next control is not a push button, need to draw the push
961 * button rectangle for the default control.
964 dlgcode
= SendMessageW(hwndNew
, WM_GETDLGCODE
, 0, 0 );
967 /* Make sure the old default control is a valid push button ID */
968 if (!hwndOld
|| !(SendMessageW( hwndOld
, WM_GETDLGCODE
, 0, 0) & DLGC_DEFPUSHBUTTON
))
969 hwndOld
= DEFDLG_FindDefButton( hwndDlg
);
970 if (hwndOld
&& hwndOld
!= hwndNew
)
971 SendMessageW( hwndOld
, BM_SETSTYLE
, BS_PUSHBUTTON
, TRUE
);
975 if(dlgcode
& DLGC_UNDEFPUSHBUTTON
)
976 SendMessageW( hwndNew
, BM_SETSTYLE
, BS_DEFPUSHBUTTON
, TRUE
);
981 /***********************************************************************
984 * Implementation of DefDlgProc(). Only handle messages that need special
985 * handling for dialogs.
987 static LRESULT
DEFDLG_Proc( HWND hwnd
, UINT msg
, WPARAM wParam
,
988 LPARAM lParam
, DIALOGINFO
*dlgInfo
)
994 HBRUSH brush
= (HBRUSH
)SendMessageW( hwnd
, WM_CTLCOLORDLG
, wParam
, (LPARAM
)hwnd
);
995 if (!brush
) brush
= (HBRUSH
)DefWindowProcW( hwnd
, WM_CTLCOLORDLG
, wParam
, (LPARAM
)hwnd
);
999 HDC hdc
= (HDC
)wParam
;
1000 GetClientRect( hwnd
, &rect
);
1001 DPtoLP( hdc
, (LPPOINT
)&rect
, 2 );
1002 FillRect( hdc
, &rect
, brush
);
1007 if ((dlgInfo
= (DIALOGINFO
*)SetWindowLongPtrW( hwnd
, DWLP_ROS_DIALOGINFO
, 0 )))
1009 /* Free dialog heap (if created) */
1010 /*if (dlgInfo->hDialogHeap)
1012 GlobalUnlock16(dlgInfo->hDialogHeap);
1013 GlobalFree16(dlgInfo->hDialogHeap);
1015 if (dlgInfo
->hUserFont
) DeleteObject( dlgInfo
->hUserFont
);
1016 if (dlgInfo
->hMenu
) DestroyMenu( dlgInfo
->hMenu
);
1017 HeapFree( GetProcessHeap(), 0, dlgInfo
);
1019 /* Window clean-up */
1020 return DefWindowProcA( hwnd
, msg
, wParam
, lParam
);
1023 if (!wParam
) DEFDLG_SaveFocus( hwnd
);
1024 return DefWindowProcA( hwnd
, msg
, wParam
, lParam
);
1027 if (wParam
) DEFDLG_RestoreFocus( hwnd
);
1028 else DEFDLG_SaveFocus( hwnd
);
1032 DEFDLG_RestoreFocus( hwnd
);
1036 if (dlgInfo
&& !(dlgInfo
->flags
& DF_END
))
1037 DEFDLG_SetDefId( hwnd
, dlgInfo
, wParam
);
1041 if (dlgInfo
&& !(dlgInfo
->flags
& DF_END
))
1044 if (dlgInfo
->idResult
)
1045 return MAKELONG( dlgInfo
->idResult
, DC_HASDEFID
);
1046 if ((hwndDefId
= DEFDLG_FindDefButton( hwnd
)))
1047 return MAKELONG( GetDlgCtrlID( hwndDefId
), DC_HASDEFID
);
1054 HWND hwndDest
= (HWND
)wParam
;
1056 hwndDest
= GetNextDlgTabItem(hwnd
, GetFocus(), wParam
);
1057 if (hwndDest
) DEFDLG_SetFocus( hwnd
, hwndDest
);
1058 DEFDLG_SetDefButton( hwnd
, dlgInfo
, hwndDest
);
1062 case WM_ENTERMENULOOP
:
1063 case WM_LBUTTONDOWN
:
1064 case WM_NCLBUTTONDOWN
:
1066 HWND hwndFocus
= GetFocus();
1069 /* always make combo box hide its listbox control */
1070 if (!SendMessageW( hwndFocus
, CB_SHOWDROPDOWN
, FALSE
, 0 ))
1071 SendMessageW( GetParent(hwndFocus
), CB_SHOWDROPDOWN
, FALSE
, 0 );
1074 return DefWindowProcA( hwnd
, msg
, wParam
, lParam
);
1077 return dlgInfo
? (LRESULT
)dlgInfo
->hUserFont
: 0;
1080 PostMessageA( hwnd
, WM_COMMAND
, MAKEWPARAM(IDCANCEL
, BN_CLICKED
),
1081 (LPARAM
)GetDlgItem( hwnd
, IDCANCEL
) );
1087 /***********************************************************************
1090 static LRESULT
DEFDLG_Epilog(HWND hwnd
, UINT msg
, BOOL fResult
)
1093 // TODO: where's wine's WM_CTLCOLOR from?
1094 if ((msg
>= WM_CTLCOLORMSGBOX
&& msg
<= WM_CTLCOLORSTATIC
) ||
1095 msg
== WM_CTLCOLOR
|| msg
== WM_COMPAREITEM
||
1096 msg
== WM_VKEYTOITEM
|| msg
== WM_CHARTOITEM
||
1097 msg
== WM_QUERYDRAGICON
|| msg
== WM_INITDIALOG
)
1100 return GetWindowLongPtrW( hwnd
, DWLP_MSGRESULT
);
1103 /***********************************************************************
1104 * DIALOG_GetNextTabItem
1106 * Helper for GetNextDlgTabItem
1108 static HWND
DIALOG_GetNextTabItem( HWND hwndMain
, HWND hwndDlg
, HWND hwndCtrl
, BOOL fPrevious
)
1112 UINT wndSearch
= fPrevious
? GW_HWNDPREV
: GW_HWNDNEXT
;
1114 HWND hChildFirst
= 0;
1118 hChildFirst
= GetWindow(hwndDlg
,GW_CHILD
);
1119 if(fPrevious
) hChildFirst
= GetWindow(hChildFirst
,GW_HWNDLAST
);
1121 else if (IsChild( hwndMain
, hwndCtrl
))
1123 hChildFirst
= GetWindow(hwndCtrl
,wndSearch
);
1126 if(GetParent(hwndCtrl
) != hwndMain
)
1127 /* i.e. if we are not at the top level of the recursion */
1128 hChildFirst
= GetWindow(GetParent(hwndCtrl
),wndSearch
);
1130 hChildFirst
= GetWindow(hwndCtrl
, fPrevious
? GW_HWNDLAST
: GW_HWNDFIRST
);
1136 dsStyle
= GetWindowLongA(hChildFirst
,GWL_STYLE
);
1137 exStyle
= GetWindowLongA(hChildFirst
,GWL_EXSTYLE
);
1138 if( (exStyle
& WS_EX_CONTROLPARENT
) && (dsStyle
& WS_VISIBLE
) && !(dsStyle
& WS_DISABLED
))
1141 retWnd
= DIALOG_GetNextTabItem(hwndMain
,hChildFirst
,NULL
,fPrevious
);
1142 if (retWnd
) return (retWnd
);
1144 else if( (dsStyle
& WS_TABSTOP
) && (dsStyle
& WS_VISIBLE
) && !(dsStyle
& WS_DISABLED
))
1146 return (hChildFirst
);
1148 hChildFirst
= GetWindow(hChildFirst
,wndSearch
);
1152 HWND hParent
= GetParent(hwndCtrl
);
1155 if(hParent
== hwndMain
) break;
1156 retWnd
= DIALOG_GetNextTabItem(hwndMain
,GetParent(hParent
),hParent
,fPrevious
);
1158 hParent
= GetParent(hParent
);
1161 retWnd
= DIALOG_GetNextTabItem(hwndMain
,hwndMain
,NULL
,fPrevious
);
1163 return retWnd
? retWnd
: hwndCtrl
;
1167 /**********************************************************************
1168 * DIALOG_DlgDirListW
1170 * Helper function for DlgDirList*W
1172 static INT
DIALOG_DlgDirListW( HWND hDlg
, LPWSTR spec
, INT idLBox
,
1173 INT idStatic
, UINT attrib
, BOOL combo
)
1176 LPWSTR orig_spec
= spec
;
1177 WCHAR any
[] = {'*','.','*',0};
1179 #define SENDMSG(msg,wparam,lparam) \
1180 ((attrib & DDL_POSTMSGS) ? PostMessageW( hwnd, msg, wparam, lparam ) \
1181 : SendMessageW( hwnd, msg, wparam, lparam ))
1183 // DPRINT("%p '%s' %d %d %04x\n",
1184 // hDlg, spec ? spec : "NULL", idLBox, idStatic, attrib );
1186 /* If the path exists and is a directory, chdir to it */
1187 if (!spec
|| !spec
[0] || SetCurrentDirectoryW( spec
)) spec
= any
;
1192 if ((p2
= strrchrW( p
, '\\' ))) p
= p2
;
1193 if ((p2
= strrchrW( p
, '/' ))) p
= p2
;
1198 if (!SetCurrentDirectoryW( spec
))
1200 *p
= sep
; /* Restore the original spec */
1207 DPRINT( "mask=%s\n", spec
);
1209 if (idLBox
&& ((hwnd
= GetDlgItem( hDlg
, idLBox
)) != 0))
1211 SENDMSG( combo
? CB_RESETCONTENT
: LB_RESETCONTENT
, 0, 0 );
1212 if (attrib
& DDL_DIRECTORY
)
1214 if (!(attrib
& DDL_EXCLUSIVE
))
1216 if (SENDMSG( combo
? CB_DIR
: LB_DIR
,
1217 attrib
& ~(DDL_DIRECTORY
| DDL_DRIVES
),
1218 (LPARAM
)spec
) == LB_ERR
)
1221 if (SENDMSG( combo
? CB_DIR
: LB_DIR
,
1222 (attrib
& (DDL_DIRECTORY
| DDL_DRIVES
)) | DDL_EXCLUSIVE
,
1223 (LPARAM
)any
) == LB_ERR
)
1228 if (SENDMSG( combo
? CB_DIR
: LB_DIR
, attrib
,
1229 (LPARAM
)spec
) == LB_ERR
)
1234 if (idStatic
&& ((hwnd
= GetDlgItem( hDlg
, idStatic
)) != 0))
1236 WCHAR temp
[MAX_PATH
];
1237 GetCurrentDirectoryW( sizeof(temp
)/sizeof(WCHAR
), temp
);
1239 /* Can't use PostMessage() here, because the string is on the stack */
1240 SetDlgItemTextW( hDlg
, idStatic
, temp
);
1243 if (orig_spec
&& (spec
!= orig_spec
))
1245 /* Update the original file spec */
1247 while ((*orig_spec
++ = *p
++));
1254 /**********************************************************************
1255 * DIALOG_DlgDirListA
1257 * Helper function for DlgDirList*A
1259 static INT
DIALOG_DlgDirListA( HWND hDlg
, LPSTR spec
, INT idLBox
,
1260 INT idStatic
, UINT attrib
, BOOL combo
)
1264 INT ret
, len
= MultiByteToWideChar( CP_ACP
, 0, spec
, -1, NULL
, 0 );
1265 LPWSTR specW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1266 MultiByteToWideChar( CP_ACP
, 0, spec
, -1, specW
, len
);
1267 ret
= DIALOG_DlgDirListW( hDlg
, specW
, idLBox
, idStatic
, attrib
, combo
);
1268 WideCharToMultiByte( CP_ACP
, 0, specW
, -1, spec
, 0x7fffffff, NULL
, NULL
);
1269 HeapFree( GetProcessHeap(), 0, specW
);
1272 return DIALOG_DlgDirListW( hDlg
, NULL
, idLBox
, idStatic
, attrib
, combo
);
1275 /**********************************************************************
1276 * DIALOG_DlgDirSelect
1278 * Helper function for DlgDirSelect*
1280 static BOOL
DIALOG_DlgDirSelect( HWND hwnd
, LPWSTR str
, INT len
,
1281 INT id
, BOOL unicode
, BOOL combo
)
1283 WCHAR
*buffer
, *ptr
;
1286 HWND listbox
= GetDlgItem( hwnd
, id
);
1288 DPRINT("%p '%s' %d\n", hwnd
, str
, id
);
1289 if (!listbox
) return FALSE
;
1291 item
= SendMessageW(listbox
, combo
? CB_GETCURSEL
: LB_GETCURSEL
, 0, 0 );
1292 if (item
== LB_ERR
) return FALSE
;
1293 size
= SendMessageW(listbox
, combo
? CB_GETLBTEXTLEN
: LB_GETTEXTLEN
, 0, 0 );
1294 if (size
== LB_ERR
) return FALSE
;
1296 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
+1 ))) return FALSE
;
1298 SendMessageW( listbox
, combo
? CB_GETLBTEXT
: LB_GETTEXT
, item
, (LPARAM
)buffer
);
1300 if ((ret
= (buffer
[0] == '['))) /* drive or directory */
1302 if (buffer
[1] == '-') /* drive */
1310 buffer
[strlenW(buffer
)-1] = '\\';
1318 if (len
> 0 && !WideCharToMultiByte( CP_ACP
, 0, ptr
, -1, (LPSTR
)str
, len
, 0, 0 ))
1319 ((LPSTR
)str
)[len
-1] = 0;
1321 else lstrcpynW( str
, ptr
, len
);
1322 HeapFree( GetProcessHeap(), 0, buffer
);
1323 DPRINT("Returning %d '%s'\n", ret
, str
);
1327 /***********************************************************************
1328 * GetDlgItemEnumProc
1330 * Callback for GetDlgItem
1332 BOOL CALLBACK
GetDlgItemEnumProc (HWND hwnd
, LPARAM lParam
)
1334 GETDLGITEMINFO
* info
= (GETDLGITEMINFO
*)lParam
;
1335 if(info
->nIDDlgItem
== GetWindowLongW( hwnd
, GWL_ID
))
1337 info
->control
= hwnd
;
1344 /* FUNCTIONS *****************************************************************/
1351 CreateDialogIndirectParamAorW(
1352 HINSTANCE hInstance
,
1353 LPCDLGTEMPLATE lpTemplate
,
1355 DLGPROC lpDialogFunc
,
1360 * This function might be obsolete since I don't think it is exported by NT
1361 * Also wine has one more parameter identifying weather it should call
1362 * the function with unicode or not
1364 return DIALOG_CreateIndirect( hInstance
, lpTemplate
, hWndParent
, lpDialogFunc
, lParamInit
, !Flags
, FALSE
);
1373 CreateDialogIndirectParamA(
1374 HINSTANCE hInstance
,
1375 LPCDLGTEMPLATE lpTemplate
,
1377 DLGPROC lpDialogFunc
,
1380 return CreateDialogIndirectParamAorW( hInstance
, lpTemplate
, hWndParent
, lpDialogFunc
, lParamInit
, 2 );
1389 CreateDialogIndirectParamW(
1390 HINSTANCE hInstance
,
1391 LPCDLGTEMPLATE lpTemplate
,
1393 DLGPROC lpDialogFunc
,
1396 return CreateDialogIndirectParamAorW( hInstance
, lpTemplate
, hWndParent
, lpDialogFunc
, lParamInit
, 0);
1406 HINSTANCE hInstance
,
1407 LPCSTR lpTemplateName
,
1409 DLGPROC lpDialogFunc
,
1415 if (!(hrsrc
= FindResourceA( hInstance
, lpTemplateName
, (LPCSTR
)RT_DIALOG
))) return 0;
1416 if (!(ptr
= (LPCDLGTEMPLATE
)LoadResource(hInstance
, hrsrc
))) return 0;
1417 return CreateDialogIndirectParamA( hInstance
, ptr
, hWndParent
, lpDialogFunc
, dwInitParam
);
1427 HINSTANCE hInstance
,
1428 LPCWSTR lpTemplateName
,
1430 DLGPROC lpDialogFunc
,
1436 if (!(hrsrc
= FindResourceW( hInstance
, lpTemplateName
, (LPCWSTR
)RT_DIALOG
))) return 0;
1437 if (!(ptr
= (LPCDLGTEMPLATE
)LoadResource(hInstance
, hrsrc
))) return 0;
1438 return CreateDialogIndirectParamW( hInstance
, ptr
, hWndParent
, lpDialogFunc
, dwInitParam
);
1454 BOOL result
= FALSE
;
1455 DIALOGINFO
* dlgInfo
;
1457 /* if there's no dialog info property then call default windows proc?? */
1458 if (!(dlgInfo
= GETDLGINFO(hDlg
)))
1459 return DefWindowProcA( hDlg
, Msg
, wParam
, lParam
);
1461 SetWindowLongPtrW( hDlg
, DWLP_MSGRESULT
, 0 );
1463 if ((dlgproc
= (WNDPROC
)GetWindowLongPtrW( hDlg
, DWLP_DLGPROC
)))
1465 /* Call dialog procedure */
1466 result
= CallWindowProcA( dlgproc
, hDlg
, Msg
, wParam
, lParam
);
1469 if (!result
&& IsWindow(hDlg
))
1471 /* callback didn't process this message */
1485 case WM_ENTERMENULOOP
:
1486 case WM_LBUTTONDOWN
:
1487 case WM_NCLBUTTONDOWN
:
1488 return DEFDLG_Proc( hDlg
, Msg
, wParam
, lParam
, dlgInfo
);
1491 case WM_COMPAREITEM
:
1496 return DefWindowProcA( hDlg
, Msg
, wParam
, lParam
);
1499 return DEFDLG_Epilog(hDlg
, Msg
, result
);
1515 BOOL result
= FALSE
;
1516 DIALOGINFO
* dlgInfo
;
1518 /* if there's no dialog info property then call default windows proc?? */
1519 if (!(dlgInfo
= GETDLGINFO(hDlg
)))
1520 return DefWindowProcW( hDlg
, Msg
, wParam
, lParam
);
1522 SetWindowLongPtrW( hDlg
, DWLP_MSGRESULT
, 0 );
1524 if ((dlgproc
= (WNDPROC
)GetWindowLongPtrW( hDlg
, DWLP_DLGPROC
)))
1526 /* Call dialog procedure */
1527 result
= CallWindowProcW( dlgproc
, hDlg
, Msg
, wParam
, lParam
);
1530 if (!result
&& IsWindow(hDlg
))
1532 /* callback didn't process this message */
1546 case WM_ENTERMENULOOP
:
1547 case WM_LBUTTONDOWN
:
1548 case WM_NCLBUTTONDOWN
:
1549 return DEFDLG_Proc( hDlg
, Msg
, wParam
, lParam
, dlgInfo
);
1552 case WM_COMPAREITEM
:
1557 return DefWindowProcW( hDlg
, Msg
, wParam
, lParam
);
1560 return DEFDLG_Epilog(hDlg
, Msg
, result
);
1569 DialogBoxIndirectParamAorW(
1570 HINSTANCE hInstance
,
1571 LPCDLGTEMPLATE hDialogTemplate
,
1573 DLGPROC lpDialogFunc
,
1578 * This function might be obsolete since I don't think it is exported by NT
1579 * Also wine has one more parameter identifying weather it should call
1580 * the function with unicode or not
1582 HWND hWnd
= DIALOG_CreateIndirect( hInstance
, hDialogTemplate
, hWndParent
, lpDialogFunc
, dwInitParam
, !Flags
, TRUE
);
1583 if (hWnd
) return DIALOG_DoDialogBox( hWnd
, hWndParent
);
1593 DialogBoxIndirectParamA(
1594 HINSTANCE hInstance
,
1595 LPCDLGTEMPLATE hDialogTemplate
,
1597 DLGPROC lpDialogFunc
,
1600 return DialogBoxIndirectParamAorW( hInstance
, hDialogTemplate
, hWndParent
, lpDialogFunc
, dwInitParam
, 2);
1609 DialogBoxIndirectParamW(
1610 HINSTANCE hInstance
,
1611 LPCDLGTEMPLATE hDialogTemplate
,
1613 DLGPROC lpDialogFunc
,
1616 return DialogBoxIndirectParamAorW( hInstance
, hDialogTemplate
, hWndParent
, lpDialogFunc
, dwInitParam
, 0);
1626 HINSTANCE hInstance
,
1627 LPCSTR lpTemplateName
,
1629 DLGPROC lpDialogFunc
,
1636 if (!(hrsrc
= FindResourceA( hInstance
, lpTemplateName
, (LPCSTR
)RT_DIALOG
))) return 0;
1637 if (!(ptr
= (LPCDLGTEMPLATE
)LoadResource(hInstance
, hrsrc
))) return 0;
1638 hwnd
= DIALOG_CreateIndirect(hInstance
, ptr
, hWndParent
, lpDialogFunc
, dwInitParam
, FALSE
, TRUE
);
1639 if (hwnd
) return DIALOG_DoDialogBox(hwnd
, hWndParent
);
1650 HINSTANCE hInstance
,
1651 LPCWSTR lpTemplateName
,
1653 DLGPROC lpDialogFunc
,
1660 if (!(hrsrc
= FindResourceW( hInstance
, lpTemplateName
, (LPCWSTR
)RT_DIALOG
))) return 0;
1661 if (!(ptr
= (LPCDLGTEMPLATE
)LoadResource(hInstance
, hrsrc
))) return 0;
1662 hwnd
= DIALOG_CreateIndirect(hInstance
, ptr
, hWndParent
, lpDialogFunc
, dwInitParam
, TRUE
, TRUE
);
1663 if (hwnd
) return DIALOG_DoDialogBox(hwnd
, hWndParent
);
1680 return DIALOG_DlgDirListA( hDlg
, lpPathSpec
, nIDListBox
, nIDStaticPath
, uFileType
, FALSE
);
1689 DlgDirListComboBoxA(
1696 return DIALOG_DlgDirListA( hDlg
, lpPathSpec
, nIDComboBox
, nIDStaticPath
, uFiletype
, TRUE
);
1705 DlgDirListComboBoxW(
1712 return DIALOG_DlgDirListW( hDlg
, lpPathSpec
, nIDComboBox
, nIDStaticPath
, uFiletype
, TRUE
);
1728 return DIALOG_DlgDirListW( hDlg
, lpPathSpec
, nIDListBox
, nIDStaticPath
, uFileType
, FALSE
);
1737 DlgDirSelectComboBoxExA(
1743 return DIALOG_DlgDirSelect( hDlg
, (LPWSTR
)lpString
, nCount
, nIDComboBox
, FALSE
, TRUE
);
1752 DlgDirSelectComboBoxExW(
1758 return DIALOG_DlgDirSelect( hDlg
, (LPWSTR
)lpString
, nCount
, nIDComboBox
, TRUE
, TRUE
);
1773 return DIALOG_DlgDirSelect( hDlg
, (LPWSTR
)lpString
, nCount
, nIDListBox
, FALSE
, FALSE
);
1788 return DIALOG_DlgDirSelect( hDlg
, lpString
, nCount
, nIDListBox
, TRUE
, FALSE
);
1801 BOOL wasEnabled
= TRUE
;
1802 DIALOGINFO
* dlgInfo
;
1805 if (!(dlgInfo
= GETDLGINFO(hDlg
))) return FALSE
;
1807 dlgInfo
->idResult
= nResult
;
1808 dlgInfo
->flags
|= DF_END
;
1809 wasEnabled
= (dlgInfo
->flags
& DF_OWNERENABLED
);
1811 if (wasEnabled
&& (owner
= GetWindow( hDlg
, GW_OWNER
)))
1812 DIALOG_EnableOwner( owner
);
1814 /* Windows sets the focus to the dialog itself in EndDialog */
1816 if (IsChild(hDlg
, GetFocus()))
1819 /* Don't have to send a ShowWindow(SW_HIDE), just do
1820 SetWindowPos with SWP_HIDEWINDOW as done in Windows */
1822 SetWindowPos(hDlg
, NULL
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
1823 | SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_HIDEWINDOW
);
1825 if (hDlg
== GetActiveWindow()) WinPosActivateOtherWindow( hDlg
);
1827 /* unblock dialog loop */
1828 PostMessageA(hDlg
, WM_NULL
, 0, 0);
1838 GetDialogBaseUnits(VOID
)
1847 if ((hdc
= GetDC(0)))
1849 size
.cx
= GdiGetCharDimensions( hdc
, NULL
, &size
.cy
);
1850 if (size
.cx
) units
= MAKELONG( size
.cx
, size
.cy
);
1851 ReleaseDC( 0, hdc
);
1866 return GetWindowLongPtrW( hwndCtl
, GWLP_ID
);
1879 GETDLGITEMINFO info
;
1880 info
.nIDDlgItem
= nIDDlgItem
;
1882 if(hDlg
&& !EnumChildWindows(hDlg
, (WNDENUMPROC
)&GetDlgItemEnumProc
, (LPARAM
)&info
))
1883 return info
.control
;
1904 if (lpTranslated
) *lpTranslated
= FALSE
;
1905 if (!SendDlgItemMessageA(hDlg
, nIDDlgItem
, WM_GETTEXT
, sizeof(str
), (LPARAM
)str
))
1909 result
= strtol( str
, &endptr
, 10 );
1910 if (!endptr
|| (endptr
== str
)) /* Conversion was unsuccessful */
1913 if (((result
== 0) || (result
== 0xFFFFFFFF))/* && (errno == ERANGE) */)
1918 result
= strtoul( str
, &endptr
, 10 );
1919 if (!endptr
|| (endptr
== str
)) /* Conversion was unsuccessful */
1922 if ((result
== 0xFFFFFFFF)/* && (errno == ERANGE) */) return 0;
1924 if (lpTranslated
) *lpTranslated
= TRUE
;
1925 return (UINT
)result
;
1940 if (lpString
&& (lpString
> 0)) lpString
[0] = '\0';
1941 return (UINT
)SendDlgItemMessageA( hDlg
, nIDDlgItem
, WM_GETTEXT
, nMaxCount
, (LPARAM
)lpString
);
1956 if (lpString
&& (lpString
> 0)) lpString
[0] = '\0';
1957 return (UINT
)SendDlgItemMessageW( hDlg
, nIDDlgItem
, WM_GETTEXT
, nMaxCount
, (LPARAM
)lpString
);
1965 GetNextDlgGroupItem(
1970 HWND hwnd
, hwndNext
, retvalue
, hwndLastGroup
= 0;
1972 BOOL fSkipping
=FALSE
;
1974 if (hDlg
== hCtl
) hCtl
= NULL
;
1975 if (!hCtl
&& bPrevious
) return 0;
1977 /* if the hwndCtrl is the child of the control in the hwndDlg,
1978 * then the hwndDlg has to be the parent of the hwndCtrl */
1982 if (!IsChild (hDlg
, hCtl
)) return 0;
1983 /* Make sure hwndCtrl is a top-level child */
1988 /* No ctrl specified -> start from the beginning */
1989 if (!(hCtl
= GetWindow( hDlg
, GW_CHILD
))) return 0;
1990 /* MSDN is wrong. fPrevious does not result in the last child */
1992 /* No ctrl specified -> start from the beginning */
1993 if (!(hCtl
= GetWindow( hDlg
, GW_CHILD
))) return 0;
1995 /* MSDN is wrong. fPrevious does not result in the last child */
1997 /* Maybe that first one is valid. If so then we don't want to skip it*/
1998 if ((GetWindowLongW( hCtl
, GWL_STYLE
) & (WS_VISIBLE
|WS_DISABLED
)) == WS_VISIBLE
)
2005 /* Always go forward around the group and list of controls; for the
2006 * previous control keep track; for the next break when you find one
2010 while (hwndNext
= GetWindow (hwnd
, GW_HWNDNEXT
),
2015 /* Climb out until there is a next sibling of the ancestor or we
2016 * reach the top (in which case we loop back to the start)
2018 if (hDlg
== GetParent (hwnd
))
2020 /* Wrap around to the beginning of the list, within the same
2021 * group. (Once only)
2023 if (fLooped
) goto end
;
2025 hwndNext
= GetWindow (hDlg
, GW_CHILD
);
2029 hwnd
= GetParent (hwnd
);
2030 hwndNext
= GetWindow (hwnd
, GW_HWNDNEXT
);
2035 /* Wander down the leading edge of controlparents */
2036 while ( (GetWindowLongW (hwnd
, GWL_EXSTYLE
) & WS_EX_CONTROLPARENT
) &&
2037 ((GetWindowLongW (hwnd
, GWL_STYLE
) & (WS_VISIBLE
| WS_DISABLED
)) == WS_VISIBLE
) &&
2038 (hwndNext
= GetWindow (hwnd
, GW_CHILD
)))
2040 /* Question. If the control is a control parent but either has no
2041 * children or is not visible/enabled then if it has a WS_GROUP does
2042 * it count? For that matter does it count anyway?
2043 * I believe it doesn't count.
2046 if ((GetWindowLongW (hwnd
, GWL_STYLE
) & WS_GROUP
))
2048 hwndLastGroup
= hwnd
;
2051 /* Look for the beginning of the group */
2058 if (!fSkipping
) break;
2059 if (hwndLastGroup
== hwnd
) break;
2060 hwnd
= hwndLastGroup
;
2066 (GetWindowLongW (hwnd
, GWL_STYLE
) & (WS_VISIBLE
|WS_DISABLED
)) ==
2070 if (!bPrevious
) break;
2088 /* Undocumented but tested under Win2000 and WinME */
2089 if (hDlg
== hCtl
) hCtl
= NULL
;
2091 /* Contrary to MSDN documentation, tested under Win2000 and WinME
2092 * NB GetLastError returns whatever was set before the function was
2095 if (!hCtl
&& bPrevious
) return 0;
2097 return DIALOG_GetNextTabItem(hDlg
, hDlg
, hCtl
, bPrevious
);
2108 return IsDialogMessageW(hDlg
, lpMsg
);
2112 /***********************************************************************
2113 * DIALOG_FixOneChildOnChangeFocus
2115 * Callback helper for DIALOG_FixChildrenOnChangeFocus
2118 static BOOL CALLBACK
DIALOG_FixOneChildOnChangeFocus (HWND hwndChild
,
2121 /* If a default pushbutton then no longer default */
2122 if (DLGC_DEFPUSHBUTTON
& SendMessageW (hwndChild
, WM_GETDLGCODE
, 0, 0))
2123 SendMessageW (hwndChild
, BM_SETSTYLE
, BS_PUSHBUTTON
, TRUE
);
2127 /***********************************************************************
2128 * DIALOG_FixChildrenOnChangeFocus
2130 * Following the change of focus that occurs for example after handling
2131 * a WM_KEYDOWN VK_TAB in IsDialogMessage, some tidying of the dialog's
2132 * children may be required.
2134 static void DIALOG_FixChildrenOnChangeFocus (HWND hwndDlg
, HWND hwndNext
)
2136 INT dlgcode_next
= SendMessageW (hwndNext
, WM_GETDLGCODE
, 0, 0);
2137 /* INT dlgcode_dlg = SendMessageW (hwndDlg, WM_GETDLGCODE, 0, 0); */
2138 /* Windows does ask for this. I don't know why yet */
2140 EnumChildWindows (hwndDlg
, DIALOG_FixOneChildOnChangeFocus
, 0);
2142 /* If the button that is getting the focus WAS flagged as the default
2143 * pushbutton then ask the dialog what it thinks the default is and
2144 * set that in the default style.
2146 if (dlgcode_next
& DLGC_DEFPUSHBUTTON
)
2148 DWORD def_id
= SendMessageW (hwndDlg
, DM_GETDEFID
, 0, 0);
2149 if (HIWORD(def_id
) == DC_HASDEFID
)
2152 def_id
= LOWORD(def_id
);
2153 hwndDef
= GetDlgItem (hwndDlg
, def_id
);
2156 INT dlgcode_def
= SendMessageW (hwndDef
, WM_GETDLGCODE
, 0, 0);
2157 /* I know that if it is a button then it should already be a
2158 * UNDEFPUSHBUTTON, since we have just told the buttons to
2159 * change style. But maybe they ignored our request
2161 if ((dlgcode_def
& DLGC_BUTTON
) &&
2162 (dlgcode_def
& DLGC_UNDEFPUSHBUTTON
))
2164 SendMessageW (hwndDef
, BM_SETSTYLE
, BS_DEFPUSHBUTTON
, TRUE
);
2169 else if ((dlgcode_next
& DLGC_BUTTON
) && (dlgcode_next
& DLGC_UNDEFPUSHBUTTON
))
2171 SendMessageW (hwndNext
, BM_SETSTYLE
, BS_DEFPUSHBUTTON
, TRUE
);
2172 /* I wonder why it doesn't send a DM_SETDEFID */
2188 if (CallMsgFilterW( lpMsg
, MSGF_DIALOGBOX
)) return TRUE
;
2190 if ((hDlg
!= lpMsg
->hwnd
) && !IsChild( hDlg
, lpMsg
->hwnd
)) return FALSE
;
2192 if (hDlg
== GetDesktopWindow()) return FALSE
;
2194 hDlg
= DIALOG_FindMsgDestination(hDlg
);
2196 switch(lpMsg
->message
)
2199 dlgCode
= SendMessageW( lpMsg
->hwnd
, WM_GETDLGCODE
, lpMsg
->wParam
, (LPARAM
)lpMsg
);
2200 if (dlgCode
& DLGC_WANTMESSAGE
) break;
2202 switch(lpMsg
->wParam
)
2205 if (!(dlgCode
& DLGC_WANTTAB
))
2207 /* I am not sure under which circumstances the TAB is handled
2208 * each way. All I do know is that it does not always simply
2209 * send WM_NEXTDLGCTL. (Personally I have never yet seen it
2210 * do so but I presume someone has)
2212 if (GETDLGINFO(hDlg
))
2213 SendMessageW( hDlg
, WM_NEXTDLGCTL
, (GetKeyState(VK_SHIFT
) & 0x8000), 0 );
2216 /* It would appear that GetNextDlgTabItem can handle being
2217 * passed hwndDlg rather than NULL but that is undocumented
2218 * so let's do it properly
2220 HWND hwndFocus
= GetFocus();
2221 HWND hwndNext
= GetNextDlgTabItem (hDlg
,
2222 hwndFocus
== hDlg
? NULL
: hwndFocus
,
2223 GetKeyState (VK_SHIFT
) & 0x8000);
2226 dlgCode
= SendMessageW (hwndNext
, WM_GETDLGCODE
,
2227 lpMsg
->wParam
, (LPARAM
)lpMsg
);
2228 if (dlgCode
& DLGC_HASSETSEL
)
2230 INT maxlen
= 1 + SendMessageW (hwndNext
, WM_GETTEXTLENGTH
, 0, 0);
2231 WCHAR
*buffer
= HeapAlloc (GetProcessHeap(), 0, maxlen
* sizeof(WCHAR
));
2235 SendMessageW (hwndNext
, WM_GETTEXT
, maxlen
, (LPARAM
) buffer
);
2236 length
= wcslen (buffer
);
2237 HeapFree (GetProcessHeap(), 0, buffer
);
2238 SendMessageW (hwndNext
, EM_SETSEL
, 0, length
);
2241 SetFocus (hwndNext
);
2242 DIALOG_FixChildrenOnChangeFocus (hDlg
, hwndNext
);
2255 if (!(dlgCode
& DLGC_WANTARROWS
))
2257 BOOL fPrevious
= (lpMsg
->wParam
== VK_LEFT
|| lpMsg
->wParam
== VK_UP
);
2258 HWND hwndNext
= GetNextDlgGroupItem (hDlg
, GetFocus(), fPrevious
);
2259 SendMessageW( hDlg
, WM_NEXTDLGCTL
, (WPARAM
)hwndNext
, 1 );
2266 SendMessageW( hDlg
, WM_COMMAND
, IDCANCEL
, (LPARAM
)GetDlgItem( hDlg
, IDCANCEL
) );
2273 if ((GetFocus() == lpMsg
->hwnd
) &&
2274 (SendMessageW (lpMsg
->hwnd
, WM_GETDLGCODE
, 0, 0) & DLGC_DEFPUSHBUTTON
))
2276 SendMessageW (hDlg
, WM_COMMAND
, MAKEWPARAM (GetDlgCtrlID(lpMsg
->hwnd
),BN_CLICKED
), (LPARAM
)lpMsg
->hwnd
);
2278 else if (DC_HASDEFID
== HIWORD(dw
= SendMessageW (hDlg
, DM_GETDEFID
, 0, 0)))
2280 SendMessageW( hDlg
, WM_COMMAND
, MAKEWPARAM( LOWORD(dw
), BN_CLICKED
),
2281 (LPARAM
)GetDlgItem(hDlg
, LOWORD(dw
)));
2285 SendMessageW( hDlg
, WM_COMMAND
, IDOK
, (LPARAM
)GetDlgItem( hDlg
, IDOK
) );
2294 dlgCode
= SendMessageW( lpMsg
->hwnd
, WM_GETDLGCODE
, lpMsg
->wParam
, (LPARAM
)lpMsg
);
2295 if (dlgCode
& (DLGC_WANTCHARS
|DLGC_WANTMESSAGE
)) break;
2296 if (lpMsg
->wParam
== '\t' && (dlgCode
& DLGC_WANTTAB
)) break;
2300 if (DIALOG_IsAccelerator( lpMsg
->hwnd
, hDlg
, lpMsg
->wParam
))
2302 /* don't translate or dispatch */
2308 TranslateMessage( lpMsg
);
2309 DispatchMessageW( lpMsg
);
2323 return (UINT
)SendDlgItemMessageW( hDlg
, nIDButton
, BM_GETCHECK
, 0, 0 );
2336 DIALOGINFO
* dlgInfo
;
2337 if (!(dlgInfo
= GETDLGINFO(hDlg
))) return FALSE
;
2338 lpRect
->left
= MulDiv(lpRect
->left
, dlgInfo
->xBaseUnit
, 4);
2339 lpRect
->right
= MulDiv(lpRect
->right
, dlgInfo
->xBaseUnit
, 4);
2340 lpRect
->top
= MulDiv(lpRect
->top
, dlgInfo
->yBaseUnit
, 8);
2341 lpRect
->bottom
= MulDiv(lpRect
->bottom
, dlgInfo
->yBaseUnit
, 8);
2351 SendDlgItemMessageA(
2358 HWND hwndCtrl
= GetDlgItem( hDlg
, nIDDlgItem
);
2359 if (hwndCtrl
) return SendMessageA( hwndCtrl
, Msg
, wParam
, lParam
);
2369 SendDlgItemMessageW(
2376 HWND hwndCtrl
= GetDlgItem( hDlg
, nIDDlgItem
);
2377 if (hwndCtrl
) return SendMessageW( hwndCtrl
, Msg
, wParam
, lParam
);
2395 if (bSigned
) sprintf( str
, "%d", (INT
)uValue
);
2396 else sprintf( str
, "%u", uValue
);
2397 SendDlgItemMessageA( hDlg
, nIDDlgItem
, WM_SETTEXT
, 0, (LPARAM
)str
);
2412 return SendDlgItemMessageA( hDlg
, nIDDlgItem
, WM_SETTEXT
, 0, (LPARAM
)lpString
);
2426 return SendDlgItemMessageW( hDlg
, nIDDlgItem
, WM_SETTEXT
, 0, (LPARAM
)lpString
);
2440 SendDlgItemMessageW( hDlg
, nIDButton
, BM_SETCHECK
, uCheck
, 0 );
2444 static BOOL CALLBACK
CheckRB(HWND hwnd
, LPARAM lParam
)
2446 LONG lChildID
= GetWindowLongPtrW(hwnd
, GWLP_ID
);
2447 RADIOGROUP
*lpRadioGroup
= (RADIOGROUP
*)lParam
;
2449 if((lChildID
>= lpRadioGroup
->firstID
) &&
2450 (lChildID
<= lpRadioGroup
->lastID
))
2452 if (lChildID
== lpRadioGroup
->checkID
)
2454 SendMessageW(hwnd
, BM_SETCHECK
, BST_CHECKED
, 0);
2458 SendMessageW(hwnd
, BM_SETCHECK
, BST_UNCHECKED
, 0);
2476 RADIOGROUP radioGroup
;
2478 radioGroup
.firstID
= nIDFirstButton
;
2479 radioGroup
.lastID
= nIDLastButton
;
2480 radioGroup
.checkID
= nIDCheckButton
;
2482 return EnumChildWindows(hDlg
, CheckRB
, (LPARAM
)&radioGroup
);