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