2 * Common controls functions
4 * Copyright 1997 Dimitrie O. Paun
5 * Copyright 1998,2000 Eric Kohl
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * This code was audited for completeness against the documented features
24 * of Comctl32.dll version 6.0 on Oct. 21, 2002, by Christian Neumair.
26 * Unless otherwise noted, we believe this code to be complete, as per
27 * the specification mentioned above.
28 * If you discover missing features, or bugs, please note them below.
31 * -- implement GetMUILanguage + InitMUILanguage
32 * -- LibMain => DLLMain ("DLLMain takes over the functionality of both the
33 * LibMain and the WEP function.", MSDN)
34 * -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW
35 * -- FIXMEs + BUGS (search for them)
38 * -- ICC_ANIMATE_CLASS
43 * -- ICC_INTERNET_CLASSES
45 * -- ICC_LISTVIEW_CLASSES
46 * -- ICC_NATIVEFNTCTL_CLASS
47 * -- ICC_PAGESCROLLER_CLASS
48 * -- ICC_PROGRESS_CLASS
49 * -- ICC_STANDARD_CLASSES (not yet implemented)
51 * -- ICC_TREEVIEW_CLASSES
53 * -- ICC_USEREX_CLASSES
54 * -- ICC_WIN95_CLASSES
69 #define NO_SHLWAPI_STREAM
72 #include "wine/debug.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
76 LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
78 LPWSTR COMCTL32_wSubclass = NULL;
79 HMODULE COMCTL32_hModule = 0;
80 LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
81 HBRUSH COMCTL32_hPattern55AABrush = NULL;
82 COMCTL32_SysColor comctl32_color;
84 static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
86 static const WORD wPattern55AA[] =
88 0x5555, 0xaaaa, 0x5555, 0xaaaa,
89 0x5555, 0xaaaa, 0x5555, 0xaaaa
92 static const WCHAR strCC32SubclassInfo[] = {
93 'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
96 /***********************************************************************
99 * Initializes the internal 'COMCTL32.DLL'.
102 * hinstDLL [I] handle to the 'dlls' instance
104 * lpvReserved [I] reserverd, must be NULL
111 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
113 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
116 case DLL_PROCESS_ATTACH:
117 DisableThreadLibraryCalls(hinstDLL);
119 COMCTL32_hModule = (HMODULE)hinstDLL;
121 /* add global subclassing atom (used by 'tooltip' and 'updown') */
122 COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
123 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
125 /* create local pattern brush */
126 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
127 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
129 /* Get all the colors at DLL load */
130 COMCTL32_RefreshSysColors();
132 /* register all Win95 common control classes */
137 LISTVIEW_Register ();
138 PROGRESS_Register ();
143 TOOLTIPS_Register ();
144 TRACKBAR_Register ();
145 TREEVIEW_Register ();
148 /* subclass user32 controls */
149 THEMING_Initialize ();
152 case DLL_PROCESS_DETACH:
153 /* clean up subclassing */
154 THEMING_Uninitialize();
156 /* unregister all common control classes */
157 ANIMATE_Unregister ();
158 COMBOEX_Unregister ();
159 DATETIME_Unregister ();
160 FLATSB_Unregister ();
161 HEADER_Unregister ();
162 HOTKEY_Unregister ();
163 IPADDRESS_Unregister ();
164 LISTVIEW_Unregister ();
165 MONTHCAL_Unregister ();
166 NATIVEFONT_Unregister ();
168 PROGRESS_Unregister ();
170 STATUS_Unregister ();
171 SYSLINK_Unregister ();
173 TOOLBAR_Unregister ();
174 TOOLTIPS_Unregister ();
175 TRACKBAR_Unregister ();
176 TREEVIEW_Unregister ();
177 UPDOWN_Unregister ();
179 /* delete local pattern brush */
180 DeleteObject (COMCTL32_hPattern55AABrush);
181 COMCTL32_hPattern55AABrush = NULL;
182 DeleteObject (COMCTL32_hPattern55AABitmap);
183 COMCTL32_hPattern55AABitmap = NULL;
185 /* delete global subclassing atom */
186 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
187 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
188 COMCTL32_wSubclass = NULL;
196 /***********************************************************************
197 * MenuHelp [COMCTL32.2]
199 * Handles the setting of status bar help messages when the user
200 * selects menu items.
203 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
204 * wParam [I] wParam of the message uMsg
205 * lParam [I] lParam of the message uMsg
206 * hMainMenu [I] handle to the application's main menu
207 * hInst [I] handle to the module that contains string resources
208 * hwndStatus [I] handle to the status bar window
209 * lpwIDs [I] pointer to an array of integers (see NOTES)
215 * The official documentation is incomplete!
216 * This is the correct documentation:
219 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
220 * WM_MENUSELECT messages.
223 * (will be written ...)
227 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
228 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
232 if (!IsWindow (hwndStatus))
237 TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n",
240 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
241 /* menu was closed */
242 TRACE("menu was closed!\n");
243 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
246 /* menu item was selected */
247 if (HIWORD(wParam) & MF_POPUP)
248 uMenuID = (UINT)*(lpwIDs+1);
250 uMenuID = (UINT)LOWORD(wParam);
251 TRACE("uMenuID = %u\n", uMenuID);
256 if (!LoadStringW (hInst, uMenuID, szText, sizeof(szText)/sizeof(szText[0])))
259 SendMessageW (hwndStatus, SB_SETTEXTW,
260 255 | SBT_NOBORDERS, (LPARAM)szText);
261 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
267 TRACE("WM_COMMAND wParam=0x%X lParam=0x%lX\n",
269 /* WM_COMMAND is not invalid since it is documented
270 * in the windows api reference. So don't output
271 * any FIXME for WM_COMMAND
273 WARN("We don't care about the WM_COMMAND\n");
277 FIXME("Invalid Message 0x%x!\n", uMsg);
283 /***********************************************************************
284 * ShowHideMenuCtl [COMCTL32.3]
286 * Shows or hides controls and updates the corresponding menu item.
289 * hwnd [I] handle to the client window.
290 * uFlags [I] menu command id.
291 * lpInfo [I] pointer to an array of integers. (See NOTES.)
298 * The official documentation is incomplete!
299 * This is the correct documentation:
302 * Handle to the window that contains the menu and controls.
305 * Identifier of the menu item to receive or lose a check mark.
308 * The array of integers contains pairs of values. BOTH values of
309 * the first pair must be the handles to the application's main menu.
310 * Each subsequent pair consists of a menu id and control id.
314 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
318 TRACE("%p, %x, %p\n", hwnd, uFlags, lpInfo);
323 if (!(lpInfo[0]) || !(lpInfo[1]))
326 /* search for control */
327 lpMenuId = &lpInfo[2];
328 while (*lpMenuId != uFlags)
331 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
332 /* uncheck menu item */
333 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
337 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
341 /* check menu item */
342 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
346 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
354 /***********************************************************************
355 * GetEffectiveClientRect [COMCTL32.4]
357 * Calculates the coordinates of a rectangle in the client area.
360 * hwnd [I] handle to the client window.
361 * lpRect [O] pointer to the rectangle of the client window
362 * lpInfo [I] pointer to an array of integers (see NOTES)
368 * The official documentation is incomplete!
369 * This is the correct documentation:
372 * (will be written ...)
376 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo)
382 TRACE("(%p %p %p)\n",
383 hwnd, lpRect, lpInfo);
385 GetClientRect (hwnd, lpRect);
393 hwndCtrl = GetDlgItem (hwnd, *lpRun);
394 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
395 TRACE("control id 0x%x\n", *lpRun);
396 GetWindowRect (hwndCtrl, &rcCtrl);
397 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
398 SubtractRect (lpRect, lpRect, &rcCtrl);
405 /***********************************************************************
406 * DrawStatusTextW [COMCTL32.@]
408 * Draws text with borders, like in a status bar.
411 * hdc [I] handle to the window's display context
412 * lprc [I] pointer to a rectangle
413 * text [I] pointer to the text
414 * style [I] drawing style
420 * The style variable can have one of the following values:
421 * (will be written ...)
424 void WINAPI DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style)
427 UINT border = BDR_SUNKENOUTER;
429 if (style & SBT_POPOUT)
430 border = BDR_RAISEDOUTER;
431 else if (style & SBT_NOBORDERS)
434 DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
438 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
439 UINT align = DT_LEFT;
440 if (*text == L'\t') {
443 if (*text == L'\t') {
449 if (style & SBT_RTLREADING)
450 FIXME("Unsupported RTL style!\n");
451 DrawTextW (hdc, text, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
452 SetBkMode(hdc, oldbkmode);
457 /***********************************************************************
458 * DrawStatusText [COMCTL32.@]
459 * DrawStatusTextA [COMCTL32.5]
461 * Draws text with borders, like in a status bar.
464 * hdc [I] handle to the window's display context
465 * lprc [I] pointer to a rectangle
466 * text [I] pointer to the text
467 * style [I] drawing style
473 void WINAPI DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style)
479 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
480 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
481 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
484 DrawStatusTextW( hdc, lprc, textW, style );
489 /***********************************************************************
490 * CreateStatusWindow [COMCTL32.@]
491 * CreateStatusWindowA [COMCTL32.6]
493 * Creates a status bar
496 * style [I] window style
497 * text [I] pointer to the window text
498 * parent [I] handle to the parent window
499 * wid [I] control id of the status bar
502 * Success: handle to the status window
507 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
509 return CreateWindowA(STATUSCLASSNAMEA, text, style,
510 CW_USEDEFAULT, CW_USEDEFAULT,
511 CW_USEDEFAULT, CW_USEDEFAULT,
512 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
516 /***********************************************************************
517 * CreateStatusWindowW [COMCTL32.@]
519 * Creates a status bar control
522 * style [I] window style
523 * text [I] pointer to the window text
524 * parent [I] handle to the parent window
525 * wid [I] control id of the status bar
528 * Success: handle to the status window
533 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
535 return CreateWindowW(STATUSCLASSNAMEW, text, style,
536 CW_USEDEFAULT, CW_USEDEFAULT,
537 CW_USEDEFAULT, CW_USEDEFAULT,
538 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
542 /***********************************************************************
543 * CreateUpDownControl [COMCTL32.16]
545 * Creates an up-down control
548 * style [I] window styles
549 * x [I] horizontal position of the control
550 * y [I] vertical position of the control
551 * cx [I] with of the control
552 * cy [I] height of the control
553 * parent [I] handle to the parent window
554 * id [I] the control's identifier
555 * inst [I] handle to the application's module instance
556 * buddy [I] handle to the buddy window, can be NULL
557 * maxVal [I] upper limit of the control
558 * minVal [I] lower limit of the control
559 * curVal [I] current value of the control
562 * Success: handle to the updown control
567 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
568 HWND parent, INT id, HINSTANCE inst,
569 HWND buddy, INT maxVal, INT minVal, INT curVal)
572 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
573 parent, (HMENU)(DWORD_PTR)id, inst, 0);
575 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
576 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
577 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
584 /***********************************************************************
585 * InitCommonControls [COMCTL32.17]
587 * Registers the common controls.
596 * This function is just a dummy.
597 * The Win95 controls are registered at the DLL's initialization.
598 * To register other controls InitCommonControlsEx() must be used.
602 InitCommonControls (void)
607 /***********************************************************************
608 * InitCommonControlsEx [COMCTL32.@]
610 * Registers the common controls.
613 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
620 * Only the additional common controls are registered by this function.
621 * The Win95 controls are registered at the DLL's initialization.
624 * implement the following control classes:
626 * ICC_STANDARD_CLASSES
630 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
637 if (lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
640 TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
642 for (cCount = 0; cCount < 32; cCount++) {
643 dwMask = 1 << cCount;
644 if (!(lpInitCtrls->dwICC & dwMask))
647 switch (lpInitCtrls->dwICC & dwMask) {
648 /* dummy initialization */
649 case ICC_ANIMATE_CLASS:
650 case ICC_BAR_CLASSES:
651 case ICC_LISTVIEW_CLASSES:
652 case ICC_TREEVIEW_CLASSES:
653 case ICC_TAB_CLASSES:
654 case ICC_UPDOWN_CLASS:
655 case ICC_PROGRESS_CLASS:
656 case ICC_HOTKEY_CLASS:
659 /* advanced classes - not included in Win95 */
660 case ICC_DATE_CLASSES:
661 MONTHCAL_Register ();
662 DATETIME_Register ();
665 case ICC_USEREX_CLASSES:
669 case ICC_COOL_CLASSES:
673 case ICC_INTERNET_CLASSES:
674 IPADDRESS_Register ();
677 case ICC_PAGESCROLLER_CLASS:
681 case ICC_NATIVEFNTCTL_CLASS:
682 NATIVEFONT_Register ();
690 FIXME("Unknown class! dwICC=0x%X\n", dwMask);
699 /***********************************************************************
700 * CreateToolbarEx [COMCTL32.@]
702 * Creates a toolbar window.
720 * Success: handle to the tool bar control
725 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
726 HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons,
727 INT iNumButtons, INT dxButton, INT dyButton,
728 INT dxBitmap, INT dyBitmap, UINT uStructSize)
733 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
734 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
738 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM)uStructSize, 0);
740 /* set bitmap and button size */
741 /*If CreateToolbarEx receives 0, windows sets default values*/
746 SendMessageW (hwndTB, TB_SETBITMAPSIZE, 0,
747 MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap));
753 SendMessageW (hwndTB, TB_SETBUTTONSIZE, 0,
754 MAKELPARAM((WORD)dxButton, (WORD)dyButton));
760 tbab.hInst = hBMInst;
763 SendMessageW (hwndTB, TB_ADDBITMAP, (WPARAM)nBitmaps, (LPARAM)&tbab);
767 SendMessageW (hwndTB, TB_ADDBUTTONSW,
768 (WPARAM)iNumButtons, (LPARAM)lpButtons);
775 /***********************************************************************
776 * CreateMappedBitmap [COMCTL32.8]
778 * Loads a bitmap resource using a colour map.
781 * hInstance [I] Handle to the module containing the bitmap.
782 * idBitmap [I] The bitmap resource ID.
783 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
784 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
785 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
788 * Success: handle to the new bitmap
793 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
794 LPCOLORMAP lpColorMap, INT iNumMaps)
798 LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
799 UINT nSize, nColorTableSize, iColor;
800 RGBQUAD *pColorTable;
801 INT i, iMaps, nWidth, nHeight;
804 LPCOLORMAP sysColorMap;
806 COLORMAP internalColorMap[4] =
807 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
809 /* initialize pointer to colortable and default color table */
812 sysColorMap = lpColorMap;
815 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
816 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
817 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
818 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
820 sysColorMap = (LPCOLORMAP)internalColorMap;
823 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
826 hglb = LoadResource (hInstance, hRsrc);
829 lpBitmap = (LPBITMAPINFOHEADER)LockResource (hglb);
830 if (lpBitmap == NULL)
833 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
834 nColorTableSize = lpBitmap->biClrUsed;
835 else if (lpBitmap->biBitCount <= 8)
836 nColorTableSize = (1 << lpBitmap->biBitCount);
839 nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
840 lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize);
841 if (lpBitmapInfo == NULL)
843 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
845 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)lpBitmapInfo->biSize);
847 for (iColor = 0; iColor < nColorTableSize; iColor++) {
848 for (i = 0; i < iMaps; i++) {
849 cRef = RGB(pColorTable[iColor].rgbRed,
850 pColorTable[iColor].rgbGreen,
851 pColorTable[iColor].rgbBlue);
852 if ( cRef == sysColorMap[i].from) {
854 if (wFlags & CBS_MASKED) {
855 if (sysColorMap[i].to != COLOR_BTNTEXT)
856 pColorTable[iColor] = RGB(255, 255, 255);
860 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
861 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
862 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
867 nWidth = (INT)lpBitmapInfo->biWidth;
868 nHeight = (INT)lpBitmapInfo->biHeight;
869 hdcScreen = GetDC (NULL);
870 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
872 HDC hdcDst = CreateCompatibleDC (hdcScreen);
873 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
874 LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
875 lpBits += nColorTableSize * sizeof(RGBQUAD);
876 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
877 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
879 SelectObject (hdcDst, hbmOld);
882 ReleaseDC (NULL, hdcScreen);
883 GlobalFree ((HGLOBAL)lpBitmapInfo);
890 /***********************************************************************
891 * CreateToolbar [COMCTL32.7]
893 * Creates a toolbar control.
906 * Success: handle to the tool bar control
910 * Do not use this functions anymore. Use CreateToolbarEx instead.
914 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
915 HINSTANCE hBMInst, UINT wBMID,
916 LPCTBBUTTON lpButtons,INT iNumButtons)
918 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
919 hBMInst, wBMID, lpButtons,
920 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
924 /***********************************************************************
925 * DllGetVersion [COMCTL32.@]
927 * Retrieves version information of the 'COMCTL32.DLL'
930 * pdvi [O] pointer to version information structure.
934 * Failure: E_INVALIDARG
937 * Returns version of a comctl32.dll from IE4.01 SP1.
940 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
942 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
943 WARN("wrong DLLVERSIONINFO size from app\n");
947 pdvi->dwMajorVersion = COMCTL32_VERSION;
948 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
949 pdvi->dwBuildNumber = 2919;
950 pdvi->dwPlatformID = 6304;
952 TRACE("%u.%u.%u.%u\n",
953 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
954 pdvi->dwBuildNumber, pdvi->dwPlatformID);
959 /***********************************************************************
960 * DllInstall (COMCTL32.@)
962 * Installs the ComCtl32 DLL.
966 * Failure: A HRESULT error
968 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
970 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
971 debugstr_w(cmdline));
976 /***********************************************************************
977 * _TrackMouseEvent [COMCTL32.@]
979 * Requests notification of mouse events
981 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
982 * to the hwnd specified in the ptme structure. After the event message
983 * is posted to the hwnd, the entry in the queue is removed.
985 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
986 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
987 * immediately and the TME_LEAVE flag being ignored.
990 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
996 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1001 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1003 return TrackMouseEvent (ptme);
1006 /*************************************************************************
1007 * GetMUILanguage [COMCTL32.@]
1009 * Returns the user interface language in use by the current process.
1012 * Language ID in use by the current process.
1014 LANGID WINAPI GetMUILanguage (VOID)
1016 return COMCTL32_uiLang;
1020 /*************************************************************************
1021 * InitMUILanguage [COMCTL32.@]
1023 * Sets the user interface language to be used by the current process.
1028 VOID WINAPI InitMUILanguage (LANGID uiLang)
1030 COMCTL32_uiLang = uiLang;
1034 /***********************************************************************
1035 * SetWindowSubclass [COMCTL32.410]
1037 * Starts a window subclass
1040 * hWnd [in] handle to window subclass.
1041 * pfnSubclass [in] Pointer to new window procedure.
1042 * uIDSubclass [in] Unique identifier of sublass together with pfnSubclass.
1043 * dwRef [in] Reference data to pass to window procedure.
1050 * If an application manually subclasses a window after subclassing it with
1051 * this API and then with this API again, then none of the previous
1052 * subclasses get called or the origional window procedure.
1055 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1056 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1058 LPSUBCLASS_INFO stack;
1059 LPSUBCLASSPROCS proc;
1061 TRACE ("(%p, %p, %x, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1063 /* Since the window procedure that we set here has two additional arguments,
1064 * we can't simply set it as the new window procedure of the window. So we
1065 * set our own window procedure and then calculate the other two arguments
1068 /* See if we have been called for this window */
1069 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1071 /* allocate stack */
1072 stack = Alloc (sizeof(SUBCLASS_INFO));
1074 ERR ("Failed to allocate our Subclassing stack\n");
1077 SetPropW (hWnd, COMCTL32_wSubclass, (HANDLE)stack);
1079 /* set window procedure to our own and save the current one */
1080 if (IsWindowUnicode (hWnd))
1081 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1082 (DWORD_PTR)COMCTL32_SubclassProc);
1084 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1085 (DWORD_PTR)COMCTL32_SubclassProc);
1088 /* Check to see if we have called this function with the same uIDSubClass
1089 * and pfnSubclass */
1090 proc = stack->SubclassProcs;
1092 if ((proc->id == uIDSubclass) &&
1093 (proc->subproc == pfnSubclass)) {
1101 proc = Alloc(sizeof(SUBCLASSPROCS));
1103 ERR ("Failed to allocate subclass entry in stack\n");
1104 if (IsWindowUnicode (hWnd))
1105 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1107 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1109 RemovePropW( hWnd, COMCTL32_wSubclass );
1113 proc->subproc = pfnSubclass;
1115 proc->id = uIDSubclass;
1116 proc->next = stack->SubclassProcs;
1117 stack->SubclassProcs = proc;
1123 /***********************************************************************
1124 * GetWindowSubclass [COMCTL32.411]
1126 * Gets the Reference data from a subclass.
1129 * hWnd [in] Handle to window which were subclassing
1130 * pfnSubclass [in] Pointer to the subclass procedure
1131 * uID [in] Unique indentifier of the subclassing procedure
1132 * pdwRef [out] Pointer to the reference data
1139 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1140 UINT_PTR uID, DWORD_PTR *pdwRef)
1142 LPSUBCLASS_INFO stack;
1143 LPSUBCLASSPROCS proc;
1145 TRACE ("(%p, %p, %x, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1147 /* See if we have been called for this window */
1148 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1152 proc = stack->SubclassProcs;
1154 if ((proc->id == uID) &&
1155 (proc->subproc == pfnSubclass)) {
1156 *pdwRef = proc->ref;
1166 /***********************************************************************
1167 * RemoveWindowSubclass [COMCTL32.412]
1169 * Removes a window subclass.
1172 * hWnd [in] Handle to the window were subclassing
1173 * pfnSubclass [in] Pointer to the subclass procedure
1174 * uID [in] Unique identifier of this subclass
1181 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1183 LPSUBCLASS_INFO stack;
1184 LPSUBCLASSPROCS prevproc = NULL;
1185 LPSUBCLASSPROCS proc;
1188 TRACE ("(%p, %p, %x)\n", hWnd, pfnSubclass, uID);
1190 /* Find the Subclass to remove */
1191 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1195 proc = stack->SubclassProcs;
1197 if ((proc->id == uID) &&
1198 (proc->subproc == pfnSubclass)) {
1201 stack->SubclassProcs = proc->next;
1203 prevproc->next = proc->next;
1205 if (stack->stackpos == proc)
1206 stack->stackpos = stack->stackpos->next;
1216 if (!stack->SubclassProcs && !stack->running) {
1217 TRACE("Last Subclass removed, cleaning up\n");
1218 /* clean up our heap and reset the origional window procedure */
1219 if (IsWindowUnicode (hWnd))
1220 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1222 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1224 RemovePropW( hWnd, COMCTL32_wSubclass );
1230 /***********************************************************************
1231 * COMCTL32_SubclassProc (internal)
1233 * Window procedure for all subclassed windows.
1234 * Saves the current subclassing stack position to support nested messages
1236 LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1238 LPSUBCLASS_INFO stack;
1239 LPSUBCLASSPROCS proc;
1242 TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1244 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1246 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1250 /* Save our old stackpos to properly handle nested messages */
1251 proc = stack->stackpos;
1252 stack->stackpos = stack->SubclassProcs;
1254 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1256 stack->stackpos = proc;
1258 if (!stack->SubclassProcs && !stack->running) {
1259 TRACE("Last Subclass removed, cleaning up\n");
1260 /* clean up our heap and reset the origional window procedure */
1261 if (IsWindowUnicode (hWnd))
1262 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1264 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1266 RemovePropW( hWnd, COMCTL32_wSubclass );
1271 /***********************************************************************
1272 * DefSubclassProc [COMCTL32.413]
1274 * Calls the next window procedure (ie. the one before this subclass)
1277 * hWnd [in] The window that we're subclassing
1279 * wParam [in] WPARAM
1280 * lParam [in] LPARAM
1287 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1289 LPSUBCLASS_INFO stack;
1292 TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1294 /* retrieve our little stack from the Properties */
1295 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1297 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1301 /* If we are at the end of stack then we have to call the original
1302 * window procedure */
1303 if (!stack->stackpos) {
1304 if (IsWindowUnicode (hWnd))
1305 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1307 ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1309 LPSUBCLASSPROCS proc = stack->stackpos;
1310 stack->stackpos = stack->stackpos->next;
1311 /* call the Subclass procedure from the stack */
1312 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1313 proc->id, proc->ref);
1320 /***********************************************************************
1321 * COMCTL32_CreateToolTip [NOT AN API]
1323 * Creates a tooltip for the control specified in hwnd and does all
1324 * necessary setup and notifications.
1327 * hwndOwner [I] Handle to the window that will own the tool tip.
1330 * Success: Handle of tool tip window.
1335 COMCTL32_CreateToolTip(HWND hwndOwner)
1339 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1340 CW_USEDEFAULT, CW_USEDEFAULT,
1341 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1344 /* Send NM_TOOLTIPSCREATED notification */
1347 NMTOOLTIPSCREATED nmttc;
1348 /* true owner can be different if hwndOwner is a child window */
1349 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1350 nmttc.hdr.hwndFrom = hwndTrueOwner;
1351 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1352 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1353 nmttc.hwndToolTips = hwndToolTip;
1355 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1356 (WPARAM)GetWindowLongPtrW(hwndTrueOwner, GWLP_ID),
1364 /***********************************************************************
1365 * COMCTL32_RefreshSysColors [NOT AN API]
1367 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1368 * refresh the color values in the color structure
1378 COMCTL32_RefreshSysColors(void)
1380 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1381 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1382 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1383 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1384 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1385 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1386 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1387 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1388 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1389 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1390 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1391 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1392 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1393 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1394 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1395 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1398 /***********************************************************************
1399 * COMCTL32_DrawInsertMark [NOT AN API]
1401 * Draws an insertion mark (which looks similar to an 'I').
1404 * hDC [I] Device context to draw onto.
1405 * lpRect [I] Co-ordinates of insertion mark.
1406 * clrInsertMark [I] Colour of the insertion mark.
1407 * bHorizontal [I] True if insert mark should be drawn horizontally,
1408 * vertical otherwise.
1414 * Draws up to but not including the bottom co-ordinate when drawing
1415 * vertically or the right co-ordinate when horizontal.
1417 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1419 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1421 static const DWORD adwPolyPoints[] = {4,4,4};
1422 LONG lCentre = (bHorizontal ?
1423 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1424 lpRect->left + (lpRect->right - lpRect->left)/2);
1425 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1426 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1427 const POINT aptInsertMark[] =
1429 /* top (V) or left (H) arrow */
1433 {lCentre + 1, l1 + 2},
1437 {lCentre + 1, l1 - 1},
1438 {lCentre + 1, l2 - 2},
1439 /* bottom (V) or right (H) arrow */
1441 {lCentre - 2, l2 - 1},
1442 {lCentre + 3, l2 - 1},
1443 {lCentre + 1, l2 - 3},
1445 hOldPen = SelectObject(hDC, hPen);
1446 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0]));
1447 SelectObject(hDC, hOldPen);
1451 /***********************************************************************
1452 * COMCTL32_EnsureBitmapSize [internal]
1454 * If needed enlarge the bitmap so that the width is at least cxMinWidth
1455 * the height is at least cyMinHeight. If the bitmap already have these
1456 * dimensions nothing changes.
1459 * hBitmap [I/O] Bitmap to modify. The handle may change
1460 * cxMinWidth [I] If the width of the bitmap is smaller then it will
1461 * be enlarged to this value
1462 * cyMinHeight [I] If the height of the bitmap is smaller then it will
1463 * be enlarged to this value
1464 * cyBackground [I] The color with which the new area will be filled
1469 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1474 HBITMAP hNewDCBitmap, hOldDCBitmap;
1478 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1480 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1481 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1482 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1485 hdcNew = CreateCompatibleDC(NULL);
1486 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1487 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1488 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1490 hdcOld = CreateCompatibleDC(NULL);
1491 hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1493 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1494 if (bmp.bmWidth < cxMinWidth)
1495 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1496 if (bmp.bmHeight < cyMinHeight)
1497 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1498 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1499 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1501 SelectObject(hdcNew, hNewDCBitmap);
1502 DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1504 SelectObject(hdcOld, hOldDCBitmap);
1507 DeleteObject(*pBitmap);
1508 *pBitmap = hNewBitmap;
1512 /***********************************************************************
1513 * MirrorIcon [COMCTL32.414]
1515 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1518 * phicon1 [I/O] Icon.
1519 * phicon2 [I/O] Icon.
1525 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1527 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1531 static inline int IsDelimiter(WCHAR c)
1544 static int CALLBACK PathWordBreakProc(LPWSTR lpch, int ichCurrent, int cch, int code)
1546 if (code == WB_ISDELIMITER)
1547 return IsDelimiter(lpch[ichCurrent]);
1550 int dir = (code == WB_LEFT) ? -1 : 1;
1551 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1552 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1557 /***********************************************************************
1558 * SetPathWordBreakProc [COMCTL32.384]
1560 * Sets the word break procedure for an edit control to one that understands
1561 * paths so that the user can jump over directories.
1564 * hwnd [I] Handle to edit control.
1565 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1568 * Result from EM_SETWORDBREAKPROC message.
1570 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1572 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1573 (LPARAM)(bSet ? PathWordBreakProc : NULL));