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