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