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 * -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW
33 * -- FIXMEs + BUGS (search for them)
36 * -- ICC_ANIMATE_CLASS
41 * -- ICC_INTERNET_CLASSES
43 * -- ICC_LISTVIEW_CLASSES
44 * -- ICC_NATIVEFNTCTL_CLASS
45 * -- ICC_PAGESCROLLER_CLASS
46 * -- ICC_PROGRESS_CLASS
47 * -- ICC_STANDARD_CLASSES (not yet implemented)
49 * -- ICC_TREEVIEW_CLASSES
51 * -- ICC_USEREX_CLASSES
52 * -- ICC_WIN95_CLASSES
67 #define NO_SHLWAPI_STREAM
70 #include "wine/debug.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
74 LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
76 LPWSTR COMCTL32_wSubclass = NULL;
77 HMODULE COMCTL32_hModule = 0;
78 LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
79 HBRUSH COMCTL32_hPattern55AABrush = NULL;
80 COMCTL32_SysColor comctl32_color;
82 static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
84 static const WORD wPattern55AA[] =
86 0x5555, 0xaaaa, 0x5555, 0xaaaa,
87 0x5555, 0xaaaa, 0x5555, 0xaaaa
90 static const WCHAR strCC32SubclassInfo[] = {
91 'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
94 /***********************************************************************
97 * Initializes the internal 'COMCTL32.DLL'.
100 * hinstDLL [I] handle to the 'dlls' instance
102 * lpvReserved [I] reserverd, must be NULL
109 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
111 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
114 case DLL_PROCESS_ATTACH:
115 DisableThreadLibraryCalls(hinstDLL);
117 COMCTL32_hModule = (HMODULE)hinstDLL;
119 /* add global subclassing atom (used by 'tooltip' and 'updown') */
120 COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
121 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
123 /* create local pattern brush */
124 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
125 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
127 /* Get all the colors at DLL load */
128 COMCTL32_RefreshSysColors();
130 /* like comctl32 5.82+ register all the common control classes */
133 DATETIME_Register ();
137 IPADDRESS_Register ();
138 LISTVIEW_Register ();
139 MONTHCAL_Register ();
140 NATIVEFONT_Register ();
142 PROGRESS_Register ();
148 TOOLTIPS_Register ();
149 TRACKBAR_Register ();
150 TREEVIEW_Register ();
153 /* subclass user32 controls */
154 THEMING_Initialize ();
157 case DLL_PROCESS_DETACH:
158 /* clean up subclassing */
159 THEMING_Uninitialize();
161 /* unregister all common control classes */
162 ANIMATE_Unregister ();
163 COMBOEX_Unregister ();
164 DATETIME_Unregister ();
165 FLATSB_Unregister ();
166 HEADER_Unregister ();
167 HOTKEY_Unregister ();
168 IPADDRESS_Unregister ();
169 LISTVIEW_Unregister ();
170 MONTHCAL_Unregister ();
171 NATIVEFONT_Unregister ();
173 PROGRESS_Unregister ();
175 STATUS_Unregister ();
176 SYSLINK_Unregister ();
178 TOOLBAR_Unregister ();
179 TOOLTIPS_Unregister ();
180 TRACKBAR_Unregister ();
181 TREEVIEW_Unregister ();
182 UPDOWN_Unregister ();
184 /* delete local pattern brush */
185 DeleteObject (COMCTL32_hPattern55AABrush);
186 COMCTL32_hPattern55AABrush = NULL;
187 DeleteObject (COMCTL32_hPattern55AABitmap);
188 COMCTL32_hPattern55AABitmap = NULL;
190 /* delete global subclassing atom */
191 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
192 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
193 COMCTL32_wSubclass = NULL;
201 /***********************************************************************
202 * MenuHelp [COMCTL32.2]
204 * Handles the setting of status bar help messages when the user
205 * selects menu items.
208 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
209 * wParam [I] wParam of the message uMsg
210 * lParam [I] lParam of the message uMsg
211 * hMainMenu [I] handle to the application's main menu
212 * hInst [I] handle to the module that contains string resources
213 * hwndStatus [I] handle to the status bar window
214 * lpwIDs [I] pointer to an array of integers (see NOTES)
220 * The official documentation is incomplete!
221 * This is the correct documentation:
224 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
225 * WM_MENUSELECT messages.
228 * (will be written ...)
232 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
233 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
237 if (!IsWindow (hwndStatus))
242 TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n",
245 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
246 /* menu was closed */
247 TRACE("menu was closed!\n");
248 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
251 /* menu item was selected */
252 if (HIWORD(wParam) & MF_POPUP)
253 uMenuID = (UINT)*(lpwIDs+1);
255 uMenuID = (UINT)LOWORD(wParam);
256 TRACE("uMenuID = %u\n", uMenuID);
261 if (!LoadStringW (hInst, uMenuID, szText, sizeof(szText)/sizeof(szText[0])))
264 SendMessageW (hwndStatus, SB_SETTEXTW,
265 255 | SBT_NOBORDERS, (LPARAM)szText);
266 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
272 TRACE("WM_COMMAND wParam=0x%X lParam=0x%lX\n",
274 /* WM_COMMAND is not invalid since it is documented
275 * in the windows api reference. So don't output
276 * any FIXME for WM_COMMAND
278 WARN("We don't care about the WM_COMMAND\n");
282 FIXME("Invalid Message 0x%x!\n", uMsg);
288 /***********************************************************************
289 * ShowHideMenuCtl [COMCTL32.3]
291 * Shows or hides controls and updates the corresponding menu item.
294 * hwnd [I] handle to the client window.
295 * uFlags [I] menu command id.
296 * lpInfo [I] pointer to an array of integers. (See NOTES.)
303 * The official documentation is incomplete!
304 * This is the correct documentation:
307 * Handle to the window that contains the menu and controls.
310 * Identifier of the menu item to receive or lose a check mark.
313 * The array of integers contains pairs of values. BOTH values of
314 * the first pair must be the handles to the application's main menu.
315 * Each subsequent pair consists of a menu id and control id.
319 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
323 TRACE("%p, %x, %p\n", hwnd, uFlags, lpInfo);
328 if (!(lpInfo[0]) || !(lpInfo[1]))
331 /* search for control */
332 lpMenuId = &lpInfo[2];
333 while (*lpMenuId != uFlags)
336 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
337 /* uncheck menu item */
338 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
342 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
346 /* check menu item */
347 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
351 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
359 /***********************************************************************
360 * GetEffectiveClientRect [COMCTL32.4]
362 * Calculates the coordinates of a rectangle in the client area.
365 * hwnd [I] handle to the client window.
366 * lpRect [O] pointer to the rectangle of the client window
367 * lpInfo [I] pointer to an array of integers (see NOTES)
373 * The official documentation is incomplete!
374 * This is the correct documentation:
377 * (will be written ...)
381 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo)
387 TRACE("(%p %p %p)\n",
388 hwnd, lpRect, lpInfo);
390 GetClientRect (hwnd, lpRect);
398 hwndCtrl = GetDlgItem (hwnd, *lpRun);
399 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
400 TRACE("control id 0x%x\n", *lpRun);
401 GetWindowRect (hwndCtrl, &rcCtrl);
402 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
403 SubtractRect (lpRect, lpRect, &rcCtrl);
410 /***********************************************************************
411 * DrawStatusTextW [COMCTL32.@]
413 * Draws text with borders, like in a status bar.
416 * hdc [I] handle to the window's display context
417 * lprc [I] pointer to a rectangle
418 * text [I] pointer to the text
419 * style [I] drawing style
425 * The style variable can have one of the following values:
426 * (will be written ...)
429 void WINAPI DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style)
432 UINT border = BDR_SUNKENOUTER;
434 if (style & SBT_POPOUT)
435 border = BDR_RAISEDOUTER;
436 else if (style & SBT_NOBORDERS)
439 DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
443 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
444 UINT align = DT_LEFT;
445 if (*text == L'\t') {
448 if (*text == L'\t') {
454 if (style & SBT_RTLREADING)
455 FIXME("Unsupported RTL style!\n");
456 DrawTextW (hdc, text, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
457 SetBkMode(hdc, oldbkmode);
462 /***********************************************************************
463 * DrawStatusText [COMCTL32.@]
464 * DrawStatusTextA [COMCTL32.5]
466 * Draws text with borders, like in a status bar.
469 * hdc [I] handle to the window's display context
470 * lprc [I] pointer to a rectangle
471 * text [I] pointer to the text
472 * style [I] drawing style
478 void WINAPI DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style)
484 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
485 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
486 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
489 DrawStatusTextW( hdc, lprc, textW, style );
494 /***********************************************************************
495 * CreateStatusWindow [COMCTL32.@]
496 * CreateStatusWindowA [COMCTL32.6]
498 * Creates a status bar
501 * style [I] window style
502 * text [I] pointer to the window text
503 * parent [I] handle to the parent window
504 * wid [I] control id of the status bar
507 * Success: handle to the status window
512 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
514 return CreateWindowA(STATUSCLASSNAMEA, text, style,
515 CW_USEDEFAULT, CW_USEDEFAULT,
516 CW_USEDEFAULT, CW_USEDEFAULT,
517 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
521 /***********************************************************************
522 * CreateStatusWindowW [COMCTL32.@]
524 * Creates a status bar control
527 * style [I] window style
528 * text [I] pointer to the window text
529 * parent [I] handle to the parent window
530 * wid [I] control id of the status bar
533 * Success: handle to the status window
538 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
540 return CreateWindowW(STATUSCLASSNAMEW, text, style,
541 CW_USEDEFAULT, CW_USEDEFAULT,
542 CW_USEDEFAULT, CW_USEDEFAULT,
543 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
547 /***********************************************************************
548 * CreateUpDownControl [COMCTL32.16]
550 * Creates an up-down control
553 * style [I] window styles
554 * x [I] horizontal position of the control
555 * y [I] vertical position of the control
556 * cx [I] with of the control
557 * cy [I] height of the control
558 * parent [I] handle to the parent window
559 * id [I] the control's identifier
560 * inst [I] handle to the application's module instance
561 * buddy [I] handle to the buddy window, can be NULL
562 * maxVal [I] upper limit of the control
563 * minVal [I] lower limit of the control
564 * curVal [I] current value of the control
567 * Success: handle to the updown control
572 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
573 HWND parent, INT id, HINSTANCE inst,
574 HWND buddy, INT maxVal, INT minVal, INT curVal)
577 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
578 parent, (HMENU)(DWORD_PTR)id, inst, 0);
580 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
581 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
582 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
589 /***********************************************************************
590 * InitCommonControls [COMCTL32.17]
592 * Registers the common controls.
601 * This function is just a dummy - all the controls are registered at
602 * the DLL's initialization. See InitCommonContolsEx for details.
606 InitCommonControls (void)
611 /***********************************************************************
612 * InitCommonControlsEx [COMCTL32.@]
614 * Registers the common controls.
617 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
624 * Probaly all versions of comctl32 initializes the Win95 controls in DllMain
625 * during DLL initializaiton. Starting from comctl32 v5.82 all the controls
626 * are initialized there. We follow this behaviour and this function is just
629 * Note: when writing programs under Windows, if you don't call any function
630 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
631 * was the only comctl32 function you were calling and you remove it you may
632 * have a false impression that InitCommonControlsEx actually did something.
636 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
638 if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
641 TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
646 /***********************************************************************
647 * CreateToolbarEx [COMCTL32.@]
649 * Creates a toolbar window.
667 * Success: handle to the tool bar control
672 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
673 HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons,
674 INT iNumButtons, INT dxButton, INT dyButton,
675 INT dxBitmap, INT dyBitmap, UINT uStructSize)
680 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
681 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
685 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM)uStructSize, 0);
687 /* set bitmap and button size */
688 /*If CreateToolbarEx receives 0, windows sets default values*/
693 SendMessageW (hwndTB, TB_SETBITMAPSIZE, 0,
694 MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap));
700 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
701 if (dxButton != 0 && dyButton != 0)
702 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
708 tbab.hInst = hBMInst;
711 SendMessageW (hwndTB, TB_ADDBITMAP, (WPARAM)nBitmaps, (LPARAM)&tbab);
715 SendMessageW (hwndTB, TB_ADDBUTTONSW,
716 (WPARAM)iNumButtons, (LPARAM)lpButtons);
723 /***********************************************************************
724 * CreateMappedBitmap [COMCTL32.8]
726 * Loads a bitmap resource using a colour map.
729 * hInstance [I] Handle to the module containing the bitmap.
730 * idBitmap [I] The bitmap resource ID.
731 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
732 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
733 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
736 * Success: handle to the new bitmap
741 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
742 LPCOLORMAP lpColorMap, INT iNumMaps)
746 LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
747 UINT nSize, nColorTableSize, iColor;
748 RGBQUAD *pColorTable;
749 INT i, iMaps, nWidth, nHeight;
752 LPCOLORMAP sysColorMap;
754 COLORMAP internalColorMap[4] =
755 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
757 /* initialize pointer to colortable and default color table */
760 sysColorMap = lpColorMap;
763 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
764 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
765 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
766 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
768 sysColorMap = (LPCOLORMAP)internalColorMap;
771 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
774 hglb = LoadResource (hInstance, hRsrc);
777 lpBitmap = (LPBITMAPINFOHEADER)LockResource (hglb);
778 if (lpBitmap == NULL)
781 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
782 nColorTableSize = lpBitmap->biClrUsed;
783 else if (lpBitmap->biBitCount <= 8)
784 nColorTableSize = (1 << lpBitmap->biBitCount);
787 nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
788 lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize);
789 if (lpBitmapInfo == NULL)
791 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
793 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)lpBitmapInfo->biSize);
795 for (iColor = 0; iColor < nColorTableSize; iColor++) {
796 for (i = 0; i < iMaps; i++) {
797 cRef = RGB(pColorTable[iColor].rgbRed,
798 pColorTable[iColor].rgbGreen,
799 pColorTable[iColor].rgbBlue);
800 if ( cRef == sysColorMap[i].from) {
802 if (wFlags & CBS_MASKED) {
803 if (sysColorMap[i].to != COLOR_BTNTEXT)
804 pColorTable[iColor] = RGB(255, 255, 255);
808 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
809 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
810 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
815 nWidth = (INT)lpBitmapInfo->biWidth;
816 nHeight = (INT)lpBitmapInfo->biHeight;
817 hdcScreen = GetDC (NULL);
818 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
820 HDC hdcDst = CreateCompatibleDC (hdcScreen);
821 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
822 LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
823 lpBits += nColorTableSize * sizeof(RGBQUAD);
824 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
825 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
827 SelectObject (hdcDst, hbmOld);
830 ReleaseDC (NULL, hdcScreen);
831 GlobalFree ((HGLOBAL)lpBitmapInfo);
838 /***********************************************************************
839 * CreateToolbar [COMCTL32.7]
841 * Creates a toolbar control.
854 * Success: handle to the tool bar control
858 * Do not use this functions anymore. Use CreateToolbarEx instead.
862 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
863 HINSTANCE hBMInst, UINT wBMID,
864 LPCTBBUTTON lpButtons,INT iNumButtons)
866 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
867 hBMInst, wBMID, lpButtons,
868 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
872 /***********************************************************************
873 * DllGetVersion [COMCTL32.@]
875 * Retrieves version information of the 'COMCTL32.DLL'
878 * pdvi [O] pointer to version information structure.
882 * Failure: E_INVALIDARG
885 * Returns version of a comctl32.dll from IE4.01 SP1.
888 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
890 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
891 WARN("wrong DLLVERSIONINFO size from app\n");
895 pdvi->dwMajorVersion = COMCTL32_VERSION;
896 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
897 pdvi->dwBuildNumber = 2919;
898 pdvi->dwPlatformID = 6304;
900 TRACE("%u.%u.%u.%u\n",
901 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
902 pdvi->dwBuildNumber, pdvi->dwPlatformID);
907 /***********************************************************************
908 * DllInstall (COMCTL32.@)
910 * Installs the ComCtl32 DLL.
914 * Failure: A HRESULT error
916 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
918 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
919 debugstr_w(cmdline));
924 /***********************************************************************
925 * _TrackMouseEvent [COMCTL32.@]
927 * Requests notification of mouse events
929 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
930 * to the hwnd specified in the ptme structure. After the event message
931 * is posted to the hwnd, the entry in the queue is removed.
933 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
934 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
935 * immediately and the TME_LEAVE flag being ignored.
938 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
944 * IMPLEMENTATION moved to USER32.TrackMouseEvent
949 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
951 return TrackMouseEvent (ptme);
954 /*************************************************************************
955 * GetMUILanguage [COMCTL32.@]
957 * Returns the user interface language in use by the current process.
960 * Language ID in use by the current process.
962 LANGID WINAPI GetMUILanguage (VOID)
964 return COMCTL32_uiLang;
968 /*************************************************************************
969 * InitMUILanguage [COMCTL32.@]
971 * Sets the user interface language to be used by the current process.
976 VOID WINAPI InitMUILanguage (LANGID uiLang)
978 COMCTL32_uiLang = uiLang;
982 /***********************************************************************
983 * SetWindowSubclass [COMCTL32.410]
985 * Starts a window subclass
988 * hWnd [in] handle to window subclass.
989 * pfnSubclass [in] Pointer to new window procedure.
990 * uIDSubclass [in] Unique identifier of sublass together with pfnSubclass.
991 * dwRef [in] Reference data to pass to window procedure.
998 * If an application manually subclasses a window after subclassing it with
999 * this API and then with this API again, then none of the previous
1000 * subclasses get called or the origional window procedure.
1003 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1004 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1006 LPSUBCLASS_INFO stack;
1007 LPSUBCLASSPROCS proc;
1009 TRACE ("(%p, %p, %x, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1011 /* Since the window procedure that we set here has two additional arguments,
1012 * we can't simply set it as the new window procedure of the window. So we
1013 * set our own window procedure and then calculate the other two arguments
1016 /* See if we have been called for this window */
1017 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1019 /* allocate stack */
1020 stack = Alloc (sizeof(SUBCLASS_INFO));
1022 ERR ("Failed to allocate our Subclassing stack\n");
1025 SetPropW (hWnd, COMCTL32_wSubclass, (HANDLE)stack);
1027 /* set window procedure to our own and save the current one */
1028 if (IsWindowUnicode (hWnd))
1029 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1030 (DWORD_PTR)COMCTL32_SubclassProc);
1032 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1033 (DWORD_PTR)COMCTL32_SubclassProc);
1036 /* Check to see if we have called this function with the same uIDSubClass
1037 * and pfnSubclass */
1038 proc = stack->SubclassProcs;
1040 if ((proc->id == uIDSubclass) &&
1041 (proc->subproc == pfnSubclass)) {
1049 proc = Alloc(sizeof(SUBCLASSPROCS));
1051 ERR ("Failed to allocate subclass entry in stack\n");
1052 if (IsWindowUnicode (hWnd))
1053 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1055 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1057 RemovePropW( hWnd, COMCTL32_wSubclass );
1061 proc->subproc = pfnSubclass;
1063 proc->id = uIDSubclass;
1064 proc->next = stack->SubclassProcs;
1065 stack->SubclassProcs = proc;
1071 /***********************************************************************
1072 * GetWindowSubclass [COMCTL32.411]
1074 * Gets the Reference data from a subclass.
1077 * hWnd [in] Handle to window which were subclassing
1078 * pfnSubclass [in] Pointer to the subclass procedure
1079 * uID [in] Unique indentifier of the subclassing procedure
1080 * pdwRef [out] Pointer to the reference data
1087 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1088 UINT_PTR uID, DWORD_PTR *pdwRef)
1090 LPSUBCLASS_INFO stack;
1091 LPSUBCLASSPROCS proc;
1093 TRACE ("(%p, %p, %x, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1095 /* See if we have been called for this window */
1096 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1100 proc = stack->SubclassProcs;
1102 if ((proc->id == uID) &&
1103 (proc->subproc == pfnSubclass)) {
1104 *pdwRef = proc->ref;
1114 /***********************************************************************
1115 * RemoveWindowSubclass [COMCTL32.412]
1117 * Removes a window subclass.
1120 * hWnd [in] Handle to the window were subclassing
1121 * pfnSubclass [in] Pointer to the subclass procedure
1122 * uID [in] Unique identifier of this subclass
1129 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1131 LPSUBCLASS_INFO stack;
1132 LPSUBCLASSPROCS prevproc = NULL;
1133 LPSUBCLASSPROCS proc;
1136 TRACE ("(%p, %p, %x)\n", hWnd, pfnSubclass, uID);
1138 /* Find the Subclass to remove */
1139 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1143 proc = stack->SubclassProcs;
1145 if ((proc->id == uID) &&
1146 (proc->subproc == pfnSubclass)) {
1149 stack->SubclassProcs = proc->next;
1151 prevproc->next = proc->next;
1153 if (stack->stackpos == proc)
1154 stack->stackpos = stack->stackpos->next;
1164 if (!stack->SubclassProcs && !stack->running) {
1165 TRACE("Last Subclass removed, cleaning up\n");
1166 /* clean up our heap and reset the origional window procedure */
1167 if (IsWindowUnicode (hWnd))
1168 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1170 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1172 RemovePropW( hWnd, COMCTL32_wSubclass );
1178 /***********************************************************************
1179 * COMCTL32_SubclassProc (internal)
1181 * Window procedure for all subclassed windows.
1182 * Saves the current subclassing stack position to support nested messages
1184 LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1186 LPSUBCLASS_INFO stack;
1187 LPSUBCLASSPROCS proc;
1190 TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1192 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1194 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1198 /* Save our old stackpos to properly handle nested messages */
1199 proc = stack->stackpos;
1200 stack->stackpos = stack->SubclassProcs;
1202 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1204 stack->stackpos = proc;
1206 if (!stack->SubclassProcs && !stack->running) {
1207 TRACE("Last Subclass removed, cleaning up\n");
1208 /* clean up our heap and reset the origional window procedure */
1209 if (IsWindowUnicode (hWnd))
1210 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1212 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1214 RemovePropW( hWnd, COMCTL32_wSubclass );
1219 /***********************************************************************
1220 * DefSubclassProc [COMCTL32.413]
1222 * Calls the next window procedure (ie. the one before this subclass)
1225 * hWnd [in] The window that we're subclassing
1227 * wParam [in] WPARAM
1228 * lParam [in] LPARAM
1235 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1237 LPSUBCLASS_INFO stack;
1240 TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1242 /* retrieve our little stack from the Properties */
1243 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1245 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1249 /* If we are at the end of stack then we have to call the original
1250 * window procedure */
1251 if (!stack->stackpos) {
1252 if (IsWindowUnicode (hWnd))
1253 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1255 ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1257 LPSUBCLASSPROCS proc = stack->stackpos;
1258 stack->stackpos = stack->stackpos->next;
1259 /* call the Subclass procedure from the stack */
1260 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1261 proc->id, proc->ref);
1268 /***********************************************************************
1269 * COMCTL32_CreateToolTip [NOT AN API]
1271 * Creates a tooltip for the control specified in hwnd and does all
1272 * necessary setup and notifications.
1275 * hwndOwner [I] Handle to the window that will own the tool tip.
1278 * Success: Handle of tool tip window.
1283 COMCTL32_CreateToolTip(HWND hwndOwner)
1287 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1288 CW_USEDEFAULT, CW_USEDEFAULT,
1289 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1292 /* Send NM_TOOLTIPSCREATED notification */
1295 NMTOOLTIPSCREATED nmttc;
1296 /* true owner can be different if hwndOwner is a child window */
1297 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1298 nmttc.hdr.hwndFrom = hwndTrueOwner;
1299 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1300 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1301 nmttc.hwndToolTips = hwndToolTip;
1303 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1304 (WPARAM)GetWindowLongPtrW(hwndTrueOwner, GWLP_ID),
1312 /***********************************************************************
1313 * COMCTL32_RefreshSysColors [NOT AN API]
1315 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1316 * refresh the color values in the color structure
1326 COMCTL32_RefreshSysColors(void)
1328 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1329 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1330 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1331 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1332 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1333 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1334 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1335 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1336 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1337 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1338 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1339 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1340 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1341 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1342 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1343 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1346 /***********************************************************************
1347 * COMCTL32_DrawInsertMark [NOT AN API]
1349 * Draws an insertion mark (which looks similar to an 'I').
1352 * hDC [I] Device context to draw onto.
1353 * lpRect [I] Co-ordinates of insertion mark.
1354 * clrInsertMark [I] Colour of the insertion mark.
1355 * bHorizontal [I] True if insert mark should be drawn horizontally,
1356 * vertical otherwise.
1362 * Draws up to but not including the bottom co-ordinate when drawing
1363 * vertically or the right co-ordinate when horizontal.
1365 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1367 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1369 static const DWORD adwPolyPoints[] = {4,4,4};
1370 LONG lCentre = (bHorizontal ?
1371 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1372 lpRect->left + (lpRect->right - lpRect->left)/2);
1373 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1374 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1375 const POINT aptInsertMark[] =
1377 /* top (V) or left (H) arrow */
1381 {lCentre + 1, l1 + 2},
1385 {lCentre + 1, l1 - 1},
1386 {lCentre + 1, l2 - 2},
1387 /* bottom (V) or right (H) arrow */
1389 {lCentre - 2, l2 - 1},
1390 {lCentre + 3, l2 - 1},
1391 {lCentre + 1, l2 - 3},
1393 hOldPen = SelectObject(hDC, hPen);
1394 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0]));
1395 SelectObject(hDC, hOldPen);
1399 /***********************************************************************
1400 * COMCTL32_EnsureBitmapSize [internal]
1402 * If needed enlarge the bitmap so that the width is at least cxMinWidth
1403 * the height is at least cyMinHeight. If the bitmap already have these
1404 * dimensions nothing changes.
1407 * hBitmap [I/O] Bitmap to modify. The handle may change
1408 * cxMinWidth [I] If the width of the bitmap is smaller then it will
1409 * be enlarged to this value
1410 * cyMinHeight [I] If the height of the bitmap is smaller then it will
1411 * be enlarged to this value
1412 * cyBackground [I] The color with which the new area will be filled
1417 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1422 HBITMAP hNewDCBitmap, hOldDCBitmap;
1426 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1428 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1429 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1430 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1433 hdcNew = CreateCompatibleDC(NULL);
1434 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1435 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1436 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1438 hdcOld = CreateCompatibleDC(NULL);
1439 hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1441 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1442 if (bmp.bmWidth < cxMinWidth)
1443 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1444 if (bmp.bmHeight < cyMinHeight)
1445 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1446 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1447 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1449 SelectObject(hdcNew, hNewDCBitmap);
1450 DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1452 SelectObject(hdcOld, hOldDCBitmap);
1455 DeleteObject(*pBitmap);
1456 *pBitmap = hNewBitmap;
1460 /***********************************************************************
1461 * MirrorIcon [COMCTL32.414]
1463 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1466 * phicon1 [I/O] Icon.
1467 * phicon2 [I/O] Icon.
1473 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1475 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1479 static inline int IsDelimiter(WCHAR c)
1492 static int CALLBACK PathWordBreakProc(LPWSTR lpch, int ichCurrent, int cch, int code)
1494 if (code == WB_ISDELIMITER)
1495 return IsDelimiter(lpch[ichCurrent]);
1498 int dir = (code == WB_LEFT) ? -1 : 1;
1499 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1500 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1505 /***********************************************************************
1506 * SetPathWordBreakProc [COMCTL32.384]
1508 * Sets the word break procedure for an edit control to one that understands
1509 * paths so that the user can jump over directories.
1512 * hwnd [I] Handle to edit control.
1513 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1516 * Result from EM_SETWORDBREAKPROC message.
1518 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1520 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1521 (LPARAM)(bSet ? PathWordBreakProc : NULL));