2 * Common controls functions
4 * Copyright 1997 Dimitrie O. Paun
5 * Copyright 1998,2000 Eric Kohl
6 * Copyright 2014-2015 Michael Müller
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.
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.
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
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.
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.
32 * -- implement GetMUILanguage + InitMUILanguage
33 * -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW
34 * -- FIXMEs + BUGS (search for them)
37 * -- ICC_ANIMATE_CLASS
42 * -- ICC_INTERNET_CLASSES
44 * -- ICC_LISTVIEW_CLASSES
45 * -- ICC_NATIVEFNTCTL_CLASS
46 * -- ICC_PAGESCROLLER_CLASS
47 * -- ICC_PROGRESS_CLASS
48 * -- ICC_STANDARD_CLASSES (not yet implemented)
50 * -- ICC_TREEVIEW_CLASSES
52 * -- ICC_USEREX_CLASSES
53 * -- ICC_WIN95_CLASSES
58 #define NO_SHLWAPI_STREAM
61 WINE_DEFAULT_DEBUG_CHANNEL(commctrl
);
63 static LRESULT WINAPI
COMCTL32_SubclassProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
65 static LPWSTR COMCTL32_wSubclass
= NULL
;
66 HMODULE COMCTL32_hModule
= 0;
67 static LANGID COMCTL32_uiLang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
68 HBRUSH COMCTL32_hPattern55AABrush
= NULL
;
69 COMCTL32_SysColor comctl32_color
;
71 static HBITMAP COMCTL32_hPattern55AABitmap
= NULL
;
73 static const WORD wPattern55AA
[] =
75 0x5555, 0xaaaa, 0x5555, 0xaaaa,
76 0x5555, 0xaaaa, 0x5555, 0xaaaa
79 static const WCHAR strCC32SubclassInfo
[] = {
80 'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
87 #define NAME L"microsoft.windows.common-controls"
88 #define VERSION_V5 L"5.82.2600.2982"
89 #define VERSION L"6.0.2600.2982"
90 #define PUBLIC_KEY L"6595b64144ccf1df"
94 #elif defined __x86_64__
100 static const WCHAR manifest_filename
[] = ARCH L
"_" NAME L
"_" PUBLIC_KEY L
"_" VERSION L
"_none_deadbeef.manifest";
101 static const WCHAR manifest_filename_v5
[] = ARCH L
"_" NAME L
"_" PUBLIC_KEY L
"_" VERSION_V5 L
"_none_deadbeef.manifest";
103 static WCHAR
* GetManifestPath(BOOL create
, BOOL bV6
)
108 pwszBuf
= HeapAlloc(GetProcessHeap(), 0, MAX_PATH
* sizeof(WCHAR
));
112 GetWindowsDirectoryW(pwszBuf
, MAX_PATH
);
113 hres
= StringCchCatW(pwszBuf
, MAX_PATH
, L
"\\winsxs");
117 CreateDirectoryW(pwszBuf
, NULL
);
118 hres
= StringCchCatW(pwszBuf
, MAX_PATH
, L
"\\manifests\\");
122 CreateDirectoryW(pwszBuf
, NULL
);
124 hres
= StringCchCatW(pwszBuf
, MAX_PATH
, bV6
? manifest_filename
: manifest_filename_v5
);
131 static BOOL
create_manifest(BOOL install
, BOOL bV6
)
137 DWORD cbManifest
, cbWritten
;
142 hResInfo
= FindResourceW(COMCTL32_hModule
, L
"WINE_MANIFEST", (LPWSTR
)RT_MANIFEST
);
144 hResInfo
= FindResourceW(COMCTL32_hModule
, L
"WINE_MANIFESTV5", (LPWSTR
)RT_MANIFEST
);
149 cbManifest
= SizeofResource(COMCTL32_hModule
, hResInfo
);
153 hResData
= LoadResource(COMCTL32_hModule
, hResInfo
);
157 pManifest
= LockResource(hResData
);
161 pwszBuf
= GetManifestPath(TRUE
, bV6
);
167 hFile
= CreateFileW(pwszBuf
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
168 if (hFile
!= INVALID_HANDLE_VALUE
)
170 if (WriteFile(hFile
, pManifest
, cbManifest
, &cbWritten
, NULL
) && cbWritten
== cbManifest
)
176 DeleteFileW(pwszBuf
);
178 TRACE("created %s\n", debugstr_w(pwszBuf
));
182 bRet
= DeleteFileW(pwszBuf
);
184 HeapFree(GetProcessHeap(), 0, pwszBuf
);
189 static HANDLE
CreateComctl32ActCtx(BOOL bV6
)
193 ACTCTXW ActCtx
= {sizeof(ACTCTX
)};
195 pwstrSource
= GetManifestPath(FALSE
, bV6
);
198 ERR("GetManifestPath failed! bV6=%d\n", bV6
);
199 return INVALID_HANDLE_VALUE
;
201 ActCtx
.lpSource
= pwstrSource
;
202 ret
= CreateActCtxW(&ActCtx
);
203 HeapFree(GetProcessHeap(), 0, pwstrSource
);
204 if (ret
== INVALID_HANDLE_VALUE
)
205 ERR("CreateActCtxW failed! bV6=%d\n", bV6
);
209 static void RegisterControls()
213 DATETIME_Register ();
217 IPADDRESS_Register ();
218 LISTVIEW_Register ();
219 MONTHCAL_Register ();
220 NATIVEFONT_Register ();
222 PROGRESS_Register ();
228 TOOLTIPS_Register ();
229 TRACKBAR_Register ();
230 TREEVIEW_Register ();
234 static void UnregisterControls()
236 ANIMATE_Unregister ();
237 COMBOEX_Unregister ();
238 DATETIME_Unregister ();
239 FLATSB_Unregister ();
240 HEADER_Unregister ();
241 HOTKEY_Unregister ();
242 IPADDRESS_Unregister ();
243 LISTVIEW_Unregister ();
244 MONTHCAL_Unregister ();
245 NATIVEFONT_Unregister ();
247 PROGRESS_Unregister ();
249 STATUS_Unregister ();
250 SYSLINK_Unregister ();
252 TOOLBAR_Unregister ();
253 TOOLTIPS_Unregister ();
254 TRACKBAR_Unregister ();
255 TREEVIEW_Unregister ();
256 UPDOWN_Unregister ();
259 static void InitializeClasses()
261 HANDLE hActCtx5
, hActCtx6
;
265 /* like comctl32 5.82+ register all the common control classes */
266 /* Register the classes once no matter what */
267 hActCtx5
= CreateComctl32ActCtx(FALSE
);
268 activated
= (hActCtx5
!= INVALID_HANDLE_VALUE
? ActivateActCtx(hActCtx5
, &ulCookie
) : FALSE
);
269 RegisterControls(); /* Register the classes pretending to be v5 */
270 if (activated
) DeactivateActCtx(0, ulCookie
);
272 hActCtx6
= CreateComctl32ActCtx(TRUE
);
273 if (hActCtx6
!= INVALID_HANDLE_VALUE
)
275 activated
= ActivateActCtx(hActCtx6
, &ulCookie
);
276 RegisterControls(); /* Register the classes pretending to be v6 */
277 if (activated
) DeactivateActCtx(0, ulCookie
);
279 /* Initialize the themed controls only when the v6 manifest is present */
280 THEMING_Initialize (hActCtx5
, hActCtx6
);
284 static void UninitializeClasses()
286 HANDLE hActCtx5
, hActCtx6
;
290 hActCtx5
= CreateComctl32ActCtx(FALSE
);
291 activated
= (hActCtx5
!= INVALID_HANDLE_VALUE
? ActivateActCtx(hActCtx5
, &ulCookie
) : FALSE
);
292 UnregisterControls();
293 if (activated
) DeactivateActCtx(0, ulCookie
);
295 hActCtx6
= CreateComctl32ActCtx(TRUE
);
296 if (hActCtx6
!= INVALID_HANDLE_VALUE
)
298 activated
= ActivateActCtx(hActCtx6
, &ulCookie
);
299 THEMING_Uninitialize();
300 UnregisterControls();
301 if (activated
) DeactivateActCtx(0, ulCookie
);
305 /***********************************************************************
306 * RegisterClassNameW [COMCTL32.@]
308 * Register window class again while using as SxS module.
310 BOOLEAN WINAPI
RegisterClassNameW(LPCWSTR className
)
318 /***********************************************************************
321 * Initializes the internal 'COMCTL32.DLL'.
324 * hinstDLL [I] handle to the 'dlls' instance
326 * lpvReserved [I] reserved, must be NULL
333 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
335 TRACE("%p,%x,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
338 case DLL_PROCESS_ATTACH
:
339 DisableThreadLibraryCalls(hinstDLL
);
341 COMCTL32_hModule
= hinstDLL
;
343 /* add global subclassing atom (used by 'tooltip' and 'updown') */
344 COMCTL32_wSubclass
= (LPWSTR
)(DWORD_PTR
)GlobalAddAtomW (strCC32SubclassInfo
);
345 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass
);
347 /* create local pattern brush */
348 COMCTL32_hPattern55AABitmap
= CreateBitmap (8, 8, 1, 1, wPattern55AA
);
349 COMCTL32_hPattern55AABrush
= CreatePatternBrush (COMCTL32_hPattern55AABitmap
);
351 /* Get all the colors at DLL load */
352 COMCTL32_RefreshSysColors();
355 /* like comctl32 5.82+ register all the common control classes */
358 DATETIME_Register ();
362 IPADDRESS_Register ();
363 LISTVIEW_Register ();
364 MONTHCAL_Register ();
365 NATIVEFONT_Register ();
367 PROGRESS_Register ();
373 TOOLTIPS_Register ();
374 TRACKBAR_Register ();
375 TREEVIEW_Register ();
378 /* subclass user32 controls */
379 THEMING_Initialize ();
386 case DLL_PROCESS_DETACH
:
387 if (lpvReserved
) break;
389 /* clean up subclassing */
390 THEMING_Uninitialize();
392 /* unregister all common control classes */
393 ANIMATE_Unregister ();
394 COMBOEX_Unregister ();
395 DATETIME_Unregister ();
396 FLATSB_Unregister ();
397 HEADER_Unregister ();
398 HOTKEY_Unregister ();
399 IPADDRESS_Unregister ();
400 LISTVIEW_Unregister ();
401 MONTHCAL_Unregister ();
402 NATIVEFONT_Unregister ();
404 PROGRESS_Unregister ();
406 STATUS_Unregister ();
407 SYSLINK_Unregister ();
409 TOOLBAR_Unregister ();
410 TOOLTIPS_Unregister ();
411 TRACKBAR_Unregister ();
412 TREEVIEW_Unregister ();
413 UPDOWN_Unregister ();
415 UninitializeClasses();
417 /* delete local pattern brush */
418 DeleteObject (COMCTL32_hPattern55AABrush
);
419 DeleteObject (COMCTL32_hPattern55AABitmap
);
421 /* delete global subclassing atom */
422 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass
));
423 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass
);
431 /***********************************************************************
432 * MenuHelp [COMCTL32.2]
434 * Handles the setting of status bar help messages when the user
435 * selects menu items.
438 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
439 * wParam [I] wParam of the message uMsg
440 * lParam [I] lParam of the message uMsg
441 * hMainMenu [I] handle to the application's main menu
442 * hInst [I] handle to the module that contains string resources
443 * hwndStatus [I] handle to the status bar window
444 * lpwIDs [I] pointer to an array of integers (see NOTES)
450 * The official documentation is incomplete!
451 * This is the correct documentation:
454 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
455 * WM_MENUSELECT messages.
458 * (will be written ...)
462 MenuHelp (UINT uMsg
, WPARAM wParam
, LPARAM lParam
, HMENU hMainMenu
,
463 HINSTANCE hInst
, HWND hwndStatus
, UINT
* lpwIDs
)
467 if (!IsWindow (hwndStatus
))
472 TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
475 if ((HIWORD(wParam
) == 0xFFFF) && (lParam
== 0)) {
476 /* menu was closed */
477 TRACE("menu was closed!\n");
478 SendMessageW (hwndStatus
, SB_SIMPLE
, FALSE
, 0);
481 /* menu item was selected */
482 if (HIWORD(wParam
) & MF_POPUP
)
483 uMenuID
= *(lpwIDs
+1);
485 uMenuID
= (UINT
)LOWORD(wParam
);
486 TRACE("uMenuID = %u\n", uMenuID
);
491 if (!LoadStringW (hInst
, uMenuID
, szText
, sizeof(szText
)/sizeof(szText
[0])))
494 SendMessageW (hwndStatus
, SB_SETTEXTW
,
495 255 | SBT_NOBORDERS
, (LPARAM
)szText
);
496 SendMessageW (hwndStatus
, SB_SIMPLE
, TRUE
, 0);
502 TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
504 /* WM_COMMAND is not invalid since it is documented
505 * in the windows api reference. So don't output
506 * any FIXME for WM_COMMAND
508 WARN("We don't care about the WM_COMMAND\n");
512 FIXME("Invalid Message 0x%x!\n", uMsg
);
518 /***********************************************************************
519 * ShowHideMenuCtl [COMCTL32.3]
521 * Shows or hides controls and updates the corresponding menu item.
524 * hwnd [I] handle to the client window.
525 * uFlags [I] menu command id.
526 * lpInfo [I] pointer to an array of integers. (See NOTES.)
533 * The official documentation is incomplete!
534 * This is the correct documentation:
537 * Handle to the window that contains the menu and controls.
540 * Identifier of the menu item to receive or lose a check mark.
543 * The array of integers contains pairs of values. BOTH values of
544 * the first pair must be the handles to the application's main menu.
545 * Each subsequent pair consists of a menu id and control id.
549 ShowHideMenuCtl (HWND hwnd
, UINT_PTR uFlags
, LPINT lpInfo
)
553 TRACE("%p, %lx, %p\n", hwnd
, uFlags
, lpInfo
);
558 if (!(lpInfo
[0]) || !(lpInfo
[1]))
561 /* search for control */
562 lpMenuId
= &lpInfo
[2];
563 while (*lpMenuId
!= uFlags
)
566 if (GetMenuState ((HMENU
)(DWORD_PTR
)lpInfo
[1], uFlags
, MF_BYCOMMAND
) & MFS_CHECKED
) {
567 /* uncheck menu item */
568 CheckMenuItem ((HMENU
)(DWORD_PTR
)lpInfo
[0], *lpMenuId
, MF_BYCOMMAND
| MF_UNCHECKED
);
572 SetWindowPos (GetDlgItem (hwnd
, *lpMenuId
), 0, 0, 0, 0, 0,
576 /* check menu item */
577 CheckMenuItem ((HMENU
)(DWORD_PTR
)lpInfo
[0], *lpMenuId
, MF_BYCOMMAND
| MF_CHECKED
);
581 SetWindowPos (GetDlgItem (hwnd
, *lpMenuId
), 0, 0, 0, 0, 0,
589 /***********************************************************************
590 * GetEffectiveClientRect [COMCTL32.4]
592 * Calculates the coordinates of a rectangle in the client area.
595 * hwnd [I] handle to the client window.
596 * lpRect [O] pointer to the rectangle of the client window
597 * lpInfo [I] pointer to an array of integers (see NOTES)
603 * The official documentation is incomplete!
604 * This is the correct documentation:
607 * (will be written ...)
611 GetEffectiveClientRect (HWND hwnd
, LPRECT lpRect
, const INT
*lpInfo
)
617 TRACE("(%p %p %p)\n",
618 hwnd
, lpRect
, lpInfo
);
620 GetClientRect (hwnd
, lpRect
);
628 hwndCtrl
= GetDlgItem (hwnd
, *lpRun
);
629 if (GetWindowLongW (hwndCtrl
, GWL_STYLE
) & WS_VISIBLE
) {
630 TRACE("control id 0x%x\n", *lpRun
);
631 GetWindowRect (hwndCtrl
, &rcCtrl
);
632 MapWindowPoints (NULL
, hwnd
, (LPPOINT
)&rcCtrl
, 2);
633 SubtractRect (lpRect
, lpRect
, &rcCtrl
);
640 /***********************************************************************
641 * DrawStatusTextW [COMCTL32.@]
643 * Draws text with borders, like in a status bar.
646 * hdc [I] handle to the window's display context
647 * lprc [I] pointer to a rectangle
648 * text [I] pointer to the text
649 * style [I] drawing style
655 * The style variable can have one of the following values:
656 * (will be written ...)
659 void WINAPI
DrawStatusTextW (HDC hdc
, LPCRECT lprc
, LPCWSTR text
, UINT style
)
662 UINT border
= BDR_SUNKENOUTER
;
664 if (style
& SBT_POPOUT
)
665 border
= BDR_RAISEDOUTER
;
666 else if (style
& SBT_NOBORDERS
)
669 DrawEdge (hdc
, &r
, border
, BF_RECT
|BF_ADJUST
);
673 int oldbkmode
= SetBkMode (hdc
, TRANSPARENT
);
674 UINT align
= DT_LEFT
;
677 if (style
& SBT_RTLREADING
)
678 FIXME("Unsupported RTL style!\n");
683 DrawTextW (hdc
, text
- strCnt
, strCnt
, &r
, align
|DT_VCENTER
|DT_SINGLELINE
|DT_NOPREFIX
);
686 if (align
==DT_RIGHT
) {
689 align
= (align
==DT_LEFT
? DT_CENTER
: DT_RIGHT
);
695 if (strCnt
) DrawTextW (hdc
, text
- strCnt
, -1, &r
, align
|DT_VCENTER
|DT_SINGLELINE
|DT_NOPREFIX
);
696 SetBkMode(hdc
, oldbkmode
);
701 /***********************************************************************
702 * DrawStatusText [COMCTL32.@]
703 * DrawStatusTextA [COMCTL32.5]
705 * Draws text with borders, like in a status bar.
708 * hdc [I] handle to the window's display context
709 * lprc [I] pointer to a rectangle
710 * text [I] pointer to the text
711 * style [I] drawing style
717 void WINAPI
DrawStatusTextA (HDC hdc
, LPCRECT lprc
, LPCSTR text
, UINT style
)
723 if ( (len
= MultiByteToWideChar( CP_ACP
, 0, text
, -1, NULL
, 0 )) ) {
724 if ( (textW
= Alloc( len
* sizeof(WCHAR
) )) )
725 MultiByteToWideChar( CP_ACP
, 0, text
, -1, textW
, len
);
728 DrawStatusTextW( hdc
, lprc
, textW
, style
);
733 /***********************************************************************
734 * CreateStatusWindow [COMCTL32.@]
735 * CreateStatusWindowA [COMCTL32.6]
737 * Creates a status bar
740 * style [I] window style
741 * text [I] pointer to the window text
742 * parent [I] handle to the parent window
743 * wid [I] control id of the status bar
746 * Success: handle to the status window
751 CreateStatusWindowA (LONG style
, LPCSTR text
, HWND parent
, UINT wid
)
753 return CreateWindowA(STATUSCLASSNAMEA
, text
, style
,
754 CW_USEDEFAULT
, CW_USEDEFAULT
,
755 CW_USEDEFAULT
, CW_USEDEFAULT
,
756 parent
, (HMENU
)(DWORD_PTR
)wid
, 0, 0);
760 /***********************************************************************
761 * CreateStatusWindowW [COMCTL32.@]
763 * Creates a status bar control
766 * style [I] window style
767 * text [I] pointer to the window text
768 * parent [I] handle to the parent window
769 * wid [I] control id of the status bar
772 * Success: handle to the status window
777 CreateStatusWindowW (LONG style
, LPCWSTR text
, HWND parent
, UINT wid
)
779 return CreateWindowW(STATUSCLASSNAMEW
, text
, style
,
780 CW_USEDEFAULT
, CW_USEDEFAULT
,
781 CW_USEDEFAULT
, CW_USEDEFAULT
,
782 parent
, (HMENU
)(DWORD_PTR
)wid
, 0, 0);
786 /***********************************************************************
787 * CreateUpDownControl [COMCTL32.16]
789 * Creates an up-down control
792 * style [I] window styles
793 * x [I] horizontal position of the control
794 * y [I] vertical position of the control
795 * cx [I] with of the control
796 * cy [I] height of the control
797 * parent [I] handle to the parent window
798 * id [I] the control's identifier
799 * inst [I] handle to the application's module instance
800 * buddy [I] handle to the buddy window, can be NULL
801 * maxVal [I] upper limit of the control
802 * minVal [I] lower limit of the control
803 * curVal [I] current value of the control
806 * Success: handle to the updown control
811 CreateUpDownControl (DWORD style
, INT x
, INT y
, INT cx
, INT cy
,
812 HWND parent
, INT id
, HINSTANCE inst
,
813 HWND buddy
, INT maxVal
, INT minVal
, INT curVal
)
816 CreateWindowW (UPDOWN_CLASSW
, 0, style
, x
, y
, cx
, cy
,
817 parent
, (HMENU
)(DWORD_PTR
)id
, inst
, 0);
819 SendMessageW (hUD
, UDM_SETBUDDY
, (WPARAM
)buddy
, 0);
820 SendMessageW (hUD
, UDM_SETRANGE
, 0, MAKELONG(maxVal
, minVal
));
821 SendMessageW (hUD
, UDM_SETPOS
, 0, MAKELONG(curVal
, 0));
828 /***********************************************************************
829 * InitCommonControls [COMCTL32.17]
831 * Registers the common controls.
840 * This function is just a dummy - all the controls are registered at
841 * the DLL initialization time. See InitCommonContolsEx for details.
845 InitCommonControls (void)
850 /***********************************************************************
851 * InitCommonControlsEx [COMCTL32.@]
853 * Registers the common controls.
856 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
863 * Probably all versions of comctl32 initializes the Win95 controls in DllMain
864 * during DLL initialization. Starting from comctl32 v5.82 all the controls
865 * are initialized there. We follow this behaviour and this function is just
868 * Note: when writing programs under Windows, if you don't call any function
869 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
870 * was the only comctl32 function you were calling and you remove it you may
871 * have a false impression that InitCommonControlsEx actually did something.
875 InitCommonControlsEx (const INITCOMMONCONTROLSEX
*lpInitCtrls
)
877 if (!lpInitCtrls
|| lpInitCtrls
->dwSize
!= sizeof(INITCOMMONCONTROLSEX
))
880 TRACE("(0x%08x)\n", lpInitCtrls
->dwICC
);
885 /***********************************************************************
886 * CreateToolbarEx [COMCTL32.@]
888 * Creates a toolbar window.
906 * Success: handle to the tool bar control
911 CreateToolbarEx (HWND hwnd
, DWORD style
, UINT wID
, INT nBitmaps
,
912 HINSTANCE hBMInst
, UINT_PTR wBMID
, LPCTBBUTTON lpButtons
,
913 INT iNumButtons
, INT dxButton
, INT dyButton
,
914 INT dxBitmap
, INT dyBitmap
, UINT uStructSize
)
919 CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
, style
|WS_CHILD
, 0,0,100,30,
920 hwnd
, (HMENU
)(DWORD_PTR
)wID
, COMCTL32_hModule
, NULL
);
924 SendMessageW (hwndTB
, TB_BUTTONSTRUCTSIZE
, uStructSize
, 0);
926 /* set bitmap and button size */
927 /*If CreateToolbarEx receives 0, windows sets default values*/
932 if (dxBitmap
== 0 || dyBitmap
== 0)
933 dxBitmap
= dyBitmap
= 16;
934 SendMessageW(hwndTB
, TB_SETBITMAPSIZE
, 0, MAKELPARAM(dxBitmap
, dyBitmap
));
940 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
941 if (dxButton
!= 0 && dyButton
!= 0)
942 SendMessageW(hwndTB
, TB_SETBITMAPSIZE
, 0, MAKELPARAM(dxButton
, dyButton
));
946 if (nBitmaps
> 0 || hBMInst
== HINST_COMMCTRL
)
948 tbab
.hInst
= hBMInst
;
951 SendMessageW (hwndTB
, TB_ADDBITMAP
, nBitmaps
, (LPARAM
)&tbab
);
955 SendMessageW (hwndTB
, TB_ADDBUTTONSW
, iNumButtons
, (LPARAM
)lpButtons
);
962 /***********************************************************************
963 * CreateMappedBitmap [COMCTL32.8]
965 * Loads a bitmap resource using a colour map.
968 * hInstance [I] Handle to the module containing the bitmap.
969 * idBitmap [I] The bitmap resource ID.
970 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
971 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
972 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
975 * Success: handle to the new bitmap
980 CreateMappedBitmap (HINSTANCE hInstance
, INT_PTR idBitmap
, UINT wFlags
,
981 LPCOLORMAP lpColorMap
, INT iNumMaps
)
985 const BITMAPINFOHEADER
*lpBitmap
;
986 LPBITMAPINFOHEADER lpBitmapInfo
;
987 UINT nSize
, nColorTableSize
, iColor
;
988 RGBQUAD
*pColorTable
;
989 INT i
, iMaps
, nWidth
, nHeight
;
992 LPCOLORMAP sysColorMap
;
994 COLORMAP internalColorMap
[4] =
995 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
997 /* initialize pointer to colortable and default color table */
1000 sysColorMap
= lpColorMap
;
1003 internalColorMap
[0].to
= GetSysColor (COLOR_BTNTEXT
);
1004 internalColorMap
[1].to
= GetSysColor (COLOR_BTNSHADOW
);
1005 internalColorMap
[2].to
= GetSysColor (COLOR_BTNFACE
);
1006 internalColorMap
[3].to
= GetSysColor (COLOR_BTNHIGHLIGHT
);
1008 sysColorMap
= internalColorMap
;
1011 hRsrc
= FindResourceW (hInstance
, (LPWSTR
)idBitmap
, (LPWSTR
)RT_BITMAP
);
1014 hglb
= LoadResource (hInstance
, hRsrc
);
1017 lpBitmap
= LockResource (hglb
);
1018 if (lpBitmap
== NULL
)
1021 if (lpBitmap
->biSize
>= sizeof(BITMAPINFOHEADER
) && lpBitmap
->biClrUsed
)
1022 nColorTableSize
= lpBitmap
->biClrUsed
;
1023 else if (lpBitmap
->biBitCount
<= 8)
1024 nColorTableSize
= (1 << lpBitmap
->biBitCount
);
1026 nColorTableSize
= 0;
1027 nSize
= lpBitmap
->biSize
;
1028 if (nSize
== sizeof(BITMAPINFOHEADER
) && lpBitmap
->biCompression
== BI_BITFIELDS
)
1029 nSize
+= 3 * sizeof(DWORD
);
1030 nSize
+= nColorTableSize
* sizeof(RGBQUAD
);
1031 lpBitmapInfo
= GlobalAlloc (GMEM_FIXED
, nSize
);
1032 if (lpBitmapInfo
== NULL
)
1034 RtlMoveMemory (lpBitmapInfo
, lpBitmap
, nSize
);
1036 pColorTable
= (RGBQUAD
*)(((LPBYTE
)lpBitmapInfo
) + lpBitmapInfo
->biSize
);
1038 for (iColor
= 0; iColor
< nColorTableSize
; iColor
++) {
1039 for (i
= 0; i
< iMaps
; i
++) {
1040 cRef
= RGB(pColorTable
[iColor
].rgbRed
,
1041 pColorTable
[iColor
].rgbGreen
,
1042 pColorTable
[iColor
].rgbBlue
);
1043 if ( cRef
== sysColorMap
[i
].from
) {
1045 if (wFlags
& CBS_MASKED
) {
1046 if (sysColorMap
[i
].to
!= COLOR_BTNTEXT
)
1047 pColorTable
[iColor
] = RGB(255, 255, 255);
1051 pColorTable
[iColor
].rgbBlue
= GetBValue(sysColorMap
[i
].to
);
1052 pColorTable
[iColor
].rgbGreen
= GetGValue(sysColorMap
[i
].to
);
1053 pColorTable
[iColor
].rgbRed
= GetRValue(sysColorMap
[i
].to
);
1058 nWidth
= lpBitmapInfo
->biWidth
;
1059 nHeight
= lpBitmapInfo
->biHeight
;
1060 hdcScreen
= GetDC (NULL
);
1061 hbm
= CreateCompatibleBitmap (hdcScreen
, nWidth
, nHeight
);
1063 HDC hdcDst
= CreateCompatibleDC (hdcScreen
);
1064 HBITMAP hbmOld
= SelectObject (hdcDst
, hbm
);
1065 const BYTE
*lpBits
= (const BYTE
*)lpBitmap
+ nSize
;
1066 StretchDIBits (hdcDst
, 0, 0, nWidth
, nHeight
, 0, 0, nWidth
, nHeight
,
1067 lpBits
, (LPBITMAPINFO
)lpBitmapInfo
, DIB_RGB_COLORS
,
1069 SelectObject (hdcDst
, hbmOld
);
1072 ReleaseDC (NULL
, hdcScreen
);
1073 GlobalFree (lpBitmapInfo
);
1074 FreeResource (hglb
);
1080 /***********************************************************************
1081 * CreateToolbar [COMCTL32.7]
1083 * Creates a toolbar control.
1096 * Success: handle to the tool bar control
1100 * Do not use this function anymore. Use CreateToolbarEx instead.
1104 CreateToolbar (HWND hwnd
, DWORD style
, UINT wID
, INT nBitmaps
,
1105 HINSTANCE hBMInst
, UINT wBMID
,
1106 LPCTBBUTTON lpButtons
,INT iNumButtons
)
1108 return CreateToolbarEx (hwnd
, style
| CCS_NODIVIDER
, wID
, nBitmaps
,
1109 hBMInst
, wBMID
, lpButtons
,
1110 iNumButtons
, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON
, dwData
));
1114 /***********************************************************************
1115 * DllGetVersion [COMCTL32.@]
1117 * Retrieves version information of the 'COMCTL32.DLL'
1120 * pdvi [O] pointer to version information structure.
1124 * Failure: E_INVALIDARG
1127 * Returns version of a comctl32.dll from IE4.01 SP1.
1130 HRESULT WINAPI
DllGetVersion (DLLVERSIONINFO
*pdvi
)
1132 if (pdvi
->cbSize
!= sizeof(DLLVERSIONINFO
)) {
1133 WARN("wrong DLLVERSIONINFO size from app\n");
1134 return E_INVALIDARG
;
1137 pdvi
->dwMajorVersion
= COMCTL32_VERSION
;
1138 pdvi
->dwMinorVersion
= COMCTL32_VERSION_MINOR
;
1139 pdvi
->dwBuildNumber
= 2919;
1140 pdvi
->dwPlatformID
= 6304;
1142 TRACE("%u.%u.%u.%u\n",
1143 pdvi
->dwMajorVersion
, pdvi
->dwMinorVersion
,
1144 pdvi
->dwBuildNumber
, pdvi
->dwPlatformID
);
1149 /***********************************************************************
1150 * DllInstall (COMCTL32.@)
1152 * Installs the ComCtl32 DLL.
1156 * Failure: A HRESULT error
1158 HRESULT WINAPI
DllInstall(BOOL bInstall
, LPCWSTR cmdline
)
1160 TRACE("(%u, %s): stub\n", bInstall
, debugstr_w(cmdline
));
1164 if (!create_manifest(bInstall
, TRUE
))
1166 ERR("Failed to install comctl32 v6 manifest!\n");
1167 return HRESULT_FROM_WIN32(GetLastError());
1170 if (!create_manifest(bInstall
, FALSE
))
1172 ERR("Failed to install comctl32 v5 manifest!\n");
1173 return HRESULT_FROM_WIN32(GetLastError());
1180 /***********************************************************************
1181 * _TrackMouseEvent [COMCTL32.@]
1183 * Requests notification of mouse events
1185 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1186 * to the hwnd specified in the ptme structure. After the event message
1187 * is posted to the hwnd, the entry in the queue is removed.
1189 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1190 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1191 * immediately and the TME_LEAVE flag being ignored.
1194 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1200 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1205 _TrackMouseEvent (TRACKMOUSEEVENT
*ptme
)
1207 return TrackMouseEvent (ptme
);
1210 /*************************************************************************
1211 * GetMUILanguage [COMCTL32.@]
1213 * Returns the user interface language in use by the current process.
1216 * Language ID in use by the current process.
1218 LANGID WINAPI
GetMUILanguage (VOID
)
1220 return COMCTL32_uiLang
;
1224 /*************************************************************************
1225 * InitMUILanguage [COMCTL32.@]
1227 * Sets the user interface language to be used by the current process.
1232 VOID WINAPI
InitMUILanguage (LANGID uiLang
)
1234 COMCTL32_uiLang
= uiLang
;
1238 /***********************************************************************
1239 * SetWindowSubclass [COMCTL32.410]
1241 * Starts a window subclass
1244 * hWnd [in] handle to window subclass.
1245 * pfnSubclass [in] Pointer to new window procedure.
1246 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1247 * dwRef [in] Reference data to pass to window procedure.
1254 * If an application manually subclasses a window after subclassing it with
1255 * this API and then with this API again, then none of the previous
1256 * subclasses get called or the original window procedure.
1259 BOOL WINAPI
SetWindowSubclass (HWND hWnd
, SUBCLASSPROC pfnSubclass
,
1260 UINT_PTR uIDSubclass
, DWORD_PTR dwRef
)
1262 LPSUBCLASS_INFO stack
;
1263 LPSUBCLASSPROCS proc
;
1265 TRACE ("(%p, %p, %lx, %lx)\n", hWnd
, pfnSubclass
, uIDSubclass
, dwRef
);
1267 /* Since the window procedure that we set here has two additional arguments,
1268 * we can't simply set it as the new window procedure of the window. So we
1269 * set our own window procedure and then calculate the other two arguments
1272 /* See if we have been called for this window */
1273 stack
= GetPropW (hWnd
, COMCTL32_wSubclass
);
1275 /* allocate stack */
1276 stack
= Alloc (sizeof(SUBCLASS_INFO
));
1278 ERR ("Failed to allocate our Subclassing stack\n");
1281 SetPropW (hWnd
, COMCTL32_wSubclass
, stack
);
1283 /* set window procedure to our own and save the current one */
1284 if (IsWindowUnicode (hWnd
))
1285 stack
->origproc
= (WNDPROC
)SetWindowLongPtrW (hWnd
, GWLP_WNDPROC
,
1286 (DWORD_PTR
)COMCTL32_SubclassProc
);
1288 stack
->origproc
= (WNDPROC
)SetWindowLongPtrA (hWnd
, GWLP_WNDPROC
,
1289 (DWORD_PTR
)COMCTL32_SubclassProc
);
1292 /* Check to see if we have called this function with the same uIDSubClass
1293 * and pfnSubclass */
1294 proc
= stack
->SubclassProcs
;
1296 if ((proc
->id
== uIDSubclass
) &&
1297 (proc
->subproc
== pfnSubclass
)) {
1305 proc
= Alloc(sizeof(SUBCLASSPROCS
));
1307 ERR ("Failed to allocate subclass entry in stack\n");
1308 if (IsWindowUnicode (hWnd
))
1309 SetWindowLongPtrW (hWnd
, GWLP_WNDPROC
, (DWORD_PTR
)stack
->origproc
);
1311 SetWindowLongPtrA (hWnd
, GWLP_WNDPROC
, (DWORD_PTR
)stack
->origproc
);
1313 RemovePropW( hWnd
, COMCTL32_wSubclass
);
1317 proc
->subproc
= pfnSubclass
;
1319 proc
->id
= uIDSubclass
;
1320 proc
->next
= stack
->SubclassProcs
;
1321 stack
->SubclassProcs
= proc
;
1327 /***********************************************************************
1328 * GetWindowSubclass [COMCTL32.411]
1330 * Gets the Reference data from a subclass.
1333 * hWnd [in] Handle to the window which we are subclassing
1334 * pfnSubclass [in] Pointer to the subclass procedure
1335 * uID [in] Unique identifier of the subclassing procedure
1336 * pdwRef [out] Pointer to the reference data
1343 BOOL WINAPI
GetWindowSubclass (HWND hWnd
, SUBCLASSPROC pfnSubclass
,
1344 UINT_PTR uID
, DWORD_PTR
*pdwRef
)
1346 const SUBCLASS_INFO
*stack
;
1347 const SUBCLASSPROCS
*proc
;
1349 TRACE ("(%p, %p, %lx, %p)\n", hWnd
, pfnSubclass
, uID
, pdwRef
);
1351 /* See if we have been called for this window */
1352 stack
= GetPropW (hWnd
, COMCTL32_wSubclass
);
1356 proc
= stack
->SubclassProcs
;
1358 if ((proc
->id
== uID
) &&
1359 (proc
->subproc
== pfnSubclass
)) {
1360 *pdwRef
= proc
->ref
;
1370 /***********************************************************************
1371 * RemoveWindowSubclass [COMCTL32.412]
1373 * Removes a window subclass.
1376 * hWnd [in] Handle to the window which we are subclassing
1377 * pfnSubclass [in] Pointer to the subclass procedure
1378 * uID [in] Unique identifier of this subclass
1385 BOOL WINAPI
RemoveWindowSubclass(HWND hWnd
, SUBCLASSPROC pfnSubclass
, UINT_PTR uID
)
1387 LPSUBCLASS_INFO stack
;
1388 LPSUBCLASSPROCS prevproc
= NULL
;
1389 LPSUBCLASSPROCS proc
;
1392 TRACE ("(%p, %p, %lx)\n", hWnd
, pfnSubclass
, uID
);
1394 /* Find the Subclass to remove */
1395 stack
= GetPropW (hWnd
, COMCTL32_wSubclass
);
1399 proc
= stack
->SubclassProcs
;
1401 if ((proc
->id
== uID
) &&
1402 (proc
->subproc
== pfnSubclass
)) {
1405 stack
->SubclassProcs
= proc
->next
;
1407 prevproc
->next
= proc
->next
;
1409 if (stack
->stackpos
== proc
)
1410 stack
->stackpos
= stack
->stackpos
->next
;
1420 if (!stack
->SubclassProcs
&& !stack
->running
) {
1421 TRACE("Last Subclass removed, cleaning up\n");
1422 /* clean up our heap and reset the original window procedure */
1423 if (IsWindowUnicode (hWnd
))
1424 SetWindowLongPtrW (hWnd
, GWLP_WNDPROC
, (DWORD_PTR
)stack
->origproc
);
1426 SetWindowLongPtrA (hWnd
, GWLP_WNDPROC
, (DWORD_PTR
)stack
->origproc
);
1428 RemovePropW( hWnd
, COMCTL32_wSubclass
);
1434 /***********************************************************************
1435 * COMCTL32_SubclassProc (internal)
1437 * Window procedure for all subclassed windows.
1438 * Saves the current subclassing stack position to support nested messages
1440 static LRESULT WINAPI
COMCTL32_SubclassProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1442 LPSUBCLASS_INFO stack
;
1443 LPSUBCLASSPROCS proc
;
1446 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd
, uMsg
, wParam
, lParam
);
1448 stack
= GetPropW (hWnd
, COMCTL32_wSubclass
);
1450 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd
);
1454 /* Save our old stackpos to properly handle nested messages */
1455 proc
= stack
->stackpos
;
1456 stack
->stackpos
= stack
->SubclassProcs
;
1458 ret
= DefSubclassProc(hWnd
, uMsg
, wParam
, lParam
);
1460 stack
->stackpos
= proc
;
1462 if (!stack
->SubclassProcs
&& !stack
->running
) {
1463 TRACE("Last Subclass removed, cleaning up\n");
1464 /* clean up our heap and reset the original window procedure */
1465 if (IsWindowUnicode (hWnd
))
1466 SetWindowLongPtrW (hWnd
, GWLP_WNDPROC
, (DWORD_PTR
)stack
->origproc
);
1468 SetWindowLongPtrA (hWnd
, GWLP_WNDPROC
, (DWORD_PTR
)stack
->origproc
);
1470 RemovePropW( hWnd
, COMCTL32_wSubclass
);
1475 /***********************************************************************
1476 * DefSubclassProc [COMCTL32.413]
1478 * Calls the next window procedure (i.e. the one before this subclass)
1481 * hWnd [in] The window that we're subclassing
1483 * wParam [in] WPARAM
1484 * lParam [in] LPARAM
1491 LRESULT WINAPI
DefSubclassProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1493 LPSUBCLASS_INFO stack
;
1496 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd
, uMsg
, wParam
, lParam
);
1498 /* retrieve our little stack from the Properties */
1499 stack
= GetPropW (hWnd
, COMCTL32_wSubclass
);
1501 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd
);
1505 /* If we are at the end of stack then we have to call the original
1506 * window procedure */
1507 if (!stack
->stackpos
) {
1508 if (IsWindowUnicode (hWnd
))
1509 ret
= CallWindowProcW (stack
->origproc
, hWnd
, uMsg
, wParam
, lParam
);
1511 ret
= CallWindowProcA (stack
->origproc
, hWnd
, uMsg
, wParam
, lParam
);
1513 const SUBCLASSPROCS
*proc
= stack
->stackpos
;
1514 stack
->stackpos
= stack
->stackpos
->next
;
1515 /* call the Subclass procedure from the stack */
1516 ret
= proc
->subproc (hWnd
, uMsg
, wParam
, lParam
,
1517 proc
->id
, proc
->ref
);
1524 /***********************************************************************
1525 * COMCTL32_CreateToolTip [NOT AN API]
1527 * Creates a tooltip for the control specified in hwnd and does all
1528 * necessary setup and notifications.
1531 * hwndOwner [I] Handle to the window that will own the tool tip.
1534 * Success: Handle of tool tip window.
1539 COMCTL32_CreateToolTip(HWND hwndOwner
)
1543 hwndToolTip
= CreateWindowExW(0, TOOLTIPS_CLASSW
, NULL
, WS_POPUP
,
1544 CW_USEDEFAULT
, CW_USEDEFAULT
,
1545 CW_USEDEFAULT
, CW_USEDEFAULT
, hwndOwner
,
1548 /* Send NM_TOOLTIPSCREATED notification */
1551 NMTOOLTIPSCREATED nmttc
;
1552 /* true owner can be different if hwndOwner is a child window */
1553 HWND hwndTrueOwner
= GetWindow(hwndToolTip
, GW_OWNER
);
1554 nmttc
.hdr
.hwndFrom
= hwndTrueOwner
;
1555 nmttc
.hdr
.idFrom
= GetWindowLongPtrW(hwndTrueOwner
, GWLP_ID
);
1556 nmttc
.hdr
.code
= NM_TOOLTIPSCREATED
;
1557 nmttc
.hwndToolTips
= hwndToolTip
;
1559 SendMessageW(GetParent(hwndTrueOwner
), WM_NOTIFY
,
1560 GetWindowLongPtrW(hwndTrueOwner
, GWLP_ID
), (LPARAM
)&nmttc
);
1567 /***********************************************************************
1568 * COMCTL32_RefreshSysColors [NOT AN API]
1570 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1571 * refresh the color values in the color structure
1581 COMCTL32_RefreshSysColors(void)
1583 comctl32_color
.clrBtnHighlight
= GetSysColor (COLOR_BTNHIGHLIGHT
);
1584 comctl32_color
.clrBtnShadow
= GetSysColor (COLOR_BTNSHADOW
);
1585 comctl32_color
.clrBtnText
= GetSysColor (COLOR_BTNTEXT
);
1586 comctl32_color
.clrBtnFace
= GetSysColor (COLOR_BTNFACE
);
1587 comctl32_color
.clrHighlight
= GetSysColor (COLOR_HIGHLIGHT
);
1588 comctl32_color
.clrHighlightText
= GetSysColor (COLOR_HIGHLIGHTTEXT
);
1589 comctl32_color
.clrHotTrackingColor
= GetSysColor (COLOR_HOTLIGHT
);
1590 comctl32_color
.clr3dHilight
= GetSysColor (COLOR_3DHILIGHT
);
1591 comctl32_color
.clr3dShadow
= GetSysColor (COLOR_3DSHADOW
);
1592 comctl32_color
.clr3dDkShadow
= GetSysColor (COLOR_3DDKSHADOW
);
1593 comctl32_color
.clr3dFace
= GetSysColor (COLOR_3DFACE
);
1594 comctl32_color
.clrWindow
= GetSysColor (COLOR_WINDOW
);
1595 comctl32_color
.clrWindowText
= GetSysColor (COLOR_WINDOWTEXT
);
1596 comctl32_color
.clrGrayText
= GetSysColor (COLOR_GRAYTEXT
);
1597 comctl32_color
.clrActiveCaption
= GetSysColor (COLOR_ACTIVECAPTION
);
1598 comctl32_color
.clrInfoBk
= GetSysColor (COLOR_INFOBK
);
1599 comctl32_color
.clrInfoText
= GetSysColor (COLOR_INFOTEXT
);
1602 /***********************************************************************
1603 * COMCTL32_DrawInsertMark [NOT AN API]
1605 * Draws an insertion mark (which looks similar to an 'I').
1608 * hDC [I] Device context to draw onto.
1609 * lpRect [I] Co-ordinates of insertion mark.
1610 * clrInsertMark [I] Colour of the insertion mark.
1611 * bHorizontal [I] True if insert mark should be drawn horizontally,
1612 * vertical otherwise.
1618 * Draws up to but not including the bottom co-ordinate when drawing
1619 * vertically or the right co-ordinate when horizontal.
1621 void COMCTL32_DrawInsertMark(HDC hDC
, const RECT
*lpRect
, COLORREF clrInsertMark
, BOOL bHorizontal
)
1623 HPEN hPen
= CreatePen(PS_SOLID
, 1, clrInsertMark
);
1625 static const DWORD adwPolyPoints
[] = {4,4,4};
1626 LONG lCentre
= (bHorizontal
?
1627 lpRect
->top
+ (lpRect
->bottom
- lpRect
->top
)/2 :
1628 lpRect
->left
+ (lpRect
->right
- lpRect
->left
)/2);
1629 LONG l1
= (bHorizontal
? lpRect
->left
: lpRect
->top
);
1630 LONG l2
= (bHorizontal
? lpRect
->right
: lpRect
->bottom
);
1631 const POINT aptInsertMark
[] =
1633 /* top (V) or left (H) arrow */
1637 {lCentre
+ 1, l1
+ 2},
1641 {lCentre
+ 1, l1
- 1},
1642 {lCentre
+ 1, l2
- 2},
1643 /* bottom (V) or right (H) arrow */
1645 {lCentre
- 2, l2
- 1},
1646 {lCentre
+ 3, l2
- 1},
1647 {lCentre
+ 1, l2
- 3},
1649 hOldPen
= SelectObject(hDC
, hPen
);
1650 PolyPolyline(hDC
, aptInsertMark
, adwPolyPoints
, sizeof(adwPolyPoints
)/sizeof(adwPolyPoints
[0]));
1651 SelectObject(hDC
, hOldPen
);
1655 /***********************************************************************
1656 * COMCTL32_EnsureBitmapSize [internal]
1658 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1659 * the height is at least cyMinHeight. If the bitmap already has these
1660 * dimensions nothing changes.
1663 * hBitmap [I/O] Bitmap to modify. The handle may change
1664 * cxMinWidth [I] If the width of the bitmap is smaller, then it will
1665 * be enlarged to this value
1666 * cyMinHeight [I] If the height of the bitmap is smaller, then it will
1667 * be enlarged to this value
1668 * cyBackground [I] The color with which the new area will be filled
1673 void COMCTL32_EnsureBitmapSize(HBITMAP
*pBitmap
, int cxMinWidth
, int cyMinHeight
, COLORREF crBackground
)
1678 HBITMAP hNewDCBitmap
, hOldDCBitmap
;
1682 if (!GetObjectW(*pBitmap
, sizeof(BITMAP
), &bmp
))
1684 cxNew
= (cxMinWidth
> bmp
.bmWidth
? cxMinWidth
: bmp
.bmWidth
);
1685 cyNew
= (cyMinHeight
> bmp
.bmHeight
? cyMinHeight
: bmp
.bmHeight
);
1686 if (cxNew
== bmp
.bmWidth
&& cyNew
== bmp
.bmHeight
)
1689 hdcNew
= CreateCompatibleDC(NULL
);
1690 hNewBitmap
= CreateBitmap(cxNew
, cyNew
, bmp
.bmPlanes
, bmp
.bmBitsPixel
, NULL
);
1691 hNewDCBitmap
= SelectObject(hdcNew
, hNewBitmap
);
1692 hNewDCBrush
= SelectObject(hdcNew
, CreateSolidBrush(crBackground
));
1694 hdcOld
= CreateCompatibleDC(NULL
);
1695 hOldDCBitmap
= SelectObject(hdcOld
, *pBitmap
);
1697 BitBlt(hdcNew
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, hdcOld
, 0, 0, SRCCOPY
);
1698 if (bmp
.bmWidth
< cxMinWidth
)
1699 PatBlt(hdcNew
, bmp
.bmWidth
, 0, cxNew
, bmp
.bmHeight
, PATCOPY
);
1700 if (bmp
.bmHeight
< cyMinHeight
)
1701 PatBlt(hdcNew
, 0, bmp
.bmHeight
, bmp
.bmWidth
, cyNew
, PATCOPY
);
1702 if (bmp
.bmWidth
< cxMinWidth
&& bmp
.bmHeight
< cyMinHeight
)
1703 PatBlt(hdcNew
, bmp
.bmWidth
, bmp
.bmHeight
, cxNew
, cyNew
, PATCOPY
);
1705 SelectObject(hdcNew
, hNewDCBitmap
);
1706 DeleteObject(SelectObject(hdcNew
, hNewDCBrush
));
1708 SelectObject(hdcOld
, hOldDCBitmap
);
1711 DeleteObject(*pBitmap
);
1712 *pBitmap
= hNewBitmap
;
1716 void COMCTL32_GetFontMetrics(HFONT hFont
, TEXTMETRICW
*ptm
)
1718 HDC hdc
= GetDC(NULL
);
1721 hOldFont
= SelectObject(hdc
, hFont
);
1722 GetTextMetricsW(hdc
, ptm
);
1723 SelectObject(hdc
, hOldFont
);
1724 ReleaseDC(NULL
, hdc
);
1727 #ifndef OCM__BASE /* avoid including olectl.h */
1728 #define OCM__BASE (WM_USER+0x1c00)
1731 /***********************************************************************
1732 * COMCTL32_IsReflectedMessage [internal]
1734 * Some parents reflect notify messages - for some messages sent by the child,
1735 * they send it back with the message code increased by OCM__BASE (0x2000).
1736 * This allows better subclassing of controls. We don't need to handle such
1737 * messages but we don't want to print ERRs for them, so this helper function
1740 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1741 * collision with defined CCM_ codes.
1743 BOOL
COMCTL32_IsReflectedMessage(UINT uMsg
)
1747 case OCM__BASE
+ WM_COMMAND
:
1748 case OCM__BASE
+ WM_CTLCOLORBTN
:
1749 case OCM__BASE
+ WM_CTLCOLOREDIT
:
1750 case OCM__BASE
+ WM_CTLCOLORDLG
:
1751 case OCM__BASE
+ WM_CTLCOLORLISTBOX
:
1752 case OCM__BASE
+ WM_CTLCOLORMSGBOX
:
1753 case OCM__BASE
+ WM_CTLCOLORSCROLLBAR
:
1754 case OCM__BASE
+ WM_CTLCOLORSTATIC
:
1755 case OCM__BASE
+ WM_DRAWITEM
:
1756 case OCM__BASE
+ WM_MEASUREITEM
:
1757 case OCM__BASE
+ WM_DELETEITEM
:
1758 case OCM__BASE
+ WM_VKEYTOITEM
:
1759 case OCM__BASE
+ WM_CHARTOITEM
:
1760 case OCM__BASE
+ WM_COMPAREITEM
:
1761 case OCM__BASE
+ WM_HSCROLL
:
1762 case OCM__BASE
+ WM_VSCROLL
:
1763 case OCM__BASE
+ WM_PARENTNOTIFY
:
1764 case OCM__BASE
+ WM_NOTIFY
:
1771 /***********************************************************************
1772 * MirrorIcon [COMCTL32.414]
1774 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1777 * phicon1 [I/O] Icon.
1778 * phicon2 [I/O] Icon.
1784 BOOL WINAPI
MirrorIcon(HICON
*phicon1
, HICON
*phicon2
)
1786 FIXME("(%p, %p): stub\n", phicon1
, phicon2
);
1790 static inline BOOL
IsDelimiter(WCHAR c
)
1803 static int CALLBACK
PathWordBreakProc(LPCWSTR lpch
, int ichCurrent
, int cch
, int code
)
1805 if (code
== WB_ISDELIMITER
)
1806 return IsDelimiter(lpch
[ichCurrent
]);
1809 int dir
= (code
== WB_LEFT
) ? -1 : 1;
1810 for(; 0 <= ichCurrent
&& ichCurrent
< cch
; ichCurrent
+= dir
)
1811 if (IsDelimiter(lpch
[ichCurrent
])) return ichCurrent
;
1816 /***********************************************************************
1817 * SetPathWordBreakProc [COMCTL32.384]
1819 * Sets the word break procedure for an edit control to one that understands
1820 * paths so that the user can jump over directories.
1823 * hwnd [I] Handle to edit control.
1824 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1827 * Result from EM_SETWORDBREAKPROC message.
1829 LRESULT WINAPI
SetPathWordBreakProc(HWND hwnd
, BOOL bSet
)
1831 return SendMessageW(hwnd
, EM_SETWORDBREAKPROC
, 0,
1832 (LPARAM
)(bSet
? PathWordBreakProc
: NULL
));
1835 /***********************************************************************
1836 * DrawShadowText [COMCTL32.@]
1838 * Draw text with shadow.
1840 int WINAPI
DrawShadowText(HDC hdc
, LPCWSTR pszText
, UINT cch
, RECT
*prc
, DWORD dwFlags
,
1841 COLORREF crText
, COLORREF crShadow
, int ixOffset
, int iyOffset
)
1845 INT iRet
, x
, y
, x2
, y2
;
1847 HBITMAP hbm
, hbmOld
;
1853 /* Create 32 bit DIB section for the shadow */
1854 ZeroMemory(&bi
, sizeof(bi
));
1855 bi
.bmiHeader
.biSize
= sizeof(bi
.bmiHeader
);
1856 bi
.bmiHeader
.biWidth
= prc
->right
- prc
->left
+ 4;
1857 bi
.bmiHeader
.biHeight
= prc
->bottom
- prc
->top
+ 5; // bottom-up DIB
1858 bi
.bmiHeader
.biPlanes
= 1;
1859 bi
.bmiHeader
.biBitCount
= 32;
1860 bi
.bmiHeader
.biCompression
= BI_RGB
;
1861 hbm
= CreateDIBSection(hdc
, &bi
, DIB_RGB_COLORS
, (PVOID
*)&pBits
, NULL
, 0);
1864 ERR("CreateDIBSection failed\n");
1868 /* Create memory device context for new DIB section and select it */
1869 hdcMem
= CreateCompatibleDC(hdc
);
1872 ERR("CreateCompatibleDC failed\n");
1877 hbmOld
= (HBITMAP
)SelectObject(hdcMem
, hbm
);
1879 /* Draw text on our helper bitmap */
1880 hOldFont
= (HFONT
)SelectObject(hdcMem
, GetCurrentObject(hdc
, OBJ_FONT
));
1881 SetTextColor(hdcMem
, RGB(16, 16, 16));
1882 SetBkColor(hdcMem
, RGB(0, 0, 0));
1883 SetBkMode(hdcMem
, TRANSPARENT
);
1884 SetRect(&rcText
, 0, 0, prc
->right
- prc
->left
, prc
->bottom
- prc
->top
);
1885 DrawTextW(hdcMem
, pszText
, cch
, &rcText
, dwFlags
);
1886 SelectObject(hdcMem
, hOldFont
);
1888 /* Flush GDI so data pointed by pBits is valid */
1891 /* Set alpha of pixels (forget about colors for now. They will be changed in next loop).
1892 We copy text image 4*5 times and each time alpha is added */
1893 for (x
= 0; x
< bi
.bmiHeader
.biWidth
; ++x
)
1894 for (y
= 0; y
< bi
.bmiHeader
.biHeight
; ++y
)
1896 BYTE
*pDest
= &pBits
[(y
* bi
.bmiHeader
.biWidth
+ x
) * 4];
1899 for (x2
= x
- 4 + 1; x2
<= x
; ++x2
)
1900 for (y2
= y
; y2
< y
+ 5; ++y2
)
1902 if (x2
>= 0 && x2
< bi
.bmiHeader
.biWidth
&& y2
>= 0 && y2
< bi
.bmiHeader
.biHeight
)
1904 BYTE
*pSrc
= &pBits
[(y2
* bi
.bmiHeader
.biWidth
+ x2
) * 4];
1914 /* Now set the color of each pixel to shadow color * alpha (see GdiAlphaBlend) */
1915 for (x
= 0; x
< bi
.bmiHeader
.biWidth
; ++x
)
1916 for (y
= 0; y
< bi
.bmiHeader
.biHeight
; ++y
)
1918 BYTE
*pDest
= &pBits
[(y
* bi
.bmiHeader
.biWidth
+ x
) * 4];
1919 pDest
[0] = GetBValue(crShadow
) * pDest
[3] / 255;
1920 pDest
[1] = GetGValue(crShadow
) * pDest
[3] / 255;
1921 pDest
[2] = GetRValue(crShadow
) * pDest
[3] / 255;
1924 /* Fix ixOffset of the shadow (tested on Win) */
1928 /* Alpha blend helper image to destination DC */
1929 bf
.BlendOp
= AC_SRC_OVER
;
1931 bf
.SourceConstantAlpha
= 255;
1932 bf
.AlphaFormat
= AC_SRC_ALPHA
;
1933 if (!GdiAlphaBlend(hdc
, prc
->left
+ ixOffset
, prc
->top
+ iyOffset
, bi
.bmiHeader
.biWidth
, bi
.bmiHeader
.biHeight
, hdcMem
, 0, 0, bi
.bmiHeader
.biWidth
, bi
.bmiHeader
.biHeight
, bf
))
1934 ERR("GdiAlphaBlend failed: %lu\n", GetLastError());
1936 /* Delete the helper bitmap */
1937 SelectObject(hdcMem
, hbmOld
);
1941 /* Finally draw the text over shadow */
1942 crOldText
= SetTextColor(hdc
, crText
);
1943 SetBkMode(hdc
, TRANSPARENT
);
1944 iRet
= DrawTextW(hdc
, pszText
, cch
, prc
, dwFlags
);
1945 SetTextColor(hdc
, crOldText
);
1950 /***********************************************************************
1951 * TaskDialogIndirect [COMCTL32.@]
1953 HRESULT WINAPI
TaskDialogIndirect(const TASKDIALOGCONFIG
*pTaskConfig
, int *pnButton
,
1954 int *pnRadioButton
, BOOL
*pfVerificationFlagChecked
)
1958 FIXME("%p, %p, %p, %p\n", pTaskConfig
, pnButton
, pnRadioButton
, pfVerificationFlagChecked
);
1960 if (pTaskConfig
->dwCommonButtons
& TDCBF_YES_BUTTON
&&
1961 pTaskConfig
->dwCommonButtons
& TDCBF_NO_BUTTON
&&
1962 pTaskConfig
->dwCommonButtons
& TDCBF_CANCEL_BUTTON
)
1963 uType
|= MB_YESNOCANCEL
;
1965 if (pTaskConfig
->dwCommonButtons
& TDCBF_YES_BUTTON
&&
1966 pTaskConfig
->dwCommonButtons
& TDCBF_NO_BUTTON
)
1969 if (pTaskConfig
->dwCommonButtons
& TDCBF_RETRY_BUTTON
&&
1970 pTaskConfig
->dwCommonButtons
& TDCBF_CANCEL_BUTTON
)
1971 uType
|= MB_RETRYCANCEL
;
1973 if (pTaskConfig
->dwCommonButtons
& TDCBF_OK_BUTTON
&&
1974 pTaskConfig
->dwCommonButtons
& TDCBF_CANCEL_BUTTON
)
1975 uType
|= MB_OKCANCEL
;
1977 if (pTaskConfig
->dwCommonButtons
& TDCBF_OK_BUTTON
)
1979 ret
= MessageBoxW(pTaskConfig
->hwndParent
, pTaskConfig
->pszMainInstruction
,
1980 pTaskConfig
->pszWindowTitle
, uType
);
1981 FIXME("dwCommonButtons=%x uType=%x ret=%x\n", pTaskConfig
->dwCommonButtons
, uType
, ret
);
1983 if (pnButton
) *pnButton
= ret
;
1984 if (pnRadioButton
) *pnRadioButton
= pTaskConfig
->nDefaultButton
;
1985 if (pfVerificationFlagChecked
) *pfVerificationFlagChecked
= TRUE
;
1989 /***********************************************************************
1990 * LoadIconWithScaleDown [COMCTL32.@]
1992 HRESULT WINAPI
LoadIconWithScaleDown(HINSTANCE hinst
, const WCHAR
*name
, int cx
, int cy
, HICON
*icon
)
1994 TRACE("(%p, %s, %d, %d, %p)\n", hinst
, debugstr_w(name
), cx
, cy
, icon
);
1999 return E_INVALIDARG
;
2001 *icon
= LoadImageW(hinst
, name
, IMAGE_ICON
, cx
, cy
,
2002 (hinst
|| IS_INTRESOURCE(name
)) ? 0 : LR_LOADFROMFILE
);
2004 return HRESULT_FROM_WIN32(GetLastError());
2009 /***********************************************************************
2010 * LoadIconMetric [COMCTL32.@]
2012 HRESULT WINAPI
LoadIconMetric(HINSTANCE hinst
, const WCHAR
*name
, int size
, HICON
*icon
)
2016 TRACE("(%p, %s, %d, %p)\n", hinst
, debugstr_w(name
), size
, icon
);
2018 if (size
== LIM_SMALL
)
2020 cx
= GetSystemMetrics(SM_CXSMICON
);
2021 cy
= GetSystemMetrics(SM_CYSMICON
);
2023 else if (size
== LIM_LARGE
)
2025 cx
= GetSystemMetrics(SM_CXICON
);
2026 cy
= GetSystemMetrics(SM_CYICON
);
2031 return E_INVALIDARG
;
2034 return LoadIconWithScaleDown(hinst
, name
, cx
, cy
, icon
);