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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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,%lx,%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)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 /* unregister all common control classes */
154 ANIMATE_Unregister ();
155 COMBOEX_Unregister ();
156 DATETIME_Unregister ();
157 FLATSB_Unregister ();
158 HEADER_Unregister ();
159 HOTKEY_Unregister ();
160 IPADDRESS_Unregister ();
161 LISTVIEW_Unregister ();
162 MONTHCAL_Unregister ();
163 NATIVEFONT_Unregister ();
165 PROGRESS_Unregister ();
167 STATUS_Unregister ();
168 SYSLINK_Unregister ();
170 TOOLBAR_Unregister ();
171 TOOLTIPS_Unregister ();
172 TRACKBAR_Unregister ();
173 TREEVIEW_Unregister ();
174 UPDOWN_Unregister ();
176 /* delete local pattern brush */
177 DeleteObject (COMCTL32_hPattern55AABrush);
178 COMCTL32_hPattern55AABrush = NULL;
179 DeleteObject (COMCTL32_hPattern55AABitmap);
180 COMCTL32_hPattern55AABitmap = NULL;
182 /* delete global subclassing atom */
183 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
184 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
185 COMCTL32_wSubclass = NULL;
193 /***********************************************************************
194 * MenuHelp [COMCTL32.2]
196 * Handles the setting of status bar help messages when the user
197 * selects menu items.
200 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
201 * wParam [I] wParam of the message uMsg
202 * lParam [I] lParam of the message uMsg
203 * hMainMenu [I] handle to the application's main menu
204 * hInst [I] handle to the module that contains string resources
205 * hwndStatus [I] handle to the status bar window
206 * lpwIDs [I] pointer to an array of integers (see NOTES)
212 * The official documentation is incomplete!
213 * This is the correct documentation:
216 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
217 * WM_MENUSELECT messages.
220 * (will be written ...)
224 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
225 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
229 if (!IsWindow (hwndStatus))
234 TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n",
237 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
238 /* menu was closed */
239 TRACE("menu was closed!\n");
240 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
243 /* menu item was selected */
244 if (HIWORD(wParam) & MF_POPUP)
245 uMenuID = (UINT)*(lpwIDs+1);
247 uMenuID = (UINT)LOWORD(wParam);
248 TRACE("uMenuID = %u\n", uMenuID);
253 if (!LoadStringW (hInst, uMenuID, szText, sizeof(szText)/sizeof(szText[0])))
256 SendMessageW (hwndStatus, SB_SETTEXTW,
257 255 | SBT_NOBORDERS, (LPARAM)szText);
258 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
264 TRACE("WM_COMMAND wParam=0x%X lParam=0x%lX\n",
266 /* WM_COMMAND is not invalid since it is documented
267 * in the windows api reference. So don't output
268 * any FIXME for WM_COMMAND
270 WARN("We don't care about the WM_COMMAND\n");
274 FIXME("Invalid Message 0x%x!\n", uMsg);
280 /***********************************************************************
281 * ShowHideMenuCtl [COMCTL32.3]
283 * Shows or hides controls and updates the corresponding menu item.
286 * hwnd [I] handle to the client window.
287 * uFlags [I] menu command id.
288 * lpInfo [I] pointer to an array of integers. (See NOTES.)
295 * The official documentation is incomplete!
296 * This is the correct documentation:
299 * Handle to the window that contains the menu and controls.
302 * Identifier of the menu item to receive or lose a check mark.
305 * The array of integers contains pairs of values. BOTH values of
306 * the first pair must be the handles to the application's main menu.
307 * Each subsequent pair consists of a menu id and control id.
311 ShowHideMenuCtl (HWND hwnd, UINT uFlags, LPINT lpInfo)
315 TRACE("%p, %x, %p\n", hwnd, uFlags, lpInfo);
320 if (!(lpInfo[0]) || !(lpInfo[1]))
323 /* search for control */
324 lpMenuId = &lpInfo[2];
325 while (*lpMenuId != uFlags)
328 if (GetMenuState ((HMENU)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
329 /* uncheck menu item */
330 CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
334 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
338 /* check menu item */
339 CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
343 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
351 /***********************************************************************
352 * GetEffectiveClientRect [COMCTL32.4]
354 * Calculates the coordinates of a rectangle in the client area.
357 * hwnd [I] handle to the client window.
358 * lpRect [O] pointer to the rectangle of the client window
359 * lpInfo [I] pointer to an array of integers (see NOTES)
365 * The official documentation is incomplete!
366 * This is the correct documentation:
369 * (will be written ...)
373 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo)
379 TRACE("(0x%08lx 0x%08lx 0x%08lx)\n",
380 (DWORD)hwnd, (DWORD)lpRect, (DWORD)lpInfo);
382 GetClientRect (hwnd, lpRect);
390 hwndCtrl = GetDlgItem (hwnd, *lpRun);
391 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
392 TRACE("control id 0x%x\n", *lpRun);
393 GetWindowRect (hwndCtrl, &rcCtrl);
394 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
395 SubtractRect (lpRect, lpRect, &rcCtrl);
402 /***********************************************************************
403 * DrawStatusTextW [COMCTL32.@]
405 * Draws text with borders, like in a status bar.
408 * hdc [I] handle to the window's display context
409 * lprc [I] pointer to a rectangle
410 * text [I] pointer to the text
411 * style [I] drawing style
417 * The style variable can have one of the following values:
418 * (will be written ...)
421 void WINAPI DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style)
424 UINT border = BDR_SUNKENOUTER;
426 if (style & SBT_POPOUT)
427 border = BDR_RAISEDOUTER;
428 else if (style & SBT_NOBORDERS)
431 DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
435 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
436 UINT align = DT_LEFT;
437 if (*text == L'\t') {
440 if (*text == L'\t') {
446 if (style & SBT_RTLREADING)
447 FIXME("Unsupported RTL style!\n");
448 DrawTextW (hdc, text, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
449 SetBkMode(hdc, oldbkmode);
454 /***********************************************************************
455 * DrawStatusText [COMCTL32.@]
456 * DrawStatusTextA [COMCTL32.5]
458 * Draws text with borders, like in a status bar.
461 * hdc [I] handle to the window's display context
462 * lprc [I] pointer to a rectangle
463 * text [I] pointer to the text
464 * style [I] drawing style
470 void WINAPI DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style)
476 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
477 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
478 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
481 DrawStatusTextW( hdc, lprc, textW, style );
486 /***********************************************************************
487 * CreateStatusWindow [COMCTL32.@]
488 * CreateStatusWindowA [COMCTL32.6]
490 * Creates a status bar
493 * style [I] window style
494 * text [I] pointer to the window text
495 * parent [I] handle to the parent window
496 * wid [I] control id of the status bar
499 * Success: handle to the status window
504 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
506 return CreateWindowA(STATUSCLASSNAMEA, text, style,
507 CW_USEDEFAULT, CW_USEDEFAULT,
508 CW_USEDEFAULT, CW_USEDEFAULT,
509 parent, (HMENU)wid, 0, 0);
513 /***********************************************************************
514 * CreateStatusWindowW [COMCTL32.@]
516 * Creates a status bar control
519 * style [I] window style
520 * text [I] pointer to the window text
521 * parent [I] handle to the parent window
522 * wid [I] control id of the status bar
525 * Success: handle to the status window
530 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
532 return CreateWindowW(STATUSCLASSNAMEW, text, style,
533 CW_USEDEFAULT, CW_USEDEFAULT,
534 CW_USEDEFAULT, CW_USEDEFAULT,
535 parent, (HMENU)wid, 0, 0);
539 /***********************************************************************
540 * CreateUpDownControl [COMCTL32.16]
542 * Creates an up-down control
545 * style [I] window styles
546 * x [I] horizontal position of the control
547 * y [I] vertical position of the control
548 * cx [I] with of the control
549 * cy [I] height of the control
550 * parent [I] handle to the parent window
551 * id [I] the control's identifier
552 * inst [I] handle to the application's module instance
553 * buddy [I] handle to the buddy window, can be NULL
554 * maxVal [I] upper limit of the control
555 * minVal [I] lower limit of the control
556 * curVal [I] current value of the control
559 * Success: handle to the updown control
564 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
565 HWND parent, INT id, HINSTANCE inst,
566 HWND buddy, INT maxVal, INT minVal, INT curVal)
569 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
570 parent, (HMENU)id, inst, 0);
572 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
573 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
574 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
581 /***********************************************************************
582 * InitCommonControls [COMCTL32.17]
584 * Registers the common controls.
593 * This function is just a dummy.
594 * The Win95 controls are registered at the DLL's initialization.
595 * To register other controls InitCommonControlsEx() must be used.
599 InitCommonControls (void)
604 /***********************************************************************
605 * InitCommonControlsEx [COMCTL32.@]
607 * Registers the common controls.
610 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
617 * Only the additional common controls are registered by this function.
618 * The Win95 controls are registered at the DLL's initialization.
621 * implement the following control classes:
623 * ICC_STANDARD_CLASSES
627 InitCommonControlsEx (LPINITCOMMONCONTROLSEX lpInitCtrls)
634 if (lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
637 TRACE("(0x%08lx)\n", lpInitCtrls->dwICC);
639 for (cCount = 0; cCount < 32; cCount++) {
640 dwMask = 1 << cCount;
641 if (!(lpInitCtrls->dwICC & dwMask))
644 switch (lpInitCtrls->dwICC & dwMask) {
645 /* dummy initialization */
646 case ICC_ANIMATE_CLASS:
647 case ICC_BAR_CLASSES:
648 case ICC_LISTVIEW_CLASSES:
649 case ICC_TREEVIEW_CLASSES:
650 case ICC_TAB_CLASSES:
651 case ICC_UPDOWN_CLASS:
652 case ICC_PROGRESS_CLASS:
653 case ICC_HOTKEY_CLASS:
656 /* advanced classes - not included in Win95 */
657 case ICC_DATE_CLASSES:
658 MONTHCAL_Register ();
659 DATETIME_Register ();
662 case ICC_USEREX_CLASSES:
666 case ICC_COOL_CLASSES:
670 case ICC_INTERNET_CLASSES:
671 IPADDRESS_Register ();
674 case ICC_PAGESCROLLER_CLASS:
678 case ICC_NATIVEFNTCTL_CLASS:
679 NATIVEFONT_Register ();
687 FIXME("Unknown class! dwICC=0x%lX\n", dwMask);
696 /***********************************************************************
697 * CreateToolbarEx [COMCTL32.@]
699 * Creates a toolbar window.
717 * Success: handle to the tool bar control
722 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
723 HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons,
724 INT iNumButtons, INT dxButton, INT dyButton,
725 INT dxBitmap, INT dyBitmap, UINT uStructSize)
730 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
731 hwnd, (HMENU)wID, COMCTL32_hModule, NULL);
735 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM)uStructSize, 0);
737 /* set bitmap and button size */
738 /*If CreateToolbarEx receives 0, windows sets default values*/
743 SendMessageW (hwndTB, TB_SETBITMAPSIZE, 0,
744 MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap));
750 SendMessageW (hwndTB, TB_SETBUTTONSIZE, 0,
751 MAKELPARAM((WORD)dxButton, (WORD)dyButton));
757 tbab.hInst = hBMInst;
760 SendMessageW (hwndTB, TB_ADDBITMAP, (WPARAM)nBitmaps, (LPARAM)&tbab);
764 SendMessageW (hwndTB, TB_ADDBUTTONSW,
765 (WPARAM)iNumButtons, (LPARAM)lpButtons);
772 /***********************************************************************
773 * CreateMappedBitmap [COMCTL32.8]
775 * Loads a bitmap resource using a colour map.
778 * hInstance [I] Handle to the module containing the bitmap.
779 * idBitmap [I] The bitmap resource ID.
780 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
781 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
782 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
785 * Success: handle to the new bitmap
790 CreateMappedBitmap (HINSTANCE hInstance, INT idBitmap, UINT wFlags,
791 LPCOLORMAP lpColorMap, INT iNumMaps)
795 LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
796 UINT nSize, nColorTableSize, iColor;
797 RGBQUAD *pColorTable;
798 INT i, iMaps, nWidth, nHeight;
801 LPCOLORMAP sysColorMap;
803 COLORMAP internalColorMap[4] =
804 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
806 /* initialize pointer to colortable and default color table */
809 sysColorMap = lpColorMap;
812 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
813 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
814 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
815 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
817 sysColorMap = (LPCOLORMAP)internalColorMap;
820 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
823 hglb = LoadResource (hInstance, hRsrc);
826 lpBitmap = (LPBITMAPINFOHEADER)LockResource (hglb);
827 if (lpBitmap == NULL)
830 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
831 nColorTableSize = lpBitmap->biClrUsed;
832 else if (lpBitmap->biBitCount <= 8)
833 nColorTableSize = (1 << lpBitmap->biBitCount);
836 nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
837 lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize);
838 if (lpBitmapInfo == NULL)
840 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
842 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)lpBitmapInfo->biSize);
844 for (iColor = 0; iColor < nColorTableSize; iColor++) {
845 for (i = 0; i < iMaps; i++) {
846 cRef = RGB(pColorTable[iColor].rgbRed,
847 pColorTable[iColor].rgbGreen,
848 pColorTable[iColor].rgbBlue);
849 if ( cRef == sysColorMap[i].from) {
851 if (wFlags & CBS_MASKED) {
852 if (sysColorMap[i].to != COLOR_BTNTEXT)
853 pColorTable[iColor] = RGB(255, 255, 255);
857 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
858 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
859 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
864 nWidth = (INT)lpBitmapInfo->biWidth;
865 nHeight = (INT)lpBitmapInfo->biHeight;
866 hdcScreen = GetDC (NULL);
867 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
869 HDC hdcDst = CreateCompatibleDC (hdcScreen);
870 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
871 LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
872 lpBits += nColorTableSize * sizeof(RGBQUAD);
873 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
874 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
876 SelectObject (hdcDst, hbmOld);
879 ReleaseDC (NULL, hdcScreen);
880 GlobalFree ((HGLOBAL)lpBitmapInfo);
887 /***********************************************************************
888 * CreateToolbar [COMCTL32.7]
890 * Creates a toolbar control.
903 * Success: handle to the tool bar control
907 * Do not use this functions anymore. Use CreateToolbarEx instead.
911 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
912 HINSTANCE hBMInst, UINT wBMID,
913 LPCTBBUTTON lpButtons,INT iNumButtons)
915 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
916 hBMInst, wBMID, lpButtons,
917 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
921 /***********************************************************************
922 * DllGetVersion [COMCTL32.@]
924 * Retrieves version information of the 'COMCTL32.DLL'
927 * pdvi [O] pointer to version information structure.
931 * Failure: E_INVALIDARG
934 * Returns version of a comctl32.dll from IE4.01 SP1.
938 COMCTL32_DllGetVersion (DLLVERSIONINFO *pdvi)
940 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
941 WARN("wrong DLLVERSIONINFO size from app\n");
945 pdvi->dwMajorVersion = COMCTL32_VERSION;
946 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
947 pdvi->dwBuildNumber = 2919;
948 pdvi->dwPlatformID = 6304;
950 TRACE("%lu.%lu.%lu.%lu\n",
951 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
952 pdvi->dwBuildNumber, pdvi->dwPlatformID);
957 /***********************************************************************
958 * DllInstall (COMCTL32.@)
960 * Installs the ComCtl32 DLL.
964 * Failure: A HRESULT error
966 HRESULT WINAPI COMCTL32_DllInstall(BOOL bInstall, LPCWSTR cmdline)
968 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
969 debugstr_w(cmdline));
974 /***********************************************************************
975 * _TrackMouseEvent [COMCTL32.@]
977 * Requests notification of mouse events
979 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
980 * to the hwnd specified in the ptme structure. After the event message
981 * is posted to the hwnd, the entry in the queue is removed.
983 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
984 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
985 * immediately and the TME_LEAVE flag being ignored.
988 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
994 * IMPLEMENTATION moved to USER32.TrackMouseEvent
999 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1001 return TrackMouseEvent (ptme);
1004 /*************************************************************************
1005 * GetMUILanguage [COMCTL32.@]
1007 * Returns the user interface language in use by the current process.
1010 * Language ID in use by the current process.
1012 LANGID WINAPI GetMUILanguage (VOID)
1014 return COMCTL32_uiLang;
1018 /*************************************************************************
1019 * InitMUILanguage [COMCTL32.@]
1021 * Sets the user interface language to be used by the current process.
1026 VOID WINAPI InitMUILanguage (LANGID uiLang)
1028 COMCTL32_uiLang = uiLang;
1032 /***********************************************************************
1033 * SetWindowSubclass [COMCTL32.410]
1035 * Starts a window subclass
1038 * hWnd [in] handle to window subclass.
1039 * pfnSubclass [in] Pointer to new window procedure.
1040 * uIDSubclass [in] Unique identifier of sublass together with pfnSubclass.
1041 * dwRef [in] Reference data to pass to window procedure.
1048 * If an application manually subclasses a window after subclassing it with
1049 * this API and then with this API again, then none of the previous
1050 * subclasses get called or the origional window procedure.
1053 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1054 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1056 LPSUBCLASS_INFO stack;
1057 LPSUBCLASSPROCS proc;
1059 TRACE ("(%p, %p, %x, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1061 /* Since the window procedure that we set here has two additional arguments,
1062 * we can't simply set it as the new window procedure of the window. So we
1063 * set our own window procedure and then calculate the other two arguments
1066 /* See if we have been called for this window */
1067 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1069 /* allocate stack */
1070 stack = Alloc (sizeof(SUBCLASS_INFO));
1072 ERR ("Failed to allocate our Subclassing stack\n");
1075 SetPropW (hWnd, COMCTL32_wSubclass, (HANDLE)stack);
1077 /* set window procedure to our own and save the current one */
1078 if (IsWindowUnicode (hWnd))
1079 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1080 (DWORD_PTR)COMCTL32_SubclassProc);
1082 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1083 (DWORD_PTR)COMCTL32_SubclassProc);
1086 /* Check to see if we have called this function with the same uIDSubClass
1087 * and pfnSubclass */
1088 proc = stack->SubclassProcs;
1090 if ((proc->id == uIDSubclass) &&
1091 (proc->subproc == pfnSubclass)) {
1099 proc = Alloc(sizeof(SUBCLASSPROCS));
1101 ERR ("Failed to allocate subclass entry in stack\n");
1102 if (IsWindowUnicode (hWnd))
1103 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1105 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1107 RemovePropW( hWnd, COMCTL32_wSubclass );
1111 proc->subproc = pfnSubclass;
1113 proc->id = uIDSubclass;
1114 proc->next = stack->SubclassProcs;
1115 stack->SubclassProcs = proc;
1121 /***********************************************************************
1122 * GetWindowSubclass [COMCTL32.411]
1124 * Gets the Reference data from a subclass.
1127 * hWnd [in] Handle to window which were subclassing
1128 * pfnSubclass [in] Pointer to the subclass procedure
1129 * uID [in] Unique indentifier of the subclassing procedure
1130 * pdwRef [out] Pointer to the reference data
1137 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1138 UINT_PTR uID, DWORD_PTR *pdwRef)
1140 LPSUBCLASS_INFO stack;
1141 LPSUBCLASSPROCS proc;
1143 TRACE ("(%p, %p, %x, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1145 /* See if we have been called for this window */
1146 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1150 proc = stack->SubclassProcs;
1152 if ((proc->id == uID) &&
1153 (proc->subproc == pfnSubclass)) {
1154 *pdwRef = proc->ref;
1164 /***********************************************************************
1165 * RemoveWindowSubclass [COMCTL32.412]
1167 * Removes a window subclass.
1170 * hWnd [in] Handle to the window were subclassing
1171 * pfnSubclass [in] Pointer to the subclass procedure
1172 * uID [in] Unique identifier of this subclass
1179 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1181 LPSUBCLASS_INFO stack;
1182 LPSUBCLASSPROCS prevproc = NULL;
1183 LPSUBCLASSPROCS proc;
1186 TRACE ("(%p, %p, %x)\n", hWnd, pfnSubclass, uID);
1188 /* Find the Subclass to remove */
1189 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1193 proc = stack->SubclassProcs;
1195 if ((proc->id == uID) &&
1196 (proc->subproc == pfnSubclass)) {
1199 stack->SubclassProcs = proc->next;
1201 prevproc->next = proc->next;
1203 if (stack->stackpos == proc)
1204 stack->stackpos = stack->stackpos->next;
1214 if (!stack->SubclassProcs && !stack->running) {
1215 TRACE("Last Subclass removed, cleaning up\n");
1216 /* clean up our heap and reset the origional window procedure */
1217 if (IsWindowUnicode (hWnd))
1218 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1220 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1222 RemovePropW( hWnd, COMCTL32_wSubclass );
1228 /***********************************************************************
1229 * COMCTL32_SubclassProc (internal)
1231 * Window procedure for all subclassed windows.
1232 * Saves the current subclassing stack position to support nested messages
1234 LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1236 LPSUBCLASS_INFO stack;
1237 LPSUBCLASSPROCS proc;
1240 TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1242 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1244 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1248 /* Save our old stackpos to properly handle nested messages */
1249 proc = stack->stackpos;
1250 stack->stackpos = stack->SubclassProcs;
1252 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1254 stack->stackpos = proc;
1256 if (!stack->SubclassProcs && !stack->running) {
1257 TRACE("Last Subclass removed, cleaning up\n");
1258 /* clean up our heap and reset the origional window procedure */
1259 if (IsWindowUnicode (hWnd))
1260 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1262 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1264 RemovePropW( hWnd, COMCTL32_wSubclass );
1269 /***********************************************************************
1270 * DefSubclassProc [COMCTL32.413]
1272 * Calls the next window procedure (ie. the one before this subclass)
1275 * hWnd [in] The window that we're subclassing
1277 * wParam [in] WPARAM
1278 * lParam [in] LPARAM
1285 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1287 LPSUBCLASS_INFO stack;
1290 TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1292 /* retrieve our little stack from the Properties */
1293 stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1295 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1299 /* If we are at the end of stack then we have to call the original
1300 * window procedure */
1301 if (!stack->stackpos) {
1302 if (IsWindowUnicode (hWnd))
1303 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1305 ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1307 LPSUBCLASSPROCS proc = stack->stackpos;
1308 stack->stackpos = stack->stackpos->next;
1309 /* call the Subclass procedure from the stack */
1310 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1311 proc->id, proc->ref);
1318 /***********************************************************************
1319 * COMCTL32_CreateToolTip [NOT AN API]
1321 * Creates a tooltip for the control specified in hwnd and does all
1322 * necessary setup and notifications.
1325 * hwndOwner [I] Handle to the window that will own the tool tip.
1328 * Success: Handle of tool tip window.
1333 COMCTL32_CreateToolTip(HWND hwndOwner)
1337 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
1338 CW_USEDEFAULT, CW_USEDEFAULT,
1339 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1342 /* Send NM_TOOLTIPSCREATED notification */
1345 NMTOOLTIPSCREATED nmttc;
1346 /* true owner can be different if hwndOwner is a child window */
1347 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1348 nmttc.hdr.hwndFrom = hwndTrueOwner;
1349 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1350 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1351 nmttc.hwndToolTips = hwndToolTip;
1353 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1354 (WPARAM)GetWindowLongPtrW(hwndTrueOwner, GWLP_ID),
1362 /***********************************************************************
1363 * COMCTL32_RefreshSysColors [NOT AN API]
1365 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1366 * refresh the color values in the color structure
1376 COMCTL32_RefreshSysColors(void)
1378 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1379 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1380 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1381 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1382 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1383 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1384 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1385 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1386 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1387 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1388 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1389 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1390 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1391 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1392 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1393 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1396 /***********************************************************************
1397 * COMCTL32_DrawInsertMark [NOT AN API]
1399 * Draws an insertion mark (which looks similar to an 'I').
1402 * hDC [I] Device context to draw onto.
1403 * lpRect [I] Co-ordinates of insertion mark.
1404 * clrInsertMark [I] Colour of the insertion mark.
1405 * bHorizontal [I] True if insert mark should be drawn horizontally,
1406 * vertical otherwise.
1412 * Draws up to but not including the bottom co-ordinate when drawing
1413 * vertically or the right co-ordinate when horizontal.
1415 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1417 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1419 static const DWORD adwPolyPoints[] = {4,4,4};
1420 LONG lCentre = (bHorizontal ?
1421 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1422 lpRect->left + (lpRect->right - lpRect->left)/2);
1423 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1424 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1425 const POINT aptInsertMark[] =
1427 /* top (V) or left (H) arrow */
1431 {lCentre + 1, l1 + 2},
1435 {lCentre + 1, l1 - 1},
1436 {lCentre + 1, l2 - 2},
1437 /* bottom (V) or right (H) arrow */
1439 {lCentre - 2, l2 - 1},
1440 {lCentre + 3, l2 - 1},
1441 {lCentre + 1, l2 - 3},
1443 hOldPen = SelectObject(hDC, hPen);
1444 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0]));
1445 SelectObject(hDC, hOldPen);
1449 /***********************************************************************
1450 * MirrorIcon [COMCTL32.414]
1452 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1455 * phicon1 [I/O] Icon.
1456 * phicon2 [I/O] Icon.
1462 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1464 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1468 static inline int IsDelimiter(WCHAR c)
1481 static int CALLBACK PathWordBreakProc(LPWSTR lpch, int ichCurrent, int cch, int code)
1483 if (code == WB_ISDELIMITER)
1484 return IsDelimiter(lpch[ichCurrent]);
1487 int dir = (code == WB_LEFT) ? -1 : 1;
1488 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1489 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1494 /***********************************************************************
1495 * SetPathWordBreakProc [COMCTL32.384]
1497 * Sets the word break procedure for an edit control to one that understands
1498 * paths so that the user can jump over directories.
1501 * hwnd [I] Handle to edit control.
1502 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1505 * Result from EM_SETWORDBREAKPROC message.
1507 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1509 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1510 (LPARAM)(bSet ? PathWordBreakProc : NULL));