- fix the "int format, HANDLE arg" type of warnings for comctl32
[wine/multimedia.git] / dlls / comctl32 / commctrl.c
blobc29c40b921f2170b7f74b01f128301c5a62af623
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 * COMCTL32_LibMain [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
143 COMCTL32_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
145 TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
147 switch (fdwReason) {
148 case DLL_PROCESS_ATTACH:
149 COMCTL32_hModule = (HMODULE)hinstDLL;
151 /* create private heap */
152 COMCTL32_hHeap = HeapCreate (0, 0x10000, 0);
153 TRACE("Heap created: %p\n", COMCTL32_hHeap);
155 /* add global subclassing atom (used by 'tooltip' and 'updown') */
156 COMCTL32_aSubclass = (LPSTR)(DWORD)GlobalAddAtomA ("CC32SubclassInfo");
157 TRACE("Subclassing atom added: %p\n", COMCTL32_aSubclass);
159 /* create local pattern brush */
160 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
161 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
163 /* Get all the colors at DLL load */
164 COMCTL32_RefreshSysColors();
166 /* register all Win95 common control classes */
167 ANIMATE_Register ();
168 FLATSB_Register ();
169 HEADER_Register ();
170 HOTKEY_Register ();
171 LISTVIEW_Register ();
172 PROGRESS_Register ();
173 STATUS_Register ();
174 TAB_Register ();
175 TOOLBAR_Register ();
176 TOOLTIPS_Register ();
177 TRACKBAR_Register ();
178 TREEVIEW_Register ();
179 UPDOWN_Register ();
180 break;
182 case DLL_PROCESS_DETACH:
183 /* unregister all common control classes */
184 ANIMATE_Unregister ();
185 COMBOEX_Unregister ();
186 DATETIME_Unregister ();
187 FLATSB_Unregister ();
188 HEADER_Unregister ();
189 HOTKEY_Unregister ();
190 IPADDRESS_Unregister ();
191 LISTVIEW_Unregister ();
192 MONTHCAL_Unregister ();
193 NATIVEFONT_Unregister ();
194 PAGER_Unregister ();
195 PROGRESS_Unregister ();
196 REBAR_Unregister ();
197 STATUS_Unregister ();
198 TAB_Unregister ();
199 TOOLBAR_Unregister ();
200 TOOLTIPS_Unregister ();
201 TRACKBAR_Unregister ();
202 TREEVIEW_Unregister ();
203 UPDOWN_Unregister ();
205 /* delete local pattern brush */
206 DeleteObject (COMCTL32_hPattern55AABrush);
207 COMCTL32_hPattern55AABrush = (HANDLE)NULL;
208 DeleteObject (COMCTL32_hPattern55AABitmap);
209 COMCTL32_hPattern55AABitmap = (HANDLE)NULL;
211 /* delete global subclassing atom */
212 GlobalDeleteAtom (LOWORD(COMCTL32_aSubclass));
213 TRACE("Subclassing atom deleted: %p\n", COMCTL32_aSubclass);
214 COMCTL32_aSubclass = (LPSTR)NULL;
216 /* destroy private heap */
217 HeapDestroy (COMCTL32_hHeap);
218 TRACE("Heap destroyed: %p\n", COMCTL32_hHeap);
219 COMCTL32_hHeap = (HANDLE)NULL;
220 break;
223 return TRUE;
227 /***********************************************************************
228 * MenuHelp [COMCTL32.2]
230 * PARAMS
231 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
232 * wParam [I] wParam of the message uMsg
233 * lParam [I] lParam of the message uMsg
234 * hMainMenu [I] handle to the application's main menu
235 * hInst [I] handle to the module that contains string resources
236 * hwndStatus [I] handle to the status bar window
237 * lpwIDs [I] pointer to an array of integers (see NOTES)
239 * RETURNS
240 * No return value
242 * NOTES
243 * The official documentation is incomplete!
244 * This is the correct documentation:
246 * uMsg:
247 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
248 * WM_MENUSELECT messages.
250 * lpwIDs:
251 * (will be written ...)
254 VOID WINAPI
255 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
256 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
258 UINT uMenuID = 0;
260 if (!IsWindow (hwndStatus))
261 return;
263 switch (uMsg) {
264 case WM_MENUSELECT:
265 TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n",
266 wParam, lParam);
268 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
269 /* menu was closed */
270 TRACE("menu was closed!\n");
271 SendMessageA (hwndStatus, SB_SIMPLE, FALSE, 0);
273 else {
274 /* menu item was selected */
275 if (HIWORD(wParam) & MF_POPUP)
276 uMenuID = (UINT)*(lpwIDs+1);
277 else
278 uMenuID = (UINT)LOWORD(wParam);
279 TRACE("uMenuID = %u\n", uMenuID);
281 if (uMenuID) {
282 CHAR szText[256];
284 if (!LoadStringA (hInst, uMenuID, szText, 256))
285 szText[0] = '\0';
287 SendMessageA (hwndStatus, SB_SETTEXTA,
288 255 | SBT_NOBORDERS, (LPARAM)szText);
289 SendMessageA (hwndStatus, SB_SIMPLE, TRUE, 0);
292 break;
294 case WM_COMMAND :
295 TRACE("WM_COMMAND wParam=0x%X lParam=0x%lX\n",
296 wParam, lParam);
297 /* WM_COMMAND is not invalid since it is documented
298 * in the windows api reference. So don't output
299 * any FIXME for WM_COMMAND
301 WARN("We don't care about the WM_COMMAND\n");
302 break;
304 default:
305 FIXME("Invalid Message 0x%x!\n", uMsg);
306 break;
311 /***********************************************************************
312 * ShowHideMenuCtl [COMCTL32.3]
314 * Shows or hides controls and updates the corresponding menu item.
316 * PARAMS
317 * hwnd [I] handle to the client window.
318 * uFlags [I] menu command id.
319 * lpInfo [I] pointer to an array of integers. (See NOTES.)
321 * RETURNS
322 * Success: TRUE
323 * Failure: FALSE
325 * NOTES
326 * The official documentation is incomplete!
327 * This is the correct documentation:
329 * hwnd
330 * Handle to the window that contains the menu and controls.
332 * uFlags
333 * Identifier of the menu item to receive or loose a check mark.
335 * lpInfo
336 * The array of integers contains pairs of values. BOTH values of
337 * the first pair must be the handles to the application's main menu.
338 * Each subsequent pair consists of a menu id and control id.
341 BOOL WINAPI
342 ShowHideMenuCtl (HWND hwnd, UINT uFlags, LPINT lpInfo)
344 LPINT lpMenuId;
346 TRACE("%p, %x, %p\n", hwnd, uFlags, lpInfo);
348 if (lpInfo == NULL)
349 return FALSE;
351 if (!(lpInfo[0]) || !(lpInfo[1]))
352 return FALSE;
354 /* search for control */
355 lpMenuId = &lpInfo[2];
356 while (*lpMenuId != uFlags)
357 lpMenuId += 2;
359 if (GetMenuState ((HMENU)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
360 /* uncheck menu item */
361 CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
363 /* hide control */
364 lpMenuId++;
365 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
366 SWP_HIDEWINDOW);
368 else {
369 /* check menu item */
370 CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
372 /* show control */
373 lpMenuId++;
374 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
375 SWP_SHOWWINDOW);
378 return TRUE;
382 /***********************************************************************
383 * GetEffectiveClientRect [COMCTL32.4]
385 * PARAMS
386 * hwnd [I] handle to the client window.
387 * lpRect [O] pointer to the rectangle of the client window
388 * lpInfo [I] pointer to an array of integers (see NOTES)
390 * RETURNS
391 * No return value.
393 * NOTES
394 * The official documentation is incomplete!
395 * This is the correct documentation:
397 * lpInfo
398 * (will be written ...)
401 VOID WINAPI
402 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo)
404 RECT rcCtrl;
405 INT *lpRun;
406 HWND hwndCtrl;
408 TRACE("(0x%08lx 0x%08lx 0x%08lx)\n",
409 (DWORD)hwnd, (DWORD)lpRect, (DWORD)lpInfo);
411 GetClientRect (hwnd, lpRect);
412 lpRun = lpInfo;
414 do {
415 lpRun += 2;
416 if (*lpRun == 0)
417 return;
418 lpRun++;
419 hwndCtrl = GetDlgItem (hwnd, *lpRun);
420 if (GetWindowLongA (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
421 TRACE("control id 0x%x\n", *lpRun);
422 GetWindowRect (hwndCtrl, &rcCtrl);
423 MapWindowPoints ((HWND)0, hwnd, (LPPOINT)&rcCtrl, 2);
424 SubtractRect (lpRect, lpRect, &rcCtrl);
426 lpRun++;
427 } while (*lpRun);
431 /***********************************************************************
432 * DrawStatusTextW [COMCTL32.@]
434 * Draws text with borders, like in a status bar.
436 * PARAMS
437 * hdc [I] handle to the window's display context
438 * lprc [I] pointer to a rectangle
439 * text [I] pointer to the text
440 * style [I] drawing style
442 * RETURNS
443 * No return value.
445 * NOTES
446 * The style variable can have one of the following values:
447 * (will be written ...)
450 void WINAPI DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style)
452 RECT r = *lprc;
453 UINT border = BDR_SUNKENOUTER;
455 if (style & SBT_POPOUT)
456 border = BDR_RAISEDOUTER;
457 else if (style & SBT_NOBORDERS)
458 border = 0;
460 DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
462 /* now draw text */
463 if (text) {
464 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
465 UINT align = DT_LEFT;
466 if (*text == L'\t') {
467 text++;
468 align = DT_CENTER;
469 if (*text == L'\t') {
470 text++;
471 align = DT_RIGHT;
474 r.left += 3;
475 if (style & SBT_RTLREADING)
476 FIXME("Unsupported RTL style!\n");
477 DrawTextW (hdc, text, -1, &r, align|DT_VCENTER|DT_SINGLELINE);
478 SetBkMode(hdc, oldbkmode);
483 /***********************************************************************
484 * DrawStatusText [COMCTL32.@]
485 * DrawStatusTextA [COMCTL32.5]
487 * Draws text with borders, like in a status bar.
489 * PARAMS
490 * hdc [I] handle to the window's display context
491 * lprc [I] pointer to a rectangle
492 * text [I] pointer to the text
493 * style [I] drawing style
495 * RETURNS
496 * No return value.
499 void WINAPI DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style)
501 INT len;
502 LPWSTR textW = NULL;
504 if ( text ) {
505 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
506 if ( (textW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )) )
507 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
510 DrawStatusTextW( hdc, lprc, textW, style );
511 HeapFree( GetProcessHeap(), 0, textW );
515 /***********************************************************************
516 * CreateStatusWindow [COMCTL32.@]
517 * CreateStatusWindowA [COMCTL32.6]
519 * Creates a status bar
521 * PARAMS
522 * style [I] window style
523 * text [I] pointer to the window text
524 * parent [I] handle to the parent window
525 * wid [I] control id of the status bar
527 * RETURNS
528 * Success: handle to the status window
529 * Failure: 0
532 HWND WINAPI
533 CreateStatusWindowA (INT style, LPCSTR text, HWND parent, UINT wid)
535 return CreateWindowA(STATUSCLASSNAMEA, text, style,
536 CW_USEDEFAULT, CW_USEDEFAULT,
537 CW_USEDEFAULT, CW_USEDEFAULT,
538 parent, (HMENU)wid, 0, 0);
542 /***********************************************************************
543 * CreateStatusWindowW [COMCTL32.@] Creates a status bar control
545 * PARAMS
546 * style [I] window style
547 * text [I] pointer to the window text
548 * parent [I] handle to the parent window
549 * wid [I] control id of the status bar
551 * RETURNS
552 * Success: handle to the status window
553 * Failure: 0
556 HWND WINAPI
557 CreateStatusWindowW (INT style, LPCWSTR text, HWND parent, UINT wid)
559 return CreateWindowW(STATUSCLASSNAMEW, text, style,
560 CW_USEDEFAULT, CW_USEDEFAULT,
561 CW_USEDEFAULT, CW_USEDEFAULT,
562 parent, (HMENU)wid, 0, 0);
566 /***********************************************************************
567 * CreateUpDownControl [COMCTL32.16] Creates an up-down control
569 * PARAMS
570 * style [I] window styles
571 * x [I] horizontal position of the control
572 * y [I] vertical position of the control
573 * cx [I] with of the control
574 * cy [I] height of the control
575 * parent [I] handle to the parent window
576 * id [I] the control's identifier
577 * inst [I] handle to the application's module instance
578 * buddy [I] handle to the buddy window, can be NULL
579 * maxVal [I] upper limit of the control
580 * minVal [I] lower limit of the control
581 * curVal [I] current value of the control
583 * RETURNS
584 * Success: handle to the updown control
585 * Failure: 0
588 HWND WINAPI
589 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
590 HWND parent, INT id, HINSTANCE inst,
591 HWND buddy, INT maxVal, INT minVal, INT curVal)
593 HWND hUD =
594 CreateWindowA (UPDOWN_CLASSA, 0, style, x, y, cx, cy,
595 parent, (HMENU)id, inst, 0);
596 if (hUD) {
597 SendMessageA (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
598 SendMessageA (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
599 SendMessageA (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
602 return hUD;
606 /***********************************************************************
607 * InitCommonControls [COMCTL32.17]
609 * Registers the common controls.
611 * PARAMS
612 * No parameters.
614 * RETURNS
615 * No return values.
617 * NOTES
618 * This function is just a dummy.
619 * The Win95 controls are registered at the DLL's initialization.
620 * To register other controls InitCommonControlsEx() must be used.
623 VOID WINAPI
624 InitCommonControls (void)
629 /***********************************************************************
630 * InitCommonControlsEx [COMCTL32.@]
632 * Registers the common controls.
634 * PARAMS
635 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
637 * RETURNS
638 * Success: TRUE
639 * Failure: FALSE
641 * NOTES
642 * Only the additional common controls are registered by this function.
643 * The Win95 controls are registered at the DLL's initialization.
645 * FIXME
646 * implement the following control classes:
647 * ICC_LINK_CLASS
648 * ICC_STANDARD_CLASSES
651 BOOL WINAPI
652 InitCommonControlsEx (LPINITCOMMONCONTROLSEX lpInitCtrls)
654 INT cCount;
655 DWORD dwMask;
657 if (!lpInitCtrls)
658 return FALSE;
659 if (lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
660 return FALSE;
662 TRACE("(0x%08lx)\n", lpInitCtrls->dwICC);
664 for (cCount = 0; cCount < 32; cCount++) {
665 dwMask = 1 << cCount;
666 if (!(lpInitCtrls->dwICC & dwMask))
667 continue;
669 switch (lpInitCtrls->dwICC & dwMask) {
670 /* dummy initialization */
671 case ICC_ANIMATE_CLASS:
672 case ICC_BAR_CLASSES:
673 case ICC_LISTVIEW_CLASSES:
674 case ICC_TREEVIEW_CLASSES:
675 case ICC_TAB_CLASSES:
676 case ICC_UPDOWN_CLASS:
677 case ICC_PROGRESS_CLASS:
678 case ICC_HOTKEY_CLASS:
679 break;
681 /* advanced classes - not included in Win95 */
682 case ICC_DATE_CLASSES:
683 MONTHCAL_Register ();
684 DATETIME_Register ();
685 break;
687 case ICC_USEREX_CLASSES:
688 COMBOEX_Register ();
689 break;
691 case ICC_COOL_CLASSES:
692 REBAR_Register ();
693 break;
695 case ICC_INTERNET_CLASSES:
696 IPADDRESS_Register ();
697 break;
699 case ICC_PAGESCROLLER_CLASS:
700 PAGER_Register ();
701 break;
703 case ICC_NATIVEFNTCTL_CLASS:
704 NATIVEFONT_Register ();
705 break;
707 default:
708 FIXME("Unknown class! dwICC=0x%lX\n", dwMask);
709 break;
713 return TRUE;
717 /***********************************************************************
718 * CreateToolbarEx [COMCTL32.@] Creates a tool bar window
720 * PARAMS
721 * hwnd
722 * style
723 * wID
724 * nBitmaps
725 * hBMInst
726 * wBMID
727 * lpButtons
728 * iNumButtons
729 * dxButton
730 * dyButton
731 * dxBitmap
732 * dyBitmap
733 * uStructSize
735 * RETURNS
736 * Success: handle to the tool bar control
737 * Failure: 0
740 HWND WINAPI
741 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
742 HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons,
743 INT iNumButtons, INT dxButton, INT dyButton,
744 INT dxBitmap, INT dyBitmap, UINT uStructSize)
746 HWND hwndTB;
748 /* If not position is specified then put it at the top */
749 if ((style & CCS_BOTTOM) == 0) {
750 style|=CCS_TOP;
753 hwndTB =
754 CreateWindowExA (0, TOOLBARCLASSNAMEA, "", style|WS_CHILD, 0, 0, 0, 0,
755 hwnd, (HMENU)wID, 0, NULL);
756 if(hwndTB) {
757 TBADDBITMAP tbab;
759 SendMessageA (hwndTB, TB_BUTTONSTRUCTSIZE,
760 (WPARAM)uStructSize, 0);
762 /* set bitmap and button size */
763 /*If CreateToolbarEx receives 0, windows sets default values*/
764 if (dxBitmap <= 0)
765 dxBitmap = 16;
766 if (dyBitmap <= 0)
767 dyBitmap = 15;
768 SendMessageA (hwndTB, TB_SETBITMAPSIZE, 0,
769 MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap));
771 if (dxButton <= 0)
772 dxButton = 24;
773 if (dyButton <= 0)
774 dyButton = 22;
775 SendMessageA (hwndTB, TB_SETBUTTONSIZE, 0,
776 MAKELPARAM((WORD)dxButton, (WORD)dyButton));
779 /* add bitmaps */
780 if (nBitmaps > 0)
782 tbab.hInst = hBMInst;
783 tbab.nID = wBMID;
785 SendMessageA (hwndTB, TB_ADDBITMAP,
786 (WPARAM)nBitmaps, (LPARAM)&tbab);
788 /* add buttons */
789 if(iNumButtons > 0)
790 SendMessageA (hwndTB, TB_ADDBUTTONSA,
791 (WPARAM)iNumButtons, (LPARAM)lpButtons);
794 return hwndTB;
798 /***********************************************************************
799 * CreateMappedBitmap [COMCTL32.8]
801 * PARAMS
802 * hInstance [I]
803 * idBitmap [I]
804 * wFlags [I]
805 * lpColorMap [I]
806 * iNumMaps [I]
808 * RETURNS
809 * Success: handle to the new bitmap
810 * Failure: 0
813 HBITMAP WINAPI
814 CreateMappedBitmap (HINSTANCE hInstance, INT idBitmap, UINT wFlags,
815 LPCOLORMAP lpColorMap, INT iNumMaps)
817 HGLOBAL hglb;
818 HRSRC hRsrc;
819 LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
820 UINT nSize, nColorTableSize;
821 RGBQUAD *pColorTable;
822 INT iColor, i, iMaps, nWidth, nHeight;
823 HDC hdcScreen;
824 HBITMAP hbm;
825 LPCOLORMAP sysColorMap;
826 COLORREF cRef;
827 COLORMAP internalColorMap[4] =
828 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
830 /* initialize pointer to colortable and default color table */
831 if (lpColorMap) {
832 iMaps = iNumMaps;
833 sysColorMap = lpColorMap;
835 else {
836 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
837 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
838 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
839 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
840 iMaps = 4;
841 sysColorMap = (LPCOLORMAP)internalColorMap;
844 hRsrc = FindResourceA (hInstance, (LPSTR)idBitmap, RT_BITMAPA);
845 if (hRsrc == 0)
846 return 0;
847 hglb = LoadResource (hInstance, hRsrc);
848 if (hglb == 0)
849 return 0;
850 lpBitmap = (LPBITMAPINFOHEADER)LockResource (hglb);
851 if (lpBitmap == NULL)
852 return 0;
854 nColorTableSize = (1 << lpBitmap->biBitCount);
855 nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
856 lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize);
857 if (lpBitmapInfo == NULL)
858 return 0;
859 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
861 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)lpBitmapInfo->biSize);
863 for (iColor = 0; iColor < nColorTableSize; iColor++) {
864 for (i = 0; i < iMaps; i++) {
865 cRef = RGB(pColorTable[iColor].rgbRed,
866 pColorTable[iColor].rgbGreen,
867 pColorTable[iColor].rgbBlue);
868 if ( cRef == sysColorMap[i].from) {
869 #if 0
870 if (wFlags & CBS_MASKED) {
871 if (sysColorMap[i].to != COLOR_BTNTEXT)
872 pColorTable[iColor] = RGB(255, 255, 255);
874 else
875 #endif
876 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
877 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
878 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
879 break;
883 nWidth = (INT)lpBitmapInfo->biWidth;
884 nHeight = (INT)lpBitmapInfo->biHeight;
885 hdcScreen = GetDC ((HWND)0);
886 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
887 if (hbm) {
888 HDC hdcDst = CreateCompatibleDC (hdcScreen);
889 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
890 LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
891 lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
892 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
893 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
894 SRCCOPY);
895 SelectObject (hdcDst, hbmOld);
896 DeleteDC (hdcDst);
898 ReleaseDC ((HWND)0, hdcScreen);
899 GlobalFree ((HGLOBAL)lpBitmapInfo);
900 FreeResource (hglb);
902 return hbm;
906 /***********************************************************************
907 * CreateToolbar [COMCTL32.7] Creates a tool bar control
909 * PARAMS
910 * hwnd
911 * style
912 * wID
913 * nBitmaps
914 * hBMInst
915 * wBMID
916 * lpButtons
917 * iNumButtons
919 * RETURNS
920 * Success: handle to the tool bar control
921 * Failure: 0
923 * NOTES
924 * Do not use this functions anymore. Use CreateToolbarEx instead.
927 HWND WINAPI
928 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
929 HINSTANCE hBMInst, UINT wBMID,
930 LPCOLDTBBUTTON lpButtons,INT iNumButtons)
932 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
933 hBMInst, wBMID, (LPCTBBUTTON)lpButtons,
934 iNumButtons, 0, 0, 0, 0, sizeof (OLDTBBUTTON));
938 /***********************************************************************
939 * DllGetVersion [COMCTL32.@]
941 * Retrieves version information of the 'COMCTL32.DLL'
943 * PARAMS
944 * pdvi [O] pointer to version information structure.
946 * RETURNS
947 * Success: S_OK
948 * Failure: E_INVALIDARG
950 * NOTES
951 * Returns version of a comctl32.dll from IE4.01 SP1.
954 HRESULT WINAPI
955 COMCTL32_DllGetVersion (DLLVERSIONINFO *pdvi)
957 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
958 WARN("wrong DLLVERSIONINFO size from app\n");
959 return E_INVALIDARG;
962 pdvi->dwMajorVersion = COMCTL32_VERSION;
963 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
964 pdvi->dwBuildNumber = 2919;
965 pdvi->dwPlatformID = 6304;
967 TRACE("%lu.%lu.%lu.%lu\n",
968 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
969 pdvi->dwBuildNumber, pdvi->dwPlatformID);
971 return S_OK;
974 /***********************************************************************
975 * DllInstall (COMCTL32.@)
977 HRESULT WINAPI COMCTL32_DllInstall(BOOL bInstall, LPCWSTR cmdline)
979 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
980 debugstr_w(cmdline));
982 return S_OK;
985 /***********************************************************************
986 * _TrackMouseEvent [COMCTL32.@]
988 * Requests notification of mouse events
990 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
991 * to the hwnd specified in the ptme structure. After the event message
992 * is posted to the hwnd, the entry in the queue is removed.
994 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
995 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
996 * immediately and the TME_LEAVE flag being ignored.
998 * PARAMS
999 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1001 * RETURNS
1002 * Success: non-zero
1003 * Failure: zero
1005 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1009 BOOL WINAPI
1010 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1012 return TrackMouseEvent (ptme);
1015 /*************************************************************************
1016 * GetMUILanguage [COMCTL32.@]
1018 * FIXME: "Returns the language currently in use by the common controls
1019 * for a particular process." (MSDN)
1022 LANGID WINAPI GetMUILanguage (VOID)
1024 return COMCTL32_uiLang;
1028 /*************************************************************************
1029 * InitMUILanguage [COMCTL32.@]
1031 * FIXME: "Enables an application to specify a language to be used with
1032 * the common controls that is different than the system language." (MSDN)
1036 VOID WINAPI InitMUILanguage (LANGID uiLang)
1038 COMCTL32_uiLang = uiLang;
1042 /***********************************************************************
1043 * SetWindowSubclass [COMCTL32.@]
1045 * Starts a window subclass
1047 * PARAMS
1048 * hWnd [in] handle to window subclass.
1049 * pfnSubclass [in] Pointer to new window procedure.
1050 * uIDSubclass [in] Unique identifier of sublass together with pfnSubclass.
1051 * dwRef [in] Reference data to pass to window procedure.
1053 * RETURNS
1054 * Success: non-zero
1055 * Failure: zero
1057 * BUGS
1058 * If an application manually subclasses a window after subclassing it with
1059 * this API and then with this API again, then none of the previous
1060 * subclasses get called or the origional window procedure.
1063 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1064 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1066 LPSUBCLASS_INFO stack;
1067 int newnum, n;
1069 TRACE ("(%p, %p, %x, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1071 /* Since the window procedure that we set here has two additional arguments,
1072 * we can't simply set it as the new window procedure of the window. So we
1073 * set our own window procedure and then calculate the other two arguments
1074 * from there. */
1076 /* See if we have been called for this window */
1077 stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1078 if (!stack) {
1079 /* allocate stack */
1080 stack = (LPSUBCLASS_INFO)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY,
1081 sizeof(SUBCLASS_INFO));
1082 if (!stack) {
1083 ERR ("Failed to allocate our Subclassing stack");
1084 return FALSE;
1086 SetPropA (hWnd, COMCTL32_aSubclass, (HANDLE)stack);
1088 /* set window procedure to our own and save the current one */
1089 if (IsWindowUnicode (hWnd))
1090 stack->origproc = (WNDPROC)SetWindowLongW (hWnd, GWL_WNDPROC,
1091 (LONG)DefSubclassProc);
1092 else
1093 stack->origproc = (WNDPROC)SetWindowLongA (hWnd, GWL_WNDPROC,
1094 (LONG)DefSubclassProc);
1095 } else {
1096 WNDPROC current;
1097 if (IsWindowUnicode (hWnd))
1098 current = (WNDPROC)GetWindowLongW (hWnd, GWL_WNDPROC);
1099 else
1100 current = (WNDPROC)GetWindowLongA (hWnd, GWL_WNDPROC);
1102 if (current != DefSubclassProc) {
1103 ERR ("Application has subclassed with our procedure, then manually, then with us again. The current implementation can't handle this.\n");
1104 return FALSE;
1108 /* Check to see if we have called this function with the same uIDSubClass
1109 * and pfnSubclass */
1110 for (n = 0; n <= stack->stacknum + stack->stacknew - 1; n++)
1111 if ((stack->SubclassProcs[n].id == uIDSubclass) &&
1112 (stack->SubclassProcs[n].subproc == pfnSubclass)) {
1113 stack->SubclassProcs[n].ref = dwRef;
1114 return TRUE;
1117 if ((stack->stacknum + stack->stacknew) >= 32) {
1118 ERR ("We have a Subclass stack overflow, please increment size");
1119 return FALSE;
1122 /* we can't simply increment both stackpos and stacknum because there might
1123 * be a window procedure running lower in the stack, we can only get them
1124 * up to date once the last window procedure has run */
1125 if (stack->stacknum == stack->stackpos) {
1126 stack->stacknum++;
1127 stack->stackpos++;
1128 } else
1129 stack->stacknew++;
1131 newnum = stack->stacknew + stack->stacknum - 1;
1133 stack->SubclassProcs[newnum].subproc = pfnSubclass;
1134 stack->SubclassProcs[newnum].ref = dwRef;
1135 stack->SubclassProcs[newnum].id = uIDSubclass;
1137 return TRUE;
1141 /***********************************************************************
1142 * GetWindowSubclass [COMCTL32.@]
1144 * Gets the Reference data from a subclass.
1146 * PARAMS
1147 * hWnd [in] Handle to window which were subclassing
1148 * pfnSubclass [in] Pointer to the subclass procedure
1149 * iID [in] Unique indentifier of the subclassing procedure
1150 * pdwRef [out] Pointer to the reference data
1152 * RETURNS
1153 * Success: non-sero
1154 * Failure: zero
1157 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1158 UINT_PTR uID, DWORD_PTR *pdwRef)
1160 LPSUBCLASS_INFO stack;
1161 int n;
1163 TRACE ("(%p, %p, %x, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1165 /* See if we have been called for this window */
1166 stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1167 if (!stack)
1168 return FALSE;
1170 for (n = 0; n <= stack->stacknum + stack->stacknew - 1; n++)
1171 if ((stack->SubclassProcs[n].id == uID) &&
1172 (stack->SubclassProcs[n].subproc == pfnSubclass)) {
1173 *pdwRef = stack->SubclassProcs[n].ref;
1174 return TRUE;
1177 return FALSE;
1181 /***********************************************************************
1182 * RemoveWindowSubclass [COMCTL32.@]
1184 * Removes a window subclass.
1186 * PARAMS
1187 * hWnd [in] Handle to the window were subclassing
1188 * pfnSubclass [in] Pointer to the subclass procedure
1189 * uID [in] Unique identifier of this subclass
1191 * RETURNS
1192 * Success: non-zero
1193 * Failure: zero
1196 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1198 LPSUBCLASS_INFO stack;
1199 int n;
1201 TRACE ("(%p, %p, %x)\n", hWnd, pfnSubclass, uID);
1203 /* Find the Subclass to remove */
1204 stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1205 if (!stack)
1206 return FALSE;
1208 if ((stack->stacknum == stack->stackpos == 1) && !stack->stacknew) {
1209 TRACE("Last Subclass removed, cleaning up\n");
1210 /* clean up our heap and reset the origional window procedure */
1211 if (IsWindowUnicode (hWnd))
1212 SetWindowLongW (hWnd, GWL_WNDPROC, (LONG)stack->origproc);
1213 else
1214 SetWindowLongA (hWnd, GWL_WNDPROC, (LONG)stack->origproc);
1215 HeapFree (GetProcessHeap (), 0, stack);
1216 RemovePropA( hWnd, COMCTL32_aSubclass );
1217 return TRUE;
1220 for (n = stack->stacknum + stack->stacknew - 1; n >= 0; n--)
1221 if ((stack->SubclassProcs[n].id == uID) &&
1222 (stack->SubclassProcs[n].subproc == pfnSubclass)) {
1223 if (n != (stack->stacknum + stack->stacknew))
1224 /* Fill the hole in the stack */
1225 memmove (&stack->SubclassProcs[n], &stack->SubclassProcs[n + 1],
1226 sizeof(stack->SubclassProcs[0]) * (stack->stacknew + stack->stacknum - n));
1227 stack->SubclassProcs[n].subproc = NULL;
1228 stack->SubclassProcs[n].ref = 0;
1229 stack->SubclassProcs[n].id = 0;
1231 /* If we are currently running a window procedure we have to manipulate
1232 * the stack position pointers so that we don't corrupt the stack */
1233 if ((n < stack->stackpos) || (stack->stackpos == stack->stacknum)) {
1234 stack->stacknum--;
1235 stack->stackpos--;
1236 } else if (n >= stack->stackpos)
1237 stack->stacknew--;
1238 return TRUE;
1241 return FALSE;
1245 /***********************************************************************
1246 * DefSubclassProc [COMCTL32.@]
1248 * Calls the next window procedure (ie. the one before this subclass)
1250 * PARAMS
1251 * hWnd [in] The window that we're subclassing
1252 * uMsg [in] Message
1253 * wParam [in] WPARAM
1254 * lParam [in] LPARAM
1256 * RETURNS
1257 * Success: non-zero
1258 * Failure: zero
1261 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1263 LPSUBCLASS_INFO stack;
1264 int stackpos;
1265 LRESULT ret;
1267 /* retrieve our little stack from the Properties */
1268 stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1269 if (!stack) {
1270 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1271 return 0;
1274 /* If we are at pos 0 then we have to call the origional window procedure */
1275 if (stack->stackpos == 0) {
1276 if (IsWindowUnicode (hWnd))
1277 return CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1278 else
1279 return CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1282 stackpos = --stack->stackpos;
1283 /* call the Subclass procedure from the stack */
1284 ret = stack->SubclassProcs[stackpos].subproc (hWnd, uMsg, wParam, lParam,
1285 stack->SubclassProcs[stackpos].id, stack->SubclassProcs[stackpos].ref);
1286 stack->stackpos++;
1288 if ((stack->stackpos == stack->stacknum) && stack->stacknew) {
1289 stack->stacknum += stack->stacknew;
1290 stack->stackpos += stack->stacknew;
1291 stack->stacknew = 0;
1294 /* If we removed the last entry in our stack while a window procedure was
1295 * running then we have to clean up */
1296 if (stack->stackpos == stack->stacknum == 0) {
1297 TRACE("Last Subclass removed, cleaning up\n");
1298 /* clean up our heap and reset the origional window procedure */
1299 if (IsWindowUnicode (hWnd))
1300 SetWindowLongW (hWnd, GWL_WNDPROC, (LONG)stack->origproc);
1301 else
1302 SetWindowLongA (hWnd, GWL_WNDPROC, (LONG)stack->origproc);
1303 HeapFree (GetProcessHeap (), 0, stack);
1304 RemovePropA( hWnd, COMCTL32_aSubclass );
1305 return TRUE;
1308 return ret;
1312 /***********************************************************************
1313 * COMCTL32_CreateToolTip [NOT AN API]
1315 * Creates a tooltip for the control specified in hwnd and does all
1316 * necessary setup and notifications.
1318 * PARAMS
1319 * hwndOwner [I] Handle to the window that will own the tool tip.
1321 * RETURNS
1322 * Success: Handle of tool tip window.
1323 * Failure: NULL
1326 HWND
1327 COMCTL32_CreateToolTip(HWND hwndOwner)
1329 HWND hwndToolTip;
1331 hwndToolTip = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
1332 CW_USEDEFAULT, CW_USEDEFAULT,
1333 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1334 0, 0, 0);
1336 /* Send NM_TOOLTIPSCREATED notification */
1337 if (hwndToolTip)
1339 NMTOOLTIPSCREATED nmttc;
1340 /* true owner can be different if hwndOwner is a child window */
1341 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1342 nmttc.hdr.hwndFrom = hwndTrueOwner;
1343 nmttc.hdr.idFrom = GetWindowLongA(hwndTrueOwner, GWL_ID);
1344 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1345 nmttc.hwndToolTips = hwndToolTip;
1347 SendMessageA(GetParent(hwndTrueOwner), WM_NOTIFY,
1348 (WPARAM)GetWindowLongA(hwndTrueOwner, GWL_ID),
1349 (LPARAM)&nmttc);
1352 return hwndToolTip;
1356 /***********************************************************************
1357 * COMCTL32_RefreshSysColors [NOT AN API]
1359 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1360 * refresh the color values in the color structure
1362 * PARAMS
1363 * none
1365 * RETURNS
1366 * none
1369 VOID
1370 COMCTL32_RefreshSysColors(void)
1372 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1373 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1374 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1375 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1376 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1377 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1378 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1379 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1380 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1381 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1382 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1383 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1384 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1385 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1386 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1387 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);