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