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