Sync with trunk r58033.
[reactos.git] / dll / win32 / comctl32 / commctrl.c
1 /*
2 * Common controls functions
3 *
4 * Copyright 1997 Dimitrie O. Paun
5 * Copyright 1998,2000 Eric Kohl
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 * NOTES
22 *
23 * This code was audited for completeness against the documented features
24 * of Comctl32.dll version 6.0 on Oct. 21, 2002, by Christian Neumair.
25 *
26 * Unless otherwise noted, we believe this code to be complete, as per
27 * the specification mentioned above.
28 * If you discover missing features, or bugs, please note them below.
29 *
30 * TODO
31 * -- implement GetMUILanguage + InitMUILanguage
32 * -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW
33 * -- FIXMEs + BUGS (search for them)
34 *
35 * Control Classes
36 * -- ICC_ANIMATE_CLASS
37 * -- ICC_BAR_CLASSES
38 * -- ICC_COOL_CLASSES
39 * -- ICC_DATE_CLASSES
40 * -- ICC_HOTKEY_CLASS
41 * -- ICC_INTERNET_CLASSES
42 * -- ICC_LINK_CLASS
43 * -- ICC_LISTVIEW_CLASSES
44 * -- ICC_NATIVEFNTCTL_CLASS
45 * -- ICC_PAGESCROLLER_CLASS
46 * -- ICC_PROGRESS_CLASS
47 * -- ICC_STANDARD_CLASSES (not yet implemented)
48 * -- ICC_TAB_CLASSES
49 * -- ICC_TREEVIEW_CLASSES
50 * -- ICC_UPDOWN_CLASS
51 * -- ICC_USEREX_CLASSES
52 * -- ICC_WIN95_CLASSES
53 */
54
55 #include <stdarg.h>
56 #include <string.h>
57 #include <stdlib.h>
58
59 #include "windef.h"
60 #include "winbase.h"
61 #include "wingdi.h"
62 #include "winuser.h"
63 #include "winnls.h"
64 #include "commctrl.h"
65 #include "winerror.h"
66 #include "winreg.h"
67 #define NO_SHLWAPI_STREAM
68 #include "shlwapi.h"
69 #include "comctl32.h"
70 #include "wine/debug.h"
71
72 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
73
74 #define NAME L"microsoft.windows.common-controls"
75 #define VERSION L"6.0.2600.2982"
76 #define PUBLIC_KEY L"6595b64144ccf1df"
77
78 #ifdef __i386__
79 #define ARCH L"x86"
80 #elif defined __x86_64__
81 #define ARCH L"amd64"
82 #else
83 #define ARCH L"none"
84 #endif
85
86 static const WCHAR manifest_filename[] = ARCH L"_" NAME L"_" PUBLIC_KEY L"_" VERSION L"_none_deadbeef.manifest";
87
88 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
89
90 static LPWSTR COMCTL32_wSubclass = NULL;
91 HMODULE COMCTL32_hModule = 0;
92 static LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
93 HBRUSH COMCTL32_hPattern55AABrush = NULL;
94 COMCTL32_SysColor comctl32_color;
95
96 static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
97
98 static const WORD wPattern55AA[] =
99 {
100 0x5555, 0xaaaa, 0x5555, 0xaaaa,
101 0x5555, 0xaaaa, 0x5555, 0xaaaa
102 };
103
104 static const WCHAR strCC32SubclassInfo[] = {
105 'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
106 };
107
108 static BOOL create_manifest(BOOL install)
109 {
110 WCHAR *pwszBuf;
111 HRSRC hResInfo;
112 HGLOBAL hResData;
113 PVOID pManifest;
114 DWORD cchBuf, cbManifest, cbWritten;
115 HANDLE hFile;
116 BOOL bRet = FALSE;
117
118 hResInfo = FindResourceW(COMCTL32_hModule, L"WINE_MANIFEST", RT_MANIFEST);
119 if (!hResInfo)
120 return FALSE;
121
122 cbManifest = SizeofResource(COMCTL32_hModule, hResInfo);
123 if (!cbManifest)
124 return FALSE;
125
126 hResData = LoadResource(COMCTL32_hModule, hResInfo);
127 if (!hResData)
128 return FALSE;
129
130 pManifest = LockResource(hResData);
131 if (!pManifest)
132 return FALSE;
133
134 cchBuf = GetWindowsDirectoryW(NULL, 0) * sizeof(WCHAR) + sizeof(L"\\winsxs\\manifests\\") + sizeof(manifest_filename);
135 pwszBuf = (WCHAR*)HeapAlloc(GetProcessHeap(), 0, cchBuf * sizeof(WCHAR));
136 if (!pwszBuf)
137 return FALSE;
138
139 GetWindowsDirectoryW(pwszBuf, cchBuf);
140 lstrcatW(pwszBuf, L"\\winsxs");
141 CreateDirectoryW(pwszBuf, NULL);
142 lstrcatW(pwszBuf, L"\\manifests\\");
143 CreateDirectoryW(pwszBuf, NULL);
144 lstrcatW(pwszBuf, manifest_filename);
145 if (install)
146 {
147 hFile = CreateFileW(pwszBuf, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
148 if (hFile != INVALID_HANDLE_VALUE)
149 {
150 if (WriteFile(hFile, pManifest, cbManifest, &cbWritten, NULL) && cbWritten == cbManifest)
151 bRet = TRUE;
152
153 CloseHandle(hFile);
154
155 if (!bRet)
156 DeleteFileW(pwszBuf);
157 else
158 TRACE("created %s\n", debugstr_w(pwszBuf));
159 }
160 }
161 else
162 bRet = DeleteFileW(pwszBuf);
163
164 HeapFree(GetProcessHeap(), 0, pwszBuf);
165
166 return bRet;
167 }
168
169
170 /***********************************************************************
171 * DllMain [Internal]
172 *
173 * Initializes the internal 'COMCTL32.DLL'.
174 *
175 * PARAMS
176 * hinstDLL [I] handle to the 'dlls' instance
177 * fdwReason [I]
178 * lpvReserved [I] reserved, must be NULL
179 *
180 * RETURNS
181 * Success: TRUE
182 * Failure: FALSE
183 */
184
185 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
186 {
187 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
188
189 switch (fdwReason) {
190 case DLL_PROCESS_ATTACH:
191 DisableThreadLibraryCalls(hinstDLL);
192
193 COMCTL32_hModule = hinstDLL;
194
195 /* add global subclassing atom (used by 'tooltip' and 'updown') */
196 COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
197 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
198
199 /* create local pattern brush */
200 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
201 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
202
203 /* Get all the colors at DLL load */
204 COMCTL32_RefreshSysColors();
205
206 /* like comctl32 5.82+ register all the common control classes */
207 ANIMATE_Register ();
208 COMBOEX_Register ();
209 DATETIME_Register ();
210 FLATSB_Register ();
211 HEADER_Register ();
212 HOTKEY_Register ();
213 IPADDRESS_Register ();
214 LISTVIEW_Register ();
215 MONTHCAL_Register ();
216 NATIVEFONT_Register ();
217 PAGER_Register ();
218 PROGRESS_Register ();
219 REBAR_Register ();
220 STATUS_Register ();
221 SYSLINK_Register ();
222 TAB_Register ();
223 TOOLBAR_Register ();
224 TOOLTIPS_Register ();
225 TRACKBAR_Register ();
226 TREEVIEW_Register ();
227 UPDOWN_Register ();
228
229 /* subclass user32 controls */
230 THEMING_Initialize ();
231 break;
232
233 case DLL_PROCESS_DETACH:
234 /* clean up subclassing */
235 THEMING_Uninitialize();
236
237 /* unregister all common control classes */
238 ANIMATE_Unregister ();
239 COMBOEX_Unregister ();
240 DATETIME_Unregister ();
241 FLATSB_Unregister ();
242 HEADER_Unregister ();
243 HOTKEY_Unregister ();
244 IPADDRESS_Unregister ();
245 LISTVIEW_Unregister ();
246 MONTHCAL_Unregister ();
247 NATIVEFONT_Unregister ();
248 PAGER_Unregister ();
249 PROGRESS_Unregister ();
250 REBAR_Unregister ();
251 STATUS_Unregister ();
252 SYSLINK_Unregister ();
253 TAB_Unregister ();
254 TOOLBAR_Unregister ();
255 TOOLTIPS_Unregister ();
256 TRACKBAR_Unregister ();
257 TREEVIEW_Unregister ();
258 UPDOWN_Unregister ();
259
260 /* delete local pattern brush */
261 DeleteObject (COMCTL32_hPattern55AABrush);
262 COMCTL32_hPattern55AABrush = NULL;
263 DeleteObject (COMCTL32_hPattern55AABitmap);
264 COMCTL32_hPattern55AABitmap = NULL;
265
266 /* delete global subclassing atom */
267 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
268 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
269 COMCTL32_wSubclass = NULL;
270 break;
271 }
272
273 return TRUE;
274 }
275
276
277 /***********************************************************************
278 * MenuHelp [COMCTL32.2]
279 *
280 * Handles the setting of status bar help messages when the user
281 * selects menu items.
282 *
283 * PARAMS
284 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
285 * wParam [I] wParam of the message uMsg
286 * lParam [I] lParam of the message uMsg
287 * hMainMenu [I] handle to the application's main menu
288 * hInst [I] handle to the module that contains string resources
289 * hwndStatus [I] handle to the status bar window
290 * lpwIDs [I] pointer to an array of integers (see NOTES)
291 *
292 * RETURNS
293 * No return value
294 *
295 * NOTES
296 * The official documentation is incomplete!
297 * This is the correct documentation:
298 *
299 * uMsg:
300 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
301 * WM_MENUSELECT messages.
302 *
303 * lpwIDs:
304 * (will be written ...)
305 */
306
307 VOID WINAPI
308 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
309 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
310 {
311 UINT uMenuID = 0;
312
313 if (!IsWindow (hwndStatus))
314 return;
315
316 switch (uMsg) {
317 case WM_MENUSELECT:
318 TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
319 wParam, lParam);
320
321 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
322 /* menu was closed */
323 TRACE("menu was closed!\n");
324 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
325 }
326 else {
327 /* menu item was selected */
328 if (HIWORD(wParam) & MF_POPUP)
329 uMenuID = *(lpwIDs+1);
330 else
331 uMenuID = (UINT)LOWORD(wParam);
332 TRACE("uMenuID = %u\n", uMenuID);
333
334 if (uMenuID) {
335 WCHAR szText[256];
336
337 if (!LoadStringW (hInst, uMenuID, szText, sizeof(szText)/sizeof(szText[0])))
338 szText[0] = '\0';
339
340 SendMessageW (hwndStatus, SB_SETTEXTW,
341 255 | SBT_NOBORDERS, (LPARAM)szText);
342 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
343 }
344 }
345 break;
346
347 case WM_COMMAND :
348 TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
349 wParam, lParam);
350 /* WM_COMMAND is not invalid since it is documented
351 * in the windows api reference. So don't output
352 * any FIXME for WM_COMMAND
353 */
354 WARN("We don't care about the WM_COMMAND\n");
355 break;
356
357 default:
358 FIXME("Invalid Message 0x%x!\n", uMsg);
359 break;
360 }
361 }
362
363
364 /***********************************************************************
365 * ShowHideMenuCtl [COMCTL32.3]
366 *
367 * Shows or hides controls and updates the corresponding menu item.
368 *
369 * PARAMS
370 * hwnd [I] handle to the client window.
371 * uFlags [I] menu command id.
372 * lpInfo [I] pointer to an array of integers. (See NOTES.)
373 *
374 * RETURNS
375 * Success: TRUE
376 * Failure: FALSE
377 *
378 * NOTES
379 * The official documentation is incomplete!
380 * This is the correct documentation:
381 *
382 * hwnd
383 * Handle to the window that contains the menu and controls.
384 *
385 * uFlags
386 * Identifier of the menu item to receive or lose a check mark.
387 *
388 * lpInfo
389 * The array of integers contains pairs of values. BOTH values of
390 * the first pair must be the handles to the application's main menu.
391 * Each subsequent pair consists of a menu id and control id.
392 */
393
394 BOOL WINAPI
395 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
396 {
397 LPINT lpMenuId;
398
399 TRACE("%p, %lx, %p\n", hwnd, uFlags, lpInfo);
400
401 if (lpInfo == NULL)
402 return FALSE;
403
404 if (!(lpInfo[0]) || !(lpInfo[1]))
405 return FALSE;
406
407 /* search for control */
408 lpMenuId = &lpInfo[2];
409 while (*lpMenuId != uFlags)
410 lpMenuId += 2;
411
412 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
413 /* uncheck menu item */
414 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
415
416 /* hide control */
417 lpMenuId++;
418 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
419 SWP_HIDEWINDOW);
420 }
421 else {
422 /* check menu item */
423 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
424
425 /* show control */
426 lpMenuId++;
427 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
428 SWP_SHOWWINDOW);
429 }
430
431 return TRUE;
432 }
433
434
435 /***********************************************************************
436 * GetEffectiveClientRect [COMCTL32.4]
437 *
438 * Calculates the coordinates of a rectangle in the client area.
439 *
440 * PARAMS
441 * hwnd [I] handle to the client window.
442 * lpRect [O] pointer to the rectangle of the client window
443 * lpInfo [I] pointer to an array of integers (see NOTES)
444 *
445 * RETURNS
446 * No return value.
447 *
448 * NOTES
449 * The official documentation is incomplete!
450 * This is the correct documentation:
451 *
452 * lpInfo
453 * (will be written ...)
454 */
455
456 VOID WINAPI
457 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
458 {
459 RECT rcCtrl;
460 const INT *lpRun;
461 HWND hwndCtrl;
462
463 TRACE("(%p %p %p)\n",
464 hwnd, lpRect, lpInfo);
465
466 GetClientRect (hwnd, lpRect);
467 lpRun = lpInfo;
468
469 do {
470 lpRun += 2;
471 if (*lpRun == 0)
472 return;
473 lpRun++;
474 hwndCtrl = GetDlgItem (hwnd, *lpRun);
475 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
476 TRACE("control id 0x%x\n", *lpRun);
477 GetWindowRect (hwndCtrl, &rcCtrl);
478 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
479 SubtractRect (lpRect, lpRect, &rcCtrl);
480 }
481 lpRun++;
482 } while (*lpRun);
483 }
484
485
486 /***********************************************************************
487 * DrawStatusTextW [COMCTL32.@]
488 *
489 * Draws text with borders, like in a status bar.
490 *
491 * PARAMS
492 * hdc [I] handle to the window's display context
493 * lprc [I] pointer to a rectangle
494 * text [I] pointer to the text
495 * style [I] drawing style
496 *
497 * RETURNS
498 * No return value.
499 *
500 * NOTES
501 * The style variable can have one of the following values:
502 * (will be written ...)
503 */
504
505 void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
506 {
507 RECT r = *lprc;
508 UINT border = BDR_SUNKENOUTER;
509
510 if (style & SBT_POPOUT)
511 border = BDR_RAISEDOUTER;
512 else if (style & SBT_NOBORDERS)
513 border = 0;
514
515 DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
516
517 /* now draw text */
518 if (text) {
519 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
520 UINT align = DT_LEFT;
521 int strCnt = 0;
522
523 if (style & SBT_RTLREADING)
524 FIXME("Unsupported RTL style!\n");
525 r.left += 3;
526 do {
527 if (*text == '\t') {
528 if (strCnt) {
529 DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
530 strCnt = 0;
531 }
532 if (align==DT_RIGHT) {
533 break;
534 }
535 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
536 } else {
537 strCnt++;
538 }
539 } while(*text++);
540
541 if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
542 SetBkMode(hdc, oldbkmode);
543 }
544 }
545
546
547 /***********************************************************************
548 * DrawStatusText [COMCTL32.@]
549 * DrawStatusTextA [COMCTL32.5]
550 *
551 * Draws text with borders, like in a status bar.
552 *
553 * PARAMS
554 * hdc [I] handle to the window's display context
555 * lprc [I] pointer to a rectangle
556 * text [I] pointer to the text
557 * style [I] drawing style
558 *
559 * RETURNS
560 * No return value.
561 */
562
563 void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
564 {
565 INT len;
566 LPWSTR textW = NULL;
567
568 if ( text ) {
569 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
570 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
571 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
572 }
573 }
574 DrawStatusTextW( hdc, lprc, textW, style );
575 Free( textW );
576 }
577
578
579 /***********************************************************************
580 * CreateStatusWindow [COMCTL32.@]
581 * CreateStatusWindowA [COMCTL32.6]
582 *
583 * Creates a status bar
584 *
585 * PARAMS
586 * style [I] window style
587 * text [I] pointer to the window text
588 * parent [I] handle to the parent window
589 * wid [I] control id of the status bar
590 *
591 * RETURNS
592 * Success: handle to the status window
593 * Failure: 0
594 */
595
596 HWND WINAPI
597 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
598 {
599 return CreateWindowA(STATUSCLASSNAMEA, text, style,
600 CW_USEDEFAULT, CW_USEDEFAULT,
601 CW_USEDEFAULT, CW_USEDEFAULT,
602 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
603 }
604
605
606 /***********************************************************************
607 * CreateStatusWindowW [COMCTL32.@]
608 *
609 * Creates a status bar control
610 *
611 * PARAMS
612 * style [I] window style
613 * text [I] pointer to the window text
614 * parent [I] handle to the parent window
615 * wid [I] control id of the status bar
616 *
617 * RETURNS
618 * Success: handle to the status window
619 * Failure: 0
620 */
621
622 HWND WINAPI
623 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
624 {
625 return CreateWindowW(STATUSCLASSNAMEW, text, style,
626 CW_USEDEFAULT, CW_USEDEFAULT,
627 CW_USEDEFAULT, CW_USEDEFAULT,
628 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
629 }
630
631
632 /***********************************************************************
633 * CreateUpDownControl [COMCTL32.16]
634 *
635 * Creates an up-down control
636 *
637 * PARAMS
638 * style [I] window styles
639 * x [I] horizontal position of the control
640 * y [I] vertical position of the control
641 * cx [I] with of the control
642 * cy [I] height of the control
643 * parent [I] handle to the parent window
644 * id [I] the control's identifier
645 * inst [I] handle to the application's module instance
646 * buddy [I] handle to the buddy window, can be NULL
647 * maxVal [I] upper limit of the control
648 * minVal [I] lower limit of the control
649 * curVal [I] current value of the control
650 *
651 * RETURNS
652 * Success: handle to the updown control
653 * Failure: 0
654 */
655
656 HWND WINAPI
657 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
658 HWND parent, INT id, HINSTANCE inst,
659 HWND buddy, INT maxVal, INT minVal, INT curVal)
660 {
661 HWND hUD =
662 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
663 parent, (HMENU)(DWORD_PTR)id, inst, 0);
664 if (hUD) {
665 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
666 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
667 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
668 }
669
670 return hUD;
671 }
672
673
674 /***********************************************************************
675 * InitCommonControls [COMCTL32.17]
676 *
677 * Registers the common controls.
678 *
679 * PARAMS
680 * No parameters.
681 *
682 * RETURNS
683 * No return values.
684 *
685 * NOTES
686 * This function is just a dummy - all the controls are registered at
687 * the DLL initialization time. See InitCommonContolsEx for details.
688 */
689
690 VOID WINAPI
691 InitCommonControls (void)
692 {
693 }
694
695
696 /***********************************************************************
697 * InitCommonControlsEx [COMCTL32.@]
698 *
699 * Registers the common controls.
700 *
701 * PARAMS
702 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
703 *
704 * RETURNS
705 * Success: TRUE
706 * Failure: FALSE
707 *
708 * NOTES
709 * Probably all versions of comctl32 initializes the Win95 controls in DllMain
710 * during DLL initialization. Starting from comctl32 v5.82 all the controls
711 * are initialized there. We follow this behaviour and this function is just
712 * a dummy.
713 *
714 * Note: when writing programs under Windows, if you don't call any function
715 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
716 * was the only comctl32 function you were calling and you remove it you may
717 * have a false impression that InitCommonControlsEx actually did something.
718 */
719
720 BOOL WINAPI
721 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
722 {
723 if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
724 return FALSE;
725
726 TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
727 return TRUE;
728 }
729
730
731 /***********************************************************************
732 * CreateToolbarEx [COMCTL32.@]
733 *
734 * Creates a toolbar window.
735 *
736 * PARAMS
737 * hwnd
738 * style
739 * wID
740 * nBitmaps
741 * hBMInst
742 * wBMID
743 * lpButtons
744 * iNumButtons
745 * dxButton
746 * dyButton
747 * dxBitmap
748 * dyBitmap
749 * uStructSize
750 *
751 * RETURNS
752 * Success: handle to the tool bar control
753 * Failure: 0
754 */
755
756 HWND WINAPI
757 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
758 HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
759 INT iNumButtons, INT dxButton, INT dyButton,
760 INT dxBitmap, INT dyBitmap, UINT uStructSize)
761 {
762 HWND hwndTB;
763
764 hwndTB =
765 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
766 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
767 if(hwndTB) {
768 TBADDBITMAP tbab;
769
770 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
771
772 /* set bitmap and button size */
773 /*If CreateToolbarEx receives 0, windows sets default values*/
774 if (dxBitmap < 0)
775 dxBitmap = 16;
776 if (dyBitmap < 0)
777 dyBitmap = 16;
778 if (dxBitmap == 0 || dyBitmap == 0)
779 dxBitmap = dyBitmap = 16;
780 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
781
782 if (dxButton < 0)
783 dxButton = dxBitmap;
784 if (dyButton < 0)
785 dyButton = dyBitmap;
786 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
787 if (dxButton != 0 && dyButton != 0)
788 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
789
790
791 /* add bitmaps */
792 if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
793 {
794 tbab.hInst = hBMInst;
795 tbab.nID = wBMID;
796
797 SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
798 }
799 /* add buttons */
800 if(iNumButtons > 0)
801 SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
802 }
803
804 return hwndTB;
805 }
806
807
808 /***********************************************************************
809 * CreateMappedBitmap [COMCTL32.8]
810 *
811 * Loads a bitmap resource using a colour map.
812 *
813 * PARAMS
814 * hInstance [I] Handle to the module containing the bitmap.
815 * idBitmap [I] The bitmap resource ID.
816 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
817 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
818 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
819 *
820 * RETURNS
821 * Success: handle to the new bitmap
822 * Failure: 0
823 */
824
825 HBITMAP WINAPI
826 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
827 LPCOLORMAP lpColorMap, INT iNumMaps)
828 {
829 HGLOBAL hglb;
830 HRSRC hRsrc;
831 const BITMAPINFOHEADER *lpBitmap;
832 LPBITMAPINFOHEADER lpBitmapInfo;
833 UINT nSize, nColorTableSize, iColor;
834 RGBQUAD *pColorTable;
835 INT i, iMaps, nWidth, nHeight;
836 HDC hdcScreen;
837 HBITMAP hbm;
838 LPCOLORMAP sysColorMap;
839 COLORREF cRef;
840 COLORMAP internalColorMap[4] =
841 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
842
843 /* initialize pointer to colortable and default color table */
844 if (lpColorMap) {
845 iMaps = iNumMaps;
846 sysColorMap = lpColorMap;
847 }
848 else {
849 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
850 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
851 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
852 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
853 iMaps = 4;
854 sysColorMap = internalColorMap;
855 }
856
857 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
858 if (hRsrc == 0)
859 return 0;
860 hglb = LoadResource (hInstance, hRsrc);
861 if (hglb == 0)
862 return 0;
863 lpBitmap = LockResource (hglb);
864 if (lpBitmap == NULL)
865 return 0;
866
867 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
868 nColorTableSize = lpBitmap->biClrUsed;
869 else if (lpBitmap->biBitCount <= 8)
870 nColorTableSize = (1 << lpBitmap->biBitCount);
871 else
872 nColorTableSize = 0;
873 nSize = lpBitmap->biSize;
874 if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
875 nSize += 3 * sizeof(DWORD);
876 nSize += nColorTableSize * sizeof(RGBQUAD);
877 lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
878 if (lpBitmapInfo == NULL)
879 return 0;
880 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
881
882 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
883
884 for (iColor = 0; iColor < nColorTableSize; iColor++) {
885 for (i = 0; i < iMaps; i++) {
886 cRef = RGB(pColorTable[iColor].rgbRed,
887 pColorTable[iColor].rgbGreen,
888 pColorTable[iColor].rgbBlue);
889 if ( cRef == sysColorMap[i].from) {
890 #if 0
891 if (wFlags & CBS_MASKED) {
892 if (sysColorMap[i].to != COLOR_BTNTEXT)
893 pColorTable[iColor] = RGB(255, 255, 255);
894 }
895 else
896 #endif
897 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
898 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
899 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
900 break;
901 }
902 }
903 }
904 nWidth = lpBitmapInfo->biWidth;
905 nHeight = lpBitmapInfo->biHeight;
906 hdcScreen = GetDC (NULL);
907 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
908 if (hbm) {
909 HDC hdcDst = CreateCompatibleDC (hdcScreen);
910 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
911 const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
912 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
913 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
914 SRCCOPY);
915 SelectObject (hdcDst, hbmOld);
916 DeleteDC (hdcDst);
917 }
918 ReleaseDC (NULL, hdcScreen);
919 GlobalFree (lpBitmapInfo);
920 FreeResource (hglb);
921
922 return hbm;
923 }
924
925
926 /***********************************************************************
927 * CreateToolbar [COMCTL32.7]
928 *
929 * Creates a toolbar control.
930 *
931 * PARAMS
932 * hwnd
933 * style
934 * wID
935 * nBitmaps
936 * hBMInst
937 * wBMID
938 * lpButtons
939 * iNumButtons
940 *
941 * RETURNS
942 * Success: handle to the tool bar control
943 * Failure: 0
944 *
945 * NOTES
946 * Do not use this functions anymore. Use CreateToolbarEx instead.
947 */
948
949 HWND WINAPI
950 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
951 HINSTANCE hBMInst, UINT wBMID,
952 LPCTBBUTTON lpButtons,INT iNumButtons)
953 {
954 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
955 hBMInst, wBMID, lpButtons,
956 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
957 }
958
959
960 /***********************************************************************
961 * DllGetVersion [COMCTL32.@]
962 *
963 * Retrieves version information of the 'COMCTL32.DLL'
964 *
965 * PARAMS
966 * pdvi [O] pointer to version information structure.
967 *
968 * RETURNS
969 * Success: S_OK
970 * Failure: E_INVALIDARG
971 *
972 * NOTES
973 * Returns version of a comctl32.dll from IE4.01 SP1.
974 */
975
976 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
977 {
978 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
979 WARN("wrong DLLVERSIONINFO size from app\n");
980 return E_INVALIDARG;
981 }
982
983 pdvi->dwMajorVersion = COMCTL32_VERSION;
984 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
985 pdvi->dwBuildNumber = 2919;
986 pdvi->dwPlatformID = 6304;
987
988 TRACE("%u.%u.%u.%u\n",
989 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
990 pdvi->dwBuildNumber, pdvi->dwPlatformID);
991
992 return S_OK;
993 }
994
995 /***********************************************************************
996 * DllInstall (COMCTL32.@)
997 *
998 * Installs the ComCtl32 DLL.
999 *
1000 * RETURNS
1001 * Success: S_OK
1002 * Failure: A HRESULT error
1003 */
1004 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
1005 {
1006 TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
1007 if (!create_manifest(bInstall))
1008 {
1009 ERR("create_manifest failed!\n");
1010 return HRESULT_FROM_WIN32(GetLastError());
1011 }
1012
1013 return S_OK;
1014 }
1015
1016 /***********************************************************************
1017 * _TrackMouseEvent [COMCTL32.@]
1018 *
1019 * Requests notification of mouse events
1020 *
1021 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1022 * to the hwnd specified in the ptme structure. After the event message
1023 * is posted to the hwnd, the entry in the queue is removed.
1024 *
1025 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1026 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1027 * immediately and the TME_LEAVE flag being ignored.
1028 *
1029 * PARAMS
1030 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1031 *
1032 * RETURNS
1033 * Success: non-zero
1034 * Failure: zero
1035 *
1036 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1037 *
1038 */
1039
1040 BOOL WINAPI
1041 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1042 {
1043 return TrackMouseEvent (ptme);
1044 }
1045
1046 /*************************************************************************
1047 * GetMUILanguage [COMCTL32.@]
1048 *
1049 * Returns the user interface language in use by the current process.
1050 *
1051 * RETURNS
1052 * Language ID in use by the current process.
1053 */
1054 LANGID WINAPI GetMUILanguage (VOID)
1055 {
1056 return COMCTL32_uiLang;
1057 }
1058
1059
1060 /*************************************************************************
1061 * InitMUILanguage [COMCTL32.@]
1062 *
1063 * Sets the user interface language to be used by the current process.
1064 *
1065 * RETURNS
1066 * Nothing.
1067 */
1068 VOID WINAPI InitMUILanguage (LANGID uiLang)
1069 {
1070 COMCTL32_uiLang = uiLang;
1071 }
1072
1073
1074 /***********************************************************************
1075 * SetWindowSubclass [COMCTL32.410]
1076 *
1077 * Starts a window subclass
1078 *
1079 * PARAMS
1080 * hWnd [in] handle to window subclass.
1081 * pfnSubclass [in] Pointer to new window procedure.
1082 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1083 * dwRef [in] Reference data to pass to window procedure.
1084 *
1085 * RETURNS
1086 * Success: non-zero
1087 * Failure: zero
1088 *
1089 * BUGS
1090 * If an application manually subclasses a window after subclassing it with
1091 * this API and then with this API again, then none of the previous
1092 * subclasses get called or the original window procedure.
1093 */
1094
1095 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1096 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1097 {
1098 LPSUBCLASS_INFO stack;
1099 LPSUBCLASSPROCS proc;
1100
1101 TRACE ("(%p, %p, %lx, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1102
1103 /* Since the window procedure that we set here has two additional arguments,
1104 * we can't simply set it as the new window procedure of the window. So we
1105 * set our own window procedure and then calculate the other two arguments
1106 * from there. */
1107
1108 /* See if we have been called for this window */
1109 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1110 if (!stack) {
1111 /* allocate stack */
1112 stack = Alloc (sizeof(SUBCLASS_INFO));
1113 if (!stack) {
1114 ERR ("Failed to allocate our Subclassing stack\n");
1115 return FALSE;
1116 }
1117 SetPropW (hWnd, COMCTL32_wSubclass, stack);
1118
1119 /* set window procedure to our own and save the current one */
1120 if (IsWindowUnicode (hWnd))
1121 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1122 (DWORD_PTR)COMCTL32_SubclassProc);
1123 else
1124 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1125 (DWORD_PTR)COMCTL32_SubclassProc);
1126 }
1127 else {
1128 /* Check to see if we have called this function with the same uIDSubClass
1129 * and pfnSubclass */
1130 proc = stack->SubclassProcs;
1131 while (proc) {
1132 if ((proc->id == uIDSubclass) &&
1133 (proc->subproc == pfnSubclass)) {
1134 proc->ref = dwRef;
1135 return TRUE;
1136 }
1137 proc = proc->next;
1138 }
1139 }
1140
1141 proc = Alloc(sizeof(SUBCLASSPROCS));
1142 if (!proc) {
1143 ERR ("Failed to allocate subclass entry in stack\n");
1144 if (IsWindowUnicode (hWnd))
1145 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1146 else
1147 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1148 Free (stack);
1149 RemovePropW( hWnd, COMCTL32_wSubclass );
1150 return FALSE;
1151 }
1152
1153 proc->subproc = pfnSubclass;
1154 proc->ref = dwRef;
1155 proc->id = uIDSubclass;
1156 proc->next = stack->SubclassProcs;
1157 stack->SubclassProcs = proc;
1158
1159 return TRUE;
1160 }
1161
1162
1163 /***********************************************************************
1164 * GetWindowSubclass [COMCTL32.411]
1165 *
1166 * Gets the Reference data from a subclass.
1167 *
1168 * PARAMS
1169 * hWnd [in] Handle to window which were subclassing
1170 * pfnSubclass [in] Pointer to the subclass procedure
1171 * uID [in] Unique identifier of the subclassing procedure
1172 * pdwRef [out] Pointer to the reference data
1173 *
1174 * RETURNS
1175 * Success: Non-zero
1176 * Failure: 0
1177 */
1178
1179 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1180 UINT_PTR uID, DWORD_PTR *pdwRef)
1181 {
1182 const SUBCLASS_INFO *stack;
1183 const SUBCLASSPROCS *proc;
1184
1185 TRACE ("(%p, %p, %lx, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1186
1187 /* See if we have been called for this window */
1188 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1189 if (!stack)
1190 return FALSE;
1191
1192 proc = stack->SubclassProcs;
1193 while (proc) {
1194 if ((proc->id == uID) &&
1195 (proc->subproc == pfnSubclass)) {
1196 *pdwRef = proc->ref;
1197 return TRUE;
1198 }
1199 proc = proc->next;
1200 }
1201
1202 return FALSE;
1203 }
1204
1205
1206 /***********************************************************************
1207 * RemoveWindowSubclass [COMCTL32.412]
1208 *
1209 * Removes a window subclass.
1210 *
1211 * PARAMS
1212 * hWnd [in] Handle to the window were subclassing
1213 * pfnSubclass [in] Pointer to the subclass procedure
1214 * uID [in] Unique identifier of this subclass
1215 *
1216 * RETURNS
1217 * Success: non-zero
1218 * Failure: zero
1219 */
1220
1221 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1222 {
1223 LPSUBCLASS_INFO stack;
1224 LPSUBCLASSPROCS prevproc = NULL;
1225 LPSUBCLASSPROCS proc;
1226 BOOL ret = FALSE;
1227
1228 TRACE ("(%p, %p, %lx)\n", hWnd, pfnSubclass, uID);
1229
1230 /* Find the Subclass to remove */
1231 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1232 if (!stack)
1233 return FALSE;
1234
1235 proc = stack->SubclassProcs;
1236 while (proc) {
1237 if ((proc->id == uID) &&
1238 (proc->subproc == pfnSubclass)) {
1239
1240 if (!prevproc)
1241 stack->SubclassProcs = proc->next;
1242 else
1243 prevproc->next = proc->next;
1244
1245 if (stack->stackpos == proc)
1246 stack->stackpos = stack->stackpos->next;
1247
1248 Free (proc);
1249 ret = TRUE;
1250 break;
1251 }
1252 prevproc = proc;
1253 proc = proc->next;
1254 }
1255
1256 if (!stack->SubclassProcs && !stack->running) {
1257 TRACE("Last Subclass removed, cleaning up\n");
1258 /* clean up our heap and reset the original window procedure */
1259 if (IsWindowUnicode (hWnd))
1260 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1261 else
1262 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1263 Free (stack);
1264 RemovePropW( hWnd, COMCTL32_wSubclass );
1265 }
1266
1267 return ret;
1268 }
1269
1270 /***********************************************************************
1271 * COMCTL32_SubclassProc (internal)
1272 *
1273 * Window procedure for all subclassed windows.
1274 * Saves the current subclassing stack position to support nested messages
1275 */
1276 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1277 {
1278 LPSUBCLASS_INFO stack;
1279 LPSUBCLASSPROCS proc;
1280 LRESULT ret;
1281
1282 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1283
1284 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1285 if (!stack) {
1286 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1287 return 0;
1288 }
1289
1290 /* Save our old stackpos to properly handle nested messages */
1291 proc = stack->stackpos;
1292 stack->stackpos = stack->SubclassProcs;
1293 stack->running++;
1294 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1295 stack->running--;
1296 stack->stackpos = proc;
1297
1298 if (!stack->SubclassProcs && !stack->running) {
1299 TRACE("Last Subclass removed, cleaning up\n");
1300 /* clean up our heap and reset the original window procedure */
1301 if (IsWindowUnicode (hWnd))
1302 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1303 else
1304 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1305 Free (stack);
1306 RemovePropW( hWnd, COMCTL32_wSubclass );
1307 }
1308 return ret;
1309 }
1310
1311 /***********************************************************************
1312 * DefSubclassProc [COMCTL32.413]
1313 *
1314 * Calls the next window procedure (i.e. the one before this subclass)
1315 *
1316 * PARAMS
1317 * hWnd [in] The window that we're subclassing
1318 * uMsg [in] Message
1319 * wParam [in] WPARAM
1320 * lParam [in] LPARAM
1321 *
1322 * RETURNS
1323 * Success: non-zero
1324 * Failure: zero
1325 */
1326
1327 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1328 {
1329 LPSUBCLASS_INFO stack;
1330 LRESULT ret;
1331
1332 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1333
1334 /* retrieve our little stack from the Properties */
1335 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1336 if (!stack) {
1337 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1338 return 0;
1339 }
1340
1341 /* If we are at the end of stack then we have to call the original
1342 * window procedure */
1343 if (!stack->stackpos) {
1344 if (IsWindowUnicode (hWnd))
1345 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1346 else
1347 ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1348 } else {
1349 const SUBCLASSPROCS *proc = stack->stackpos;
1350 stack->stackpos = stack->stackpos->next;
1351 /* call the Subclass procedure from the stack */
1352 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1353 proc->id, proc->ref);
1354 }
1355
1356 return ret;
1357 }
1358
1359
1360 /***********************************************************************
1361 * COMCTL32_CreateToolTip [NOT AN API]
1362 *
1363 * Creates a tooltip for the control specified in hwnd and does all
1364 * necessary setup and notifications.
1365 *
1366 * PARAMS
1367 * hwndOwner [I] Handle to the window that will own the tool tip.
1368 *
1369 * RETURNS
1370 * Success: Handle of tool tip window.
1371 * Failure: NULL
1372 */
1373
1374 HWND
1375 COMCTL32_CreateToolTip(HWND hwndOwner)
1376 {
1377 HWND hwndToolTip;
1378
1379 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1380 CW_USEDEFAULT, CW_USEDEFAULT,
1381 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1382 0, 0, 0);
1383
1384 /* Send NM_TOOLTIPSCREATED notification */
1385 if (hwndToolTip)
1386 {
1387 NMTOOLTIPSCREATED nmttc;
1388 /* true owner can be different if hwndOwner is a child window */
1389 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1390 nmttc.hdr.hwndFrom = hwndTrueOwner;
1391 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1392 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1393 nmttc.hwndToolTips = hwndToolTip;
1394
1395 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1396 GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
1397 }
1398
1399 return hwndToolTip;
1400 }
1401
1402
1403 /***********************************************************************
1404 * COMCTL32_RefreshSysColors [NOT AN API]
1405 *
1406 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1407 * refresh the color values in the color structure
1408 *
1409 * PARAMS
1410 * none
1411 *
1412 * RETURNS
1413 * none
1414 */
1415
1416 VOID
1417 COMCTL32_RefreshSysColors(void)
1418 {
1419 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1420 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1421 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1422 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1423 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1424 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1425 comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1426 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1427 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1428 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1429 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1430 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1431 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1432 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1433 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1434 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1435 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1436 }
1437
1438 /***********************************************************************
1439 * COMCTL32_DrawInsertMark [NOT AN API]
1440 *
1441 * Draws an insertion mark (which looks similar to an 'I').
1442 *
1443 * PARAMS
1444 * hDC [I] Device context to draw onto.
1445 * lpRect [I] Co-ordinates of insertion mark.
1446 * clrInsertMark [I] Colour of the insertion mark.
1447 * bHorizontal [I] True if insert mark should be drawn horizontally,
1448 * vertical otherwise.
1449 *
1450 * RETURNS
1451 * none
1452 *
1453 * NOTES
1454 * Draws up to but not including the bottom co-ordinate when drawing
1455 * vertically or the right co-ordinate when horizontal.
1456 */
1457 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1458 {
1459 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1460 HPEN hOldPen;
1461 static const DWORD adwPolyPoints[] = {4,4,4};
1462 LONG lCentre = (bHorizontal ?
1463 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1464 lpRect->left + (lpRect->right - lpRect->left)/2);
1465 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1466 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1467 const POINT aptInsertMark[] =
1468 {
1469 /* top (V) or left (H) arrow */
1470 {lCentre , l1 + 2},
1471 {lCentre - 2, l1 },
1472 {lCentre + 3, l1 },
1473 {lCentre + 1, l1 + 2},
1474 /* middle line */
1475 {lCentre , l2 - 2},
1476 {lCentre , l1 - 1},
1477 {lCentre + 1, l1 - 1},
1478 {lCentre + 1, l2 - 2},
1479 /* bottom (V) or right (H) arrow */
1480 {lCentre , l2 - 3},
1481 {lCentre - 2, l2 - 1},
1482 {lCentre + 3, l2 - 1},
1483 {lCentre + 1, l2 - 3},
1484 };
1485 hOldPen = SelectObject(hDC, hPen);
1486 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0]));
1487 SelectObject(hDC, hOldPen);
1488 DeleteObject(hPen);
1489 }
1490
1491 /***********************************************************************
1492 * COMCTL32_EnsureBitmapSize [internal]
1493 *
1494 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1495 * the height is at least cyMinHeight. If the bitmap already has these
1496 * dimensions nothing changes.
1497 *
1498 * PARAMS
1499 * hBitmap [I/O] Bitmap to modify. The handle may change
1500 * cxMinWidth [I] If the width of the bitmap is smaller, then it will
1501 * be enlarged to this value
1502 * cyMinHeight [I] If the height of the bitmap is smaller, then it will
1503 * be enlarged to this value
1504 * cyBackground [I] The color with which the new area will be filled
1505 *
1506 * RETURNS
1507 * none
1508 */
1509 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1510 {
1511 int cxNew, cyNew;
1512 BITMAP bmp;
1513 HBITMAP hNewBitmap;
1514 HBITMAP hNewDCBitmap, hOldDCBitmap;
1515 HBRUSH hNewDCBrush;
1516 HDC hdcNew, hdcOld;
1517
1518 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1519 return;
1520 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1521 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1522 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1523 return;
1524
1525 hdcNew = CreateCompatibleDC(NULL);
1526 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1527 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1528 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1529
1530 hdcOld = CreateCompatibleDC(NULL);
1531 hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1532
1533 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1534 if (bmp.bmWidth < cxMinWidth)
1535 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1536 if (bmp.bmHeight < cyMinHeight)
1537 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1538 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1539 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1540
1541 SelectObject(hdcNew, hNewDCBitmap);
1542 DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1543 DeleteDC(hdcNew);
1544 SelectObject(hdcOld, hOldDCBitmap);
1545 DeleteDC(hdcOld);
1546
1547 DeleteObject(*pBitmap);
1548 *pBitmap = hNewBitmap;
1549 return;
1550 }
1551
1552 void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
1553 {
1554 HDC hdc = GetDC(NULL);
1555 HFONT hOldFont;
1556
1557 hOldFont = SelectObject(hdc, hFont);
1558 GetTextMetricsW(hdc, ptm);
1559 SelectObject(hdc, hOldFont);
1560 ReleaseDC(NULL, hdc);
1561 }
1562
1563 #ifndef OCM__BASE /* avoid including olectl.h */
1564 #define OCM__BASE (WM_USER+0x1c00)
1565 #endif
1566
1567 /***********************************************************************
1568 * COMCTL32_IsReflectedMessage [internal]
1569 *
1570 * Some parents reflect notify messages - for some messages sent by the child,
1571 * they send it back with the message code increased by OCM__BASE (0x2000).
1572 * This allows better subclassing of controls. We don't need to handle such
1573 * messages but we don't want to print ERRs for them, so this helper function
1574 * identifies them.
1575 *
1576 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1577 * colision with defined CCM_ codes.
1578 */
1579 BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
1580 {
1581 switch (uMsg)
1582 {
1583 case OCM__BASE + WM_COMMAND:
1584 case OCM__BASE + WM_CTLCOLORBTN:
1585 case OCM__BASE + WM_CTLCOLOREDIT:
1586 case OCM__BASE + WM_CTLCOLORDLG:
1587 case OCM__BASE + WM_CTLCOLORLISTBOX:
1588 case OCM__BASE + WM_CTLCOLORMSGBOX:
1589 case OCM__BASE + WM_CTLCOLORSCROLLBAR:
1590 case OCM__BASE + WM_CTLCOLORSTATIC:
1591 case OCM__BASE + WM_DRAWITEM:
1592 case OCM__BASE + WM_MEASUREITEM:
1593 case OCM__BASE + WM_DELETEITEM:
1594 case OCM__BASE + WM_VKEYTOITEM:
1595 case OCM__BASE + WM_CHARTOITEM:
1596 case OCM__BASE + WM_COMPAREITEM:
1597 case OCM__BASE + WM_HSCROLL:
1598 case OCM__BASE + WM_VSCROLL:
1599 case OCM__BASE + WM_PARENTNOTIFY:
1600 case OCM__BASE + WM_NOTIFY:
1601 return TRUE;
1602 default:
1603 return FALSE;
1604 }
1605 }
1606
1607 /***********************************************************************
1608 * MirrorIcon [COMCTL32.414]
1609 *
1610 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1611 *
1612 * PARAMS
1613 * phicon1 [I/O] Icon.
1614 * phicon2 [I/O] Icon.
1615 *
1616 * RETURNS
1617 * Success: TRUE.
1618 * Failure: FALSE.
1619 */
1620 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1621 {
1622 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1623 return FALSE;
1624 }
1625
1626 static inline int IsDelimiter(WCHAR c)
1627 {
1628 switch(c)
1629 {
1630 case '/':
1631 case '\\':
1632 case '.':
1633 case ' ':
1634 return TRUE;
1635 }
1636 return FALSE;
1637 }
1638
1639 static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1640 {
1641 if (code == WB_ISDELIMITER)
1642 return IsDelimiter(lpch[ichCurrent]);
1643 else
1644 {
1645 int dir = (code == WB_LEFT) ? -1 : 1;
1646 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1647 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1648 }
1649 return ichCurrent;
1650 }
1651
1652 /***********************************************************************
1653 * SetPathWordBreakProc [COMCTL32.384]
1654 *
1655 * Sets the word break procedure for an edit control to one that understands
1656 * paths so that the user can jump over directories.
1657 *
1658 * PARAMS
1659 * hwnd [I] Handle to edit control.
1660 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1661 *
1662 * RETURNS
1663 * Result from EM_SETWORDBREAKPROC message.
1664 */
1665 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1666 {
1667 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1668 (LPARAM)(bSet ? PathWordBreakProc : NULL));
1669 }
1670
1671 /***********************************************************************
1672 * DrawShadowText [COMCTL32.@]
1673 *
1674 * Draw text with shadow.
1675 */
1676 int WINAPI DrawShadowText(HDC hdc, LPCWSTR pszText, UINT cch, RECT *prc, DWORD dwFlags,
1677 COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset)
1678 {
1679 COLORREF crOldText;
1680 RECT rcText;
1681 INT iRet, x, y, x2, y2;
1682 BYTE *pBits;
1683 HBITMAP hbm, hbmOld;
1684 BITMAPINFO bi;
1685 HDC hdcMem;
1686 HFONT hOldFont;
1687 BLENDFUNCTION bf;
1688
1689 /* Create 32 bit DIB section for the shadow */
1690 ZeroMemory(&bi, sizeof(bi));
1691 bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
1692 bi.bmiHeader.biWidth = prc->right - prc->left + 4;
1693 bi.bmiHeader.biHeight = prc->bottom - prc->top + 5; // bottom-up DIB
1694 bi.bmiHeader.biPlanes = 1;
1695 bi.bmiHeader.biBitCount = 32;
1696 bi.bmiHeader.biCompression = BI_RGB;
1697 hbm = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, (PVOID*)&pBits, NULL, 0);
1698 if(!hbm)
1699 {
1700 ERR("CreateDIBSection failed\n");
1701 return 0;
1702 }
1703
1704 /* Create memory device context for new DIB section and select it */
1705 hdcMem = CreateCompatibleDC(hdc);
1706 if(!hdcMem)
1707 {
1708 ERR("CreateCompatibleDC failed\n");
1709 DeleteObject(hbm);
1710 return 0;
1711 }
1712
1713 hbmOld = (HBITMAP)SelectObject(hdcMem, hbm);
1714
1715 /* Draw text on our helper bitmap */
1716 hOldFont = (HFONT)SelectObject(hdcMem, GetCurrentObject(hdc, OBJ_FONT));
1717 SetTextColor(hdcMem, RGB(16, 16, 16));
1718 SetBkColor(hdcMem, RGB(0, 0, 0));
1719 SetBkMode(hdcMem, TRANSPARENT);
1720 SetRect(&rcText, 0, 0, prc->right - prc->left, prc->bottom - prc->top);
1721 DrawTextW(hdcMem, pszText, cch, &rcText, dwFlags);
1722 SelectObject(hdcMem, hOldFont);
1723
1724 /* Flush GDI so data pointed by pBits is valid */
1725 GdiFlush();
1726
1727 /* Set alpha of pixels (forget about colors for now. They will be changed in next loop).
1728 We copy text image 4*5 times and each time alpha is added */
1729 for (x = 0; x < bi.bmiHeader.biWidth; ++x)
1730 for (y = 0; y < bi.bmiHeader.biHeight; ++y)
1731 {
1732 BYTE *pDest = &pBits[(y * bi.bmiHeader.biWidth + x) * 4];
1733 UINT Alpha = 0;
1734
1735 for (x2 = x - 4 + 1; x2 <= x; ++x2)
1736 for (y2 = y; y2 < y + 5; ++y2)
1737 {
1738 if (x2 >= 0 && x2 < bi.bmiHeader.biWidth && y2 >= 0 && y2 < bi.bmiHeader.biHeight)
1739 {
1740 BYTE *pSrc = &pBits[(y2 * bi.bmiHeader.biWidth + x2) * 4];
1741 Alpha += pSrc[0];
1742 }
1743 }
1744
1745 if (Alpha > 255)
1746 Alpha = 255;
1747 pDest[3] = Alpha;
1748 }
1749
1750 /* Now set the color of each pixel to shadow color * alpha (see GdiAlphaBlend) */
1751 for (x = 0; x < bi.bmiHeader.biWidth; ++x)
1752 for (y = 0; y < bi.bmiHeader.biHeight; ++y)
1753 {
1754 BYTE *pDest = &pBits[(y * bi.bmiHeader.biWidth + x) * 4];
1755 pDest[0] = GetBValue(crShadow) * pDest[3] / 255;
1756 pDest[1] = GetGValue(crShadow) * pDest[3] / 255;
1757 pDest[2] = GetRValue(crShadow) * pDest[3] / 255;
1758 }
1759
1760 /* Fix ixOffset of the shadow (tested on Win) */
1761 ixOffset -= 3;
1762 iyOffset -= 3;
1763
1764 /* Alpha blend helper image to destination DC */
1765 bf.BlendOp = AC_SRC_OVER;
1766 bf.BlendFlags = 0;
1767 bf.SourceConstantAlpha = 255;
1768 bf.AlphaFormat = AC_SRC_ALPHA;
1769 if (!GdiAlphaBlend(hdc, prc->left + ixOffset, prc->top + iyOffset, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, hdcMem, 0, 0, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, bf))
1770 ERR("GdiAlphaBlend failed: %lu\n", GetLastError());
1771
1772 /* Delete the helper bitmap */
1773 SelectObject(hdcMem, hbmOld);
1774 DeleteObject(hbm);
1775 DeleteDC(hdcMem);
1776
1777 /* Finally draw the text over shadow */
1778 crOldText = SetTextColor(hdc, crText);
1779 SetBkMode(hdc, TRANSPARENT);
1780 iRet = DrawTextW(hdc, pszText, cch, prc, dwFlags);
1781 SetTextColor(hdc, crOldText);
1782
1783 return iRet;
1784 }
1785
1786 /***********************************************************************
1787 * TaskDialogIndirect [COMCTL32.@]
1788 */
1789 HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *pTaskConfig, int *pnButton,
1790 int *pnRadioButton, BOOL *pfVerificationFlagChecked)
1791 {
1792 UINT uType = 0;
1793 INT ret;
1794 FIXME("%p, %p, %p, %p\n", pTaskConfig, pnButton, pnRadioButton, pfVerificationFlagChecked);
1795
1796 if (pTaskConfig->dwCommonButtons & TDCBF_YES_BUTTON &&
1797 pTaskConfig->dwCommonButtons & TDCBF_NO_BUTTON &&
1798 pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
1799 uType |= MB_YESNOCANCEL;
1800 else
1801 if (pTaskConfig->dwCommonButtons & TDCBF_YES_BUTTON &&
1802 pTaskConfig->dwCommonButtons & TDCBF_NO_BUTTON)
1803 uType |= MB_YESNO;
1804 else
1805 if (pTaskConfig->dwCommonButtons & TDCBF_RETRY_BUTTON &&
1806 pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
1807 uType |= MB_RETRYCANCEL;
1808 else
1809 if (pTaskConfig->dwCommonButtons & TDCBF_OK_BUTTON &&
1810 pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
1811 uType |= MB_OKCANCEL;
1812 else
1813 if (pTaskConfig->dwCommonButtons & TDCBF_OK_BUTTON)
1814 uType |= MB_OK;
1815 ret = MessageBoxW(pTaskConfig->hwndParent, pTaskConfig->pszMainInstruction,
1816 pTaskConfig->pszWindowTitle, uType);
1817 FIXME("dwCommonButtons=%x uType=%x ret=%x\n", pTaskConfig->dwCommonButtons, uType, ret);
1818
1819 if (pnButton) *pnButton = ret;
1820 if (pnRadioButton) *pnRadioButton = pTaskConfig->nDefaultButton;
1821 if (pfVerificationFlagChecked) *pfVerificationFlagChecked = TRUE;
1822 return S_OK;
1823 }
1824
1825 /***********************************************************************
1826 * RegisterClassNameW [COMCTL32.@]
1827 *
1828 * Register window class again while using as SxS module.
1829 */
1830 BOOLEAN WINAPI RegisterClassNameW(LPCWSTR className)
1831 {
1832 /* FIXME: actually register redirected user32 class,
1833 comctl32 classes are registered by this module anyway */
1834 return TRUE;
1835 }