Added CS_DBLCLKS so that systray receives double clicks.
[wine/multimedia.git] / dlls / comctl32 / commctrl.c
blobe39bcd64060c5d2b1678c3bbab9a4017c1138938
1 /*
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
21 * NOTES
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 belive this code to be complete, as per
27 * the specification mentioned above.
28 * If you discover missing features, or bugs, please note them below.
30 * TODO
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)
37 * Control Classes
38 * -- ICC_ANIMATE_CLASS
39 * -- ICC_BAR_CLASSES
40 * -- ICC_COOL_CLASSES
41 * -- ICC_DATE_CLASSES
42 * -- ICC_HOTKEY_CLASS
43 * -- ICC_INTERNET_CLASSES
44 * -- ICC_LINK_CLASS (not yet implemented)
45 * -- ICC_LISTVIEW_CLASSES
46 * -- ICC_NATIVEFNTCTL_CLASS
47 * -- ICC_PAGESCROLLER_CLASS
48 * -- ICC_PROGRESS_CLASS
49 * -- ICC_STANDARD_CLASSES (not yet implemented)
50 * -- ICC_TAB_CLASSES
51 * -- ICC_TREEVIEW_CLASSES
52 * -- ICC_UPDOWN_CLASS
53 * -- ICC_USEREX_CLASSES
54 * -- ICC_WIN95_CLASSES
57 #include <string.h>
58 #include <stdlib.h>
60 #include "winbase.h"
61 #include "commctrl.h"
62 #include "winerror.h"
63 #include "winreg.h"
64 #define NO_SHLWAPI_STREAM
65 #include "shlwapi.h"
66 #include "comctl32.h"
67 #include "wine/debug.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
71 extern void ANIMATE_Register(void);
72 extern void ANIMATE_Unregister(void);
73 extern void COMBOEX_Register(void);
74 extern void COMBOEX_Unregister(void);
75 extern void DATETIME_Register(void);
76 extern void DATETIME_Unregister(void);
77 extern void FLATSB_Register(void);
78 extern void FLATSB_Unregister(void);
79 extern void HEADER_Register(void);
80 extern void HEADER_Unregister(void);
81 extern void HOTKEY_Register(void);
82 extern void HOTKEY_Unregister(void);
83 extern void IPADDRESS_Register(void);
84 extern void IPADDRESS_Unregister(void);
85 extern void LISTVIEW_Register(void);
86 extern void LISTVIEW_Unregister(void);
87 extern void MONTHCAL_Register(void);
88 extern void MONTHCAL_Unregister(void);
89 extern void NATIVEFONT_Register(void);
90 extern void NATIVEFONT_Unregister(void);
91 extern void PAGER_Register(void);
92 extern void PAGER_Unregister(void);
93 extern void PROGRESS_Register(void);
94 extern void PROGRESS_Unregister(void);
95 extern void REBAR_Register(void);
96 extern void REBAR_Unregister(void);
97 extern void STATUS_Register(void);
98 extern void STATUS_Unregister(void);
99 extern void TAB_Register(void);
100 extern void TAB_Unregister(void);
101 extern void TOOLBAR_Register(void);
102 extern void TOOLBAR_Unregister(void);
103 extern void TOOLTIPS_Register(void);
104 extern void TOOLTIPS_Unregister(void);
105 extern void TRACKBAR_Register(void);
106 extern void TRACKBAR_Unregister(void);
107 extern void TREEVIEW_Register(void);
108 extern void TREEVIEW_Unregister(void);
109 extern void UPDOWN_Register(void);
110 extern void UPDOWN_Unregister(void);
113 HANDLE COMCTL32_hHeap = (HANDLE)NULL;
114 LPSTR COMCTL32_aSubclass = (LPSTR)NULL;
115 HMODULE COMCTL32_hModule = 0;
116 LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
117 HBRUSH COMCTL32_hPattern55AABrush = (HANDLE)NULL;
118 COMCTL32_SysColor comctl32_color;
120 static HBITMAP COMCTL32_hPattern55AABitmap = (HANDLE)NULL;
122 static const WORD wPattern55AA[] =
124 0x5555, 0xaaaa, 0x5555, 0xaaaa,
125 0x5555, 0xaaaa, 0x5555, 0xaaaa
129 /***********************************************************************
130 * DllMain [Internal] Initializes the internal 'COMCTL32.DLL'.
132 * PARAMS
133 * hinstDLL [I] handle to the 'dlls' instance
134 * fdwReason [I]
135 * lpvReserved [I] reserverd, must be NULL
137 * RETURNS
138 * Success: TRUE
139 * Failure: FALSE
142 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
144 TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
146 switch (fdwReason) {
147 case DLL_PROCESS_ATTACH:
148 COMCTL32_hModule = (HMODULE)hinstDLL;
150 /* create private heap */
151 COMCTL32_hHeap = HeapCreate (0, 0x10000, 0);
152 TRACE("Heap created: %p\n", COMCTL32_hHeap);
154 /* add global subclassing atom (used by 'tooltip' and 'updown') */
155 COMCTL32_aSubclass = (LPSTR)(DWORD)GlobalAddAtomA ("CC32SubclassInfo");
156 TRACE("Subclassing atom added: %p\n", COMCTL32_aSubclass);
158 /* create local pattern brush */
159 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
160 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
162 /* Get all the colors at DLL load */
163 COMCTL32_RefreshSysColors();
165 /* register all Win95 common control classes */
166 ANIMATE_Register ();
167 FLATSB_Register ();
168 HEADER_Register ();
169 HOTKEY_Register ();
170 LISTVIEW_Register ();
171 PROGRESS_Register ();
172 STATUS_Register ();
173 TAB_Register ();
174 TOOLBAR_Register ();
175 TOOLTIPS_Register ();
176 TRACKBAR_Register ();
177 TREEVIEW_Register ();
178 UPDOWN_Register ();
179 break;
181 case DLL_PROCESS_DETACH:
182 /* unregister all common control classes */
183 ANIMATE_Unregister ();
184 COMBOEX_Unregister ();
185 DATETIME_Unregister ();
186 FLATSB_Unregister ();
187 HEADER_Unregister ();
188 HOTKEY_Unregister ();
189 IPADDRESS_Unregister ();
190 LISTVIEW_Unregister ();
191 MONTHCAL_Unregister ();
192 NATIVEFONT_Unregister ();
193 PAGER_Unregister ();
194 PROGRESS_Unregister ();
195 REBAR_Unregister ();
196 STATUS_Unregister ();
197 TAB_Unregister ();
198 TOOLBAR_Unregister ();
199 TOOLTIPS_Unregister ();
200 TRACKBAR_Unregister ();
201 TREEVIEW_Unregister ();
202 UPDOWN_Unregister ();
204 /* delete local pattern brush */
205 DeleteObject (COMCTL32_hPattern55AABrush);
206 COMCTL32_hPattern55AABrush = (HANDLE)NULL;
207 DeleteObject (COMCTL32_hPattern55AABitmap);
208 COMCTL32_hPattern55AABitmap = (HANDLE)NULL;
210 /* delete global subclassing atom */
211 GlobalDeleteAtom (LOWORD(COMCTL32_aSubclass));
212 TRACE("Subclassing atom deleted: %p\n", COMCTL32_aSubclass);
213 COMCTL32_aSubclass = (LPSTR)NULL;
215 /* destroy private heap */
216 HeapDestroy (COMCTL32_hHeap);
217 TRACE("Heap destroyed: %p\n", COMCTL32_hHeap);
218 COMCTL32_hHeap = (HANDLE)NULL;
219 break;
222 return TRUE;
226 /***********************************************************************
227 * MenuHelp [COMCTL32.2]
229 * PARAMS
230 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
231 * wParam [I] wParam of the message uMsg
232 * lParam [I] lParam of the message uMsg
233 * hMainMenu [I] handle to the application's main menu
234 * hInst [I] handle to the module that contains string resources
235 * hwndStatus [I] handle to the status bar window
236 * lpwIDs [I] pointer to an array of integers (see NOTES)
238 * RETURNS
239 * No return value
241 * NOTES
242 * The official documentation is incomplete!
243 * This is the correct documentation:
245 * uMsg:
246 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
247 * WM_MENUSELECT messages.
249 * lpwIDs:
250 * (will be written ...)
253 VOID WINAPI
254 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
255 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
257 UINT uMenuID = 0;
259 if (!IsWindow (hwndStatus))
260 return;
262 switch (uMsg) {
263 case WM_MENUSELECT:
264 TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n",
265 wParam, lParam);
267 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
268 /* menu was closed */
269 TRACE("menu was closed!\n");
270 SendMessageA (hwndStatus, SB_SIMPLE, FALSE, 0);
272 else {
273 /* menu item was selected */
274 if (HIWORD(wParam) & MF_POPUP)
275 uMenuID = (UINT)*(lpwIDs+1);
276 else
277 uMenuID = (UINT)LOWORD(wParam);
278 TRACE("uMenuID = %u\n", uMenuID);
280 if (uMenuID) {
281 CHAR szText[256];
283 if (!LoadStringA (hInst, uMenuID, szText, 256))
284 szText[0] = '\0';
286 SendMessageA (hwndStatus, SB_SETTEXTA,
287 255 | SBT_NOBORDERS, (LPARAM)szText);
288 SendMessageA (hwndStatus, SB_SIMPLE, TRUE, 0);
291 break;
293 case WM_COMMAND :
294 TRACE("WM_COMMAND wParam=0x%X lParam=0x%lX\n",
295 wParam, lParam);
296 /* WM_COMMAND is not invalid since it is documented
297 * in the windows api reference. So don't output
298 * any FIXME for WM_COMMAND
300 WARN("We don't care about the WM_COMMAND\n");
301 break;
303 default:
304 FIXME("Invalid Message 0x%x!\n", uMsg);
305 break;
310 /***********************************************************************
311 * ShowHideMenuCtl [COMCTL32.3]
313 * Shows or hides controls and updates the corresponding menu item.
315 * PARAMS
316 * hwnd [I] handle to the client window.
317 * uFlags [I] menu command id.
318 * lpInfo [I] pointer to an array of integers. (See NOTES.)
320 * RETURNS
321 * Success: TRUE
322 * Failure: FALSE
324 * NOTES
325 * The official documentation is incomplete!
326 * This is the correct documentation:
328 * hwnd
329 * Handle to the window that contains the menu and controls.
331 * uFlags
332 * Identifier of the menu item to receive or loose a check mark.
334 * lpInfo
335 * The array of integers contains pairs of values. BOTH values of
336 * the first pair must be the handles to the application's main menu.
337 * Each subsequent pair consists of a menu id and control id.
340 BOOL WINAPI
341 ShowHideMenuCtl (HWND hwnd, UINT uFlags, LPINT lpInfo)
343 LPINT lpMenuId;
345 TRACE("%p, %x, %p\n", hwnd, uFlags, lpInfo);
347 if (lpInfo == NULL)
348 return FALSE;
350 if (!(lpInfo[0]) || !(lpInfo[1]))
351 return FALSE;
353 /* search for control */
354 lpMenuId = &lpInfo[2];
355 while (*lpMenuId != uFlags)
356 lpMenuId += 2;
358 if (GetMenuState ((HMENU)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
359 /* uncheck menu item */
360 CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
362 /* hide control */
363 lpMenuId++;
364 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
365 SWP_HIDEWINDOW);
367 else {
368 /* check menu item */
369 CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
371 /* show control */
372 lpMenuId++;
373 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
374 SWP_SHOWWINDOW);
377 return TRUE;
381 /***********************************************************************
382 * GetEffectiveClientRect [COMCTL32.4]
384 * PARAMS
385 * hwnd [I] handle to the client window.
386 * lpRect [O] pointer to the rectangle of the client window
387 * lpInfo [I] pointer to an array of integers (see NOTES)
389 * RETURNS
390 * No return value.
392 * NOTES
393 * The official documentation is incomplete!
394 * This is the correct documentation:
396 * lpInfo
397 * (will be written ...)
400 VOID WINAPI
401 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo)
403 RECT rcCtrl;
404 INT *lpRun;
405 HWND hwndCtrl;
407 TRACE("(0x%08lx 0x%08lx 0x%08lx)\n",
408 (DWORD)hwnd, (DWORD)lpRect, (DWORD)lpInfo);
410 GetClientRect (hwnd, lpRect);
411 lpRun = lpInfo;
413 do {
414 lpRun += 2;
415 if (*lpRun == 0)
416 return;
417 lpRun++;
418 hwndCtrl = GetDlgItem (hwnd, *lpRun);
419 if (GetWindowLongA (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
420 TRACE("control id 0x%x\n", *lpRun);
421 GetWindowRect (hwndCtrl, &rcCtrl);
422 MapWindowPoints ((HWND)0, hwnd, (LPPOINT)&rcCtrl, 2);
423 SubtractRect (lpRect, lpRect, &rcCtrl);
425 lpRun++;
426 } while (*lpRun);
430 /***********************************************************************
431 * DrawStatusTextW [COMCTL32.@]
433 * Draws text with borders, like in a status bar.
435 * PARAMS
436 * hdc [I] handle to the window's display context
437 * lprc [I] pointer to a rectangle
438 * text [I] pointer to the text
439 * style [I] drawing style
441 * RETURNS
442 * No return value.
444 * NOTES
445 * The style variable can have one of the following values:
446 * (will be written ...)
449 void WINAPI DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style)
451 RECT r = *lprc;
452 UINT border = BDR_SUNKENOUTER;
454 if (style & SBT_POPOUT)
455 border = BDR_RAISEDOUTER;
456 else if (style & SBT_NOBORDERS)
457 border = 0;
459 DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
461 /* now draw text */
462 if (text) {
463 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
464 UINT align = DT_LEFT;
465 if (*text == L'\t') {
466 text++;
467 align = DT_CENTER;
468 if (*text == L'\t') {
469 text++;
470 align = DT_RIGHT;
473 r.left += 3;
474 if (style & SBT_RTLREADING)
475 FIXME("Unsupported RTL style!\n");
476 DrawTextW (hdc, text, -1, &r, align|DT_VCENTER|DT_SINGLELINE);
477 SetBkMode(hdc, oldbkmode);
482 /***********************************************************************
483 * DrawStatusText [COMCTL32.@]
484 * DrawStatusTextA [COMCTL32.5]
486 * Draws text with borders, like in a status bar.
488 * PARAMS
489 * hdc [I] handle to the window's display context
490 * lprc [I] pointer to a rectangle
491 * text [I] pointer to the text
492 * style [I] drawing style
494 * RETURNS
495 * No return value.
498 void WINAPI DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style)
500 INT len;
501 LPWSTR textW = NULL;
503 if ( text ) {
504 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
505 if ( (textW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )) )
506 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
509 DrawStatusTextW( hdc, lprc, textW, style );
510 HeapFree( GetProcessHeap(), 0, textW );
514 /***********************************************************************
515 * CreateStatusWindow [COMCTL32.@]
516 * CreateStatusWindowA [COMCTL32.6]
518 * Creates a status bar
520 * PARAMS
521 * style [I] window style
522 * text [I] pointer to the window text
523 * parent [I] handle to the parent window
524 * wid [I] control id of the status bar
526 * RETURNS
527 * Success: handle to the status window
528 * Failure: 0
531 HWND WINAPI
532 CreateStatusWindowA (INT style, LPCSTR text, HWND parent, UINT wid)
534 return CreateWindowA(STATUSCLASSNAMEA, text, style,
535 CW_USEDEFAULT, CW_USEDEFAULT,
536 CW_USEDEFAULT, CW_USEDEFAULT,
537 parent, (HMENU)wid, 0, 0);
541 /***********************************************************************
542 * CreateStatusWindowW [COMCTL32.@] Creates a status bar control
544 * PARAMS
545 * style [I] window style
546 * text [I] pointer to the window text
547 * parent [I] handle to the parent window
548 * wid [I] control id of the status bar
550 * RETURNS
551 * Success: handle to the status window
552 * Failure: 0
555 HWND WINAPI
556 CreateStatusWindowW (INT style, LPCWSTR text, HWND parent, UINT wid)
558 return CreateWindowW(STATUSCLASSNAMEW, text, style,
559 CW_USEDEFAULT, CW_USEDEFAULT,
560 CW_USEDEFAULT, CW_USEDEFAULT,
561 parent, (HMENU)wid, 0, 0);
565 /***********************************************************************
566 * CreateUpDownControl [COMCTL32.16] Creates an up-down control
568 * PARAMS
569 * style [I] window styles
570 * x [I] horizontal position of the control
571 * y [I] vertical position of the control
572 * cx [I] with of the control
573 * cy [I] height of the control
574 * parent [I] handle to the parent window
575 * id [I] the control's identifier
576 * inst [I] handle to the application's module instance
577 * buddy [I] handle to the buddy window, can be NULL
578 * maxVal [I] upper limit of the control
579 * minVal [I] lower limit of the control
580 * curVal [I] current value of the control
582 * RETURNS
583 * Success: handle to the updown control
584 * Failure: 0
587 HWND WINAPI
588 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
589 HWND parent, INT id, HINSTANCE inst,
590 HWND buddy, INT maxVal, INT minVal, INT curVal)
592 HWND hUD =
593 CreateWindowA (UPDOWN_CLASSA, 0, style, x, y, cx, cy,
594 parent, (HMENU)id, inst, 0);
595 if (hUD) {
596 SendMessageA (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
597 SendMessageA (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
598 SendMessageA (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
601 return hUD;
605 /***********************************************************************
606 * InitCommonControls [COMCTL32.17]
608 * Registers the common controls.
610 * PARAMS
611 * No parameters.
613 * RETURNS
614 * No return values.
616 * NOTES
617 * This function is just a dummy.
618 * The Win95 controls are registered at the DLL's initialization.
619 * To register other controls InitCommonControlsEx() must be used.
622 VOID WINAPI
623 InitCommonControls (void)
628 /***********************************************************************
629 * InitCommonControlsEx [COMCTL32.@]
631 * Registers the common controls.
633 * PARAMS
634 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
636 * RETURNS
637 * Success: TRUE
638 * Failure: FALSE
640 * NOTES
641 * Only the additional common controls are registered by this function.
642 * The Win95 controls are registered at the DLL's initialization.
644 * FIXME
645 * implement the following control classes:
646 * ICC_LINK_CLASS
647 * ICC_STANDARD_CLASSES
650 BOOL WINAPI
651 InitCommonControlsEx (LPINITCOMMONCONTROLSEX lpInitCtrls)
653 INT cCount;
654 DWORD dwMask;
656 if (!lpInitCtrls)
657 return FALSE;
658 if (lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
659 return FALSE;
661 TRACE("(0x%08lx)\n", lpInitCtrls->dwICC);
663 for (cCount = 0; cCount < 32; cCount++) {
664 dwMask = 1 << cCount;
665 if (!(lpInitCtrls->dwICC & dwMask))
666 continue;
668 switch (lpInitCtrls->dwICC & dwMask) {
669 /* dummy initialization */
670 case ICC_ANIMATE_CLASS:
671 case ICC_BAR_CLASSES:
672 case ICC_LISTVIEW_CLASSES:
673 case ICC_TREEVIEW_CLASSES:
674 case ICC_TAB_CLASSES:
675 case ICC_UPDOWN_CLASS:
676 case ICC_PROGRESS_CLASS:
677 case ICC_HOTKEY_CLASS:
678 break;
680 /* advanced classes - not included in Win95 */
681 case ICC_DATE_CLASSES:
682 MONTHCAL_Register ();
683 DATETIME_Register ();
684 break;
686 case ICC_USEREX_CLASSES:
687 COMBOEX_Register ();
688 break;
690 case ICC_COOL_CLASSES:
691 REBAR_Register ();
692 break;
694 case ICC_INTERNET_CLASSES:
695 IPADDRESS_Register ();
696 break;
698 case ICC_PAGESCROLLER_CLASS:
699 PAGER_Register ();
700 break;
702 case ICC_NATIVEFNTCTL_CLASS:
703 NATIVEFONT_Register ();
704 break;
706 default:
707 FIXME("Unknown class! dwICC=0x%lX\n", dwMask);
708 break;
712 return TRUE;
716 /***********************************************************************
717 * CreateToolbarEx [COMCTL32.@] Creates a tool bar window
719 * PARAMS
720 * hwnd
721 * style
722 * wID
723 * nBitmaps
724 * hBMInst
725 * wBMID
726 * lpButtons
727 * iNumButtons
728 * dxButton
729 * dyButton
730 * dxBitmap
731 * dyBitmap
732 * uStructSize
734 * RETURNS
735 * Success: handle to the tool bar control
736 * Failure: 0
739 HWND WINAPI
740 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
741 HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons,
742 INT iNumButtons, INT dxButton, INT dyButton,
743 INT dxBitmap, INT dyBitmap, UINT uStructSize)
745 HWND hwndTB;
747 /* If not position is specified then put it at the top */
748 if ((style & CCS_BOTTOM) == 0) {
749 style|=CCS_TOP;
752 hwndTB =
753 CreateWindowExA (0, TOOLBARCLASSNAMEA, "", style|WS_CHILD, 0, 0, 0, 0,
754 hwnd, (HMENU)wID, 0, NULL);
755 if(hwndTB) {
756 TBADDBITMAP tbab;
758 SendMessageA (hwndTB, TB_BUTTONSTRUCTSIZE,
759 (WPARAM)uStructSize, 0);
761 /* set bitmap and button size */
762 /*If CreateToolbarEx receives 0, windows sets default values*/
763 if (dxBitmap <= 0)
764 dxBitmap = 16;
765 if (dyBitmap <= 0)
766 dyBitmap = 15;
767 SendMessageA (hwndTB, TB_SETBITMAPSIZE, 0,
768 MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap));
770 if (dxButton <= 0)
771 dxButton = 24;
772 if (dyButton <= 0)
773 dyButton = 22;
774 SendMessageA (hwndTB, TB_SETBUTTONSIZE, 0,
775 MAKELPARAM((WORD)dxButton, (WORD)dyButton));
778 /* add bitmaps */
779 if (nBitmaps > 0)
781 tbab.hInst = hBMInst;
782 tbab.nID = wBMID;
784 SendMessageA (hwndTB, TB_ADDBITMAP,
785 (WPARAM)nBitmaps, (LPARAM)&tbab);
787 /* add buttons */
788 if(iNumButtons > 0)
789 SendMessageA (hwndTB, TB_ADDBUTTONSA,
790 (WPARAM)iNumButtons, (LPARAM)lpButtons);
793 return hwndTB;
797 /***********************************************************************
798 * CreateMappedBitmap [COMCTL32.8]
800 * PARAMS
801 * hInstance [I]
802 * idBitmap [I]
803 * wFlags [I]
804 * lpColorMap [I]
805 * iNumMaps [I]
807 * RETURNS
808 * Success: handle to the new bitmap
809 * Failure: 0
812 HBITMAP WINAPI
813 CreateMappedBitmap (HINSTANCE hInstance, INT idBitmap, UINT wFlags,
814 LPCOLORMAP lpColorMap, INT iNumMaps)
816 HGLOBAL hglb;
817 HRSRC hRsrc;
818 LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
819 UINT nSize, nColorTableSize;
820 RGBQUAD *pColorTable;
821 INT iColor, i, iMaps, nWidth, nHeight;
822 HDC hdcScreen;
823 HBITMAP hbm;
824 LPCOLORMAP sysColorMap;
825 COLORREF cRef;
826 COLORMAP internalColorMap[4] =
827 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
829 /* initialize pointer to colortable and default color table */
830 if (lpColorMap) {
831 iMaps = iNumMaps;
832 sysColorMap = lpColorMap;
834 else {
835 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
836 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
837 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
838 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
839 iMaps = 4;
840 sysColorMap = (LPCOLORMAP)internalColorMap;
843 hRsrc = FindResourceA (hInstance, (LPSTR)idBitmap, RT_BITMAPA);
844 if (hRsrc == 0)
845 return 0;
846 hglb = LoadResource (hInstance, hRsrc);
847 if (hglb == 0)
848 return 0;
849 lpBitmap = (LPBITMAPINFOHEADER)LockResource (hglb);
850 if (lpBitmap == NULL)
851 return 0;
853 nColorTableSize = (1 << lpBitmap->biBitCount);
854 nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
855 lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize);
856 if (lpBitmapInfo == NULL)
857 return 0;
858 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
860 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)lpBitmapInfo->biSize);
862 for (iColor = 0; iColor < nColorTableSize; iColor++) {
863 for (i = 0; i < iMaps; i++) {
864 cRef = RGB(pColorTable[iColor].rgbRed,
865 pColorTable[iColor].rgbGreen,
866 pColorTable[iColor].rgbBlue);
867 if ( cRef == sysColorMap[i].from) {
868 #if 0
869 if (wFlags & CBS_MASKED) {
870 if (sysColorMap[i].to != COLOR_BTNTEXT)
871 pColorTable[iColor] = RGB(255, 255, 255);
873 else
874 #endif
875 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
876 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
877 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
878 break;
882 nWidth = (INT)lpBitmapInfo->biWidth;
883 nHeight = (INT)lpBitmapInfo->biHeight;
884 hdcScreen = GetDC ((HWND)0);
885 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
886 if (hbm) {
887 HDC hdcDst = CreateCompatibleDC (hdcScreen);
888 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
889 LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
890 lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
891 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
892 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
893 SRCCOPY);
894 SelectObject (hdcDst, hbmOld);
895 DeleteDC (hdcDst);
897 ReleaseDC ((HWND)0, hdcScreen);
898 GlobalFree ((HGLOBAL)lpBitmapInfo);
899 FreeResource (hglb);
901 return hbm;
905 /***********************************************************************
906 * CreateToolbar [COMCTL32.7] Creates a tool bar control
908 * PARAMS
909 * hwnd
910 * style
911 * wID
912 * nBitmaps
913 * hBMInst
914 * wBMID
915 * lpButtons
916 * iNumButtons
918 * RETURNS
919 * Success: handle to the tool bar control
920 * Failure: 0
922 * NOTES
923 * Do not use this functions anymore. Use CreateToolbarEx instead.
926 HWND WINAPI
927 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
928 HINSTANCE hBMInst, UINT wBMID,
929 LPCOLDTBBUTTON lpButtons,INT iNumButtons)
931 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
932 hBMInst, wBMID, (LPCTBBUTTON)lpButtons,
933 iNumButtons, 0, 0, 0, 0, sizeof (OLDTBBUTTON));
937 /***********************************************************************
938 * DllGetVersion [COMCTL32.@]
940 * Retrieves version information of the 'COMCTL32.DLL'
942 * PARAMS
943 * pdvi [O] pointer to version information structure.
945 * RETURNS
946 * Success: S_OK
947 * Failure: E_INVALIDARG
949 * NOTES
950 * Returns version of a comctl32.dll from IE4.01 SP1.
953 HRESULT WINAPI
954 COMCTL32_DllGetVersion (DLLVERSIONINFO *pdvi)
956 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
957 WARN("wrong DLLVERSIONINFO size from app\n");
958 return E_INVALIDARG;
961 pdvi->dwMajorVersion = COMCTL32_VERSION;
962 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
963 pdvi->dwBuildNumber = 2919;
964 pdvi->dwPlatformID = 6304;
966 TRACE("%lu.%lu.%lu.%lu\n",
967 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
968 pdvi->dwBuildNumber, pdvi->dwPlatformID);
970 return S_OK;
973 /***********************************************************************
974 * DllInstall (COMCTL32.@)
976 HRESULT WINAPI COMCTL32_DllInstall(BOOL bInstall, LPCWSTR cmdline)
978 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
979 debugstr_w(cmdline));
981 return S_OK;
984 /***********************************************************************
985 * _TrackMouseEvent [COMCTL32.@]
987 * Requests notification of mouse events
989 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
990 * to the hwnd specified in the ptme structure. After the event message
991 * is posted to the hwnd, the entry in the queue is removed.
993 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
994 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
995 * immediately and the TME_LEAVE flag being ignored.
997 * PARAMS
998 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1000 * RETURNS
1001 * Success: non-zero
1002 * Failure: zero
1004 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1008 BOOL WINAPI
1009 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1011 return TrackMouseEvent (ptme);
1014 /*************************************************************************
1015 * GetMUILanguage [COMCTL32.@]
1017 * FIXME: "Returns the language currently in use by the common controls
1018 * for a particular process." (MSDN)
1021 LANGID WINAPI GetMUILanguage (VOID)
1023 return COMCTL32_uiLang;
1027 /*************************************************************************
1028 * InitMUILanguage [COMCTL32.@]
1030 * FIXME: "Enables an application to specify a language to be used with
1031 * the common controls that is different than the system language." (MSDN)
1035 VOID WINAPI InitMUILanguage (LANGID uiLang)
1037 COMCTL32_uiLang = uiLang;
1041 /***********************************************************************
1042 * SetWindowSubclass [COMCTL32.@]
1044 * Starts a window subclass
1046 * PARAMS
1047 * hWnd [in] handle to window subclass.
1048 * pfnSubclass [in] Pointer to new window procedure.
1049 * uIDSubclass [in] Unique identifier of sublass together with pfnSubclass.
1050 * dwRef [in] Reference data to pass to window procedure.
1052 * RETURNS
1053 * Success: non-zero
1054 * Failure: zero
1056 * BUGS
1057 * If an application manually subclasses a window after subclassing it with
1058 * this API and then with this API again, then none of the previous
1059 * subclasses get called or the origional window procedure.
1062 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1063 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1065 LPSUBCLASS_INFO stack;
1066 int newnum, n;
1068 TRACE ("(%p, %p, %x, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1070 /* Since the window procedure that we set here has two additional arguments,
1071 * we can't simply set it as the new window procedure of the window. So we
1072 * set our own window procedure and then calculate the other two arguments
1073 * from there. */
1075 /* See if we have been called for this window */
1076 stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1077 if (!stack) {
1078 /* allocate stack */
1079 stack = (LPSUBCLASS_INFO)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY,
1080 sizeof(SUBCLASS_INFO));
1081 if (!stack) {
1082 ERR ("Failed to allocate our Subclassing stack");
1083 return FALSE;
1085 SetPropA (hWnd, COMCTL32_aSubclass, (HANDLE)stack);
1087 /* set window procedure to our own and save the current one */
1088 if (IsWindowUnicode (hWnd))
1089 stack->origproc = (WNDPROC)SetWindowLongW (hWnd, GWL_WNDPROC,
1090 (LONG)DefSubclassProc);
1091 else
1092 stack->origproc = (WNDPROC)SetWindowLongA (hWnd, GWL_WNDPROC,
1093 (LONG)DefSubclassProc);
1094 } else {
1095 WNDPROC current;
1096 if (IsWindowUnicode (hWnd))
1097 current = (WNDPROC)GetWindowLongW (hWnd, GWL_WNDPROC);
1098 else
1099 current = (WNDPROC)GetWindowLongA (hWnd, GWL_WNDPROC);
1101 if (current != DefSubclassProc) {
1102 ERR ("Application has subclassed with our procedure, then manually, then with us again. The current implementation can't handle this.\n");
1103 return FALSE;
1107 /* Check to see if we have called this function with the same uIDSubClass
1108 * and pfnSubclass */
1109 for (n = 0; n <= stack->stacknum + stack->stacknew - 1; n++)
1110 if ((stack->SubclassProcs[n].id == uIDSubclass) &&
1111 (stack->SubclassProcs[n].subproc == pfnSubclass)) {
1112 stack->SubclassProcs[n].ref = dwRef;
1113 return TRUE;
1116 if ((stack->stacknum + stack->stacknew) >= 32) {
1117 ERR ("We have a Subclass stack overflow, please increment size");
1118 return FALSE;
1121 /* we can't simply increment both stackpos and stacknum because there might
1122 * be a window procedure running lower in the stack, we can only get them
1123 * up to date once the last window procedure has run */
1124 if (stack->stacknum == stack->stackpos) {
1125 stack->stacknum++;
1126 stack->stackpos++;
1127 } else
1128 stack->stacknew++;
1130 newnum = stack->stacknew + stack->stacknum - 1;
1132 stack->SubclassProcs[newnum].subproc = pfnSubclass;
1133 stack->SubclassProcs[newnum].ref = dwRef;
1134 stack->SubclassProcs[newnum].id = uIDSubclass;
1136 return TRUE;
1140 /***********************************************************************
1141 * GetWindowSubclass [COMCTL32.@]
1143 * Gets the Reference data from a subclass.
1145 * PARAMS
1146 * hWnd [in] Handle to window which were subclassing
1147 * pfnSubclass [in] Pointer to the subclass procedure
1148 * iID [in] Unique indentifier of the subclassing procedure
1149 * pdwRef [out] Pointer to the reference data
1151 * RETURNS
1152 * Success: non-sero
1153 * Failure: zero
1156 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1157 UINT_PTR uID, DWORD_PTR *pdwRef)
1159 LPSUBCLASS_INFO stack;
1160 int n;
1162 TRACE ("(%p, %p, %x, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1164 /* See if we have been called for this window */
1165 stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1166 if (!stack)
1167 return FALSE;
1169 for (n = 0; n <= stack->stacknum + stack->stacknew - 1; n++)
1170 if ((stack->SubclassProcs[n].id == uID) &&
1171 (stack->SubclassProcs[n].subproc == pfnSubclass)) {
1172 *pdwRef = stack->SubclassProcs[n].ref;
1173 return TRUE;
1176 return FALSE;
1180 /***********************************************************************
1181 * RemoveWindowSubclass [COMCTL32.@]
1183 * Removes a window subclass.
1185 * PARAMS
1186 * hWnd [in] Handle to the window were subclassing
1187 * pfnSubclass [in] Pointer to the subclass procedure
1188 * uID [in] Unique identifier of this subclass
1190 * RETURNS
1191 * Success: non-zero
1192 * Failure: zero
1195 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1197 LPSUBCLASS_INFO stack;
1198 int n;
1200 TRACE ("(%p, %p, %x)\n", hWnd, pfnSubclass, uID);
1202 /* Find the Subclass to remove */
1203 stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1204 if (!stack)
1205 return FALSE;
1207 if ((stack->stacknum == stack->stackpos == 1) && !stack->stacknew) {
1208 TRACE("Last Subclass removed, cleaning up\n");
1209 /* clean up our heap and reset the origional window procedure */
1210 if (IsWindowUnicode (hWnd))
1211 SetWindowLongW (hWnd, GWL_WNDPROC, (LONG)stack->origproc);
1212 else
1213 SetWindowLongA (hWnd, GWL_WNDPROC, (LONG)stack->origproc);
1214 HeapFree (GetProcessHeap (), 0, stack);
1215 RemovePropA( hWnd, COMCTL32_aSubclass );
1216 return TRUE;
1219 for (n = stack->stacknum + stack->stacknew - 1; n >= 0; n--)
1220 if ((stack->SubclassProcs[n].id == uID) &&
1221 (stack->SubclassProcs[n].subproc == pfnSubclass)) {
1222 if (n != (stack->stacknum + stack->stacknew))
1223 /* Fill the hole in the stack */
1224 memmove (&stack->SubclassProcs[n], &stack->SubclassProcs[n + 1],
1225 sizeof(stack->SubclassProcs[0]) * (stack->stacknew + stack->stacknum - n));
1226 stack->SubclassProcs[n].subproc = NULL;
1227 stack->SubclassProcs[n].ref = 0;
1228 stack->SubclassProcs[n].id = 0;
1230 /* If we are currently running a window procedure we have to manipulate
1231 * the stack position pointers so that we don't corrupt the stack */
1232 if ((n < stack->stackpos) || (stack->stackpos == stack->stacknum)) {
1233 stack->stacknum--;
1234 stack->stackpos--;
1235 } else if (n >= stack->stackpos)
1236 stack->stacknew--;
1237 return TRUE;
1240 return FALSE;
1244 /***********************************************************************
1245 * DefSubclassProc [COMCTL32.@]
1247 * Calls the next window procedure (ie. the one before this subclass)
1249 * PARAMS
1250 * hWnd [in] The window that we're subclassing
1251 * uMsg [in] Message
1252 * wParam [in] WPARAM
1253 * lParam [in] LPARAM
1255 * RETURNS
1256 * Success: non-zero
1257 * Failure: zero
1260 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1262 LPSUBCLASS_INFO stack;
1263 int stackpos;
1264 LRESULT ret;
1266 /* retrieve our little stack from the Properties */
1267 stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1268 if (!stack) {
1269 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1270 return 0;
1273 /* If we are at pos 0 then we have to call the origional window procedure */
1274 if (stack->stackpos == 0) {
1275 if (IsWindowUnicode (hWnd))
1276 return CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1277 else
1278 return CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1281 stackpos = --stack->stackpos;
1282 /* call the Subclass procedure from the stack */
1283 ret = stack->SubclassProcs[stackpos].subproc (hWnd, uMsg, wParam, lParam,
1284 stack->SubclassProcs[stackpos].id, stack->SubclassProcs[stackpos].ref);
1285 stack->stackpos++;
1287 if ((stack->stackpos == stack->stacknum) && stack->stacknew) {
1288 stack->stacknum += stack->stacknew;
1289 stack->stackpos += stack->stacknew;
1290 stack->stacknew = 0;
1293 /* If we removed the last entry in our stack while a window procedure was
1294 * running then we have to clean up */
1295 if (stack->stackpos == stack->stacknum == 0) {
1296 TRACE("Last Subclass removed, cleaning up\n");
1297 /* clean up our heap and reset the origional window procedure */
1298 if (IsWindowUnicode (hWnd))
1299 SetWindowLongW (hWnd, GWL_WNDPROC, (LONG)stack->origproc);
1300 else
1301 SetWindowLongA (hWnd, GWL_WNDPROC, (LONG)stack->origproc);
1302 HeapFree (GetProcessHeap (), 0, stack);
1303 RemovePropA( hWnd, COMCTL32_aSubclass );
1304 return TRUE;
1307 return ret;
1311 /***********************************************************************
1312 * COMCTL32_CreateToolTip [NOT AN API]
1314 * Creates a tooltip for the control specified in hwnd and does all
1315 * necessary setup and notifications.
1317 * PARAMS
1318 * hwndOwner [I] Handle to the window that will own the tool tip.
1320 * RETURNS
1321 * Success: Handle of tool tip window.
1322 * Failure: NULL
1325 HWND
1326 COMCTL32_CreateToolTip(HWND hwndOwner)
1328 HWND hwndToolTip;
1330 hwndToolTip = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
1331 CW_USEDEFAULT, CW_USEDEFAULT,
1332 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1333 0, 0, 0);
1335 /* Send NM_TOOLTIPSCREATED notification */
1336 if (hwndToolTip)
1338 NMTOOLTIPSCREATED nmttc;
1339 /* true owner can be different if hwndOwner is a child window */
1340 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1341 nmttc.hdr.hwndFrom = hwndTrueOwner;
1342 nmttc.hdr.idFrom = GetWindowLongA(hwndTrueOwner, GWL_ID);
1343 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1344 nmttc.hwndToolTips = hwndToolTip;
1346 SendMessageA(GetParent(hwndTrueOwner), WM_NOTIFY,
1347 (WPARAM)GetWindowLongA(hwndTrueOwner, GWL_ID),
1348 (LPARAM)&nmttc);
1351 return hwndToolTip;
1355 /***********************************************************************
1356 * COMCTL32_RefreshSysColors [NOT AN API]
1358 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1359 * refresh the color values in the color structure
1361 * PARAMS
1362 * none
1364 * RETURNS
1365 * none
1368 VOID
1369 COMCTL32_RefreshSysColors(void)
1371 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1372 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1373 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1374 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1375 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1376 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1377 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1378 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1379 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1380 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1381 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1382 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1383 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1384 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1385 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1386 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);