xref: /reactos/dll/win32/comctl32/commctrl.c (revision c2c66aff)
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 }
2016