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