Fixed header dependencies to be fully compatible with the Windows
[wine/multimedia.git] / dlls / comctl32 / commctrl.c
blob5f1beadf3580227f7738b7cfdcab85741562debe
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 <stdarg.h>
58 #include <string.h>
59 #include <stdlib.h>
61 #include "windef.h"
62 #include "winbase.h"
63 #include "wingdi.h"
64 #include "winuser.h"
65 #include "winnls.h"
66 #include "commctrl.h"
67 #include "winerror.h"
68 #include "winreg.h"
69 #define NO_SHLWAPI_STREAM
70 #include "shlwapi.h"
71 #include "comctl32.h"
72 #include "wine/debug.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
76 extern void ANIMATE_Register(void);
77 extern void ANIMATE_Unregister(void);
78 extern void COMBOEX_Register(void);
79 extern void COMBOEX_Unregister(void);
80 extern void DATETIME_Register(void);
81 extern void DATETIME_Unregister(void);
82 extern void FLATSB_Register(void);
83 extern void FLATSB_Unregister(void);
84 extern void HEADER_Register(void);
85 extern void HEADER_Unregister(void);
86 extern void HOTKEY_Register(void);
87 extern void HOTKEY_Unregister(void);
88 extern void IPADDRESS_Register(void);
89 extern void IPADDRESS_Unregister(void);
90 extern void LISTVIEW_Register(void);
91 extern void LISTVIEW_Unregister(void);
92 extern void MONTHCAL_Register(void);
93 extern void MONTHCAL_Unregister(void);
94 extern void NATIVEFONT_Register(void);
95 extern void NATIVEFONT_Unregister(void);
96 extern void PAGER_Register(void);
97 extern void PAGER_Unregister(void);
98 extern void PROGRESS_Register(void);
99 extern void PROGRESS_Unregister(void);
100 extern void REBAR_Register(void);
101 extern void REBAR_Unregister(void);
102 extern void STATUS_Register(void);
103 extern void STATUS_Unregister(void);
104 extern void TAB_Register(void);
105 extern void TAB_Unregister(void);
106 extern void TOOLBAR_Register(void);
107 extern void TOOLBAR_Unregister(void);
108 extern void TOOLTIPS_Register(void);
109 extern void TOOLTIPS_Unregister(void);
110 extern void TRACKBAR_Register(void);
111 extern void TRACKBAR_Unregister(void);
112 extern void TREEVIEW_Register(void);
113 extern void TREEVIEW_Unregister(void);
114 extern void UPDOWN_Register(void);
115 extern void UPDOWN_Unregister(void);
118 HANDLE COMCTL32_hHeap = NULL;
119 LPSTR COMCTL32_aSubclass = NULL;
120 HMODULE COMCTL32_hModule = 0;
121 LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
122 HBRUSH COMCTL32_hPattern55AABrush = NULL;
123 COMCTL32_SysColor comctl32_color;
125 static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
127 static const WORD wPattern55AA[] =
129 0x5555, 0xaaaa, 0x5555, 0xaaaa,
130 0x5555, 0xaaaa, 0x5555, 0xaaaa
134 /***********************************************************************
135 * DllMain [Internal] Initializes the internal 'COMCTL32.DLL'.
137 * PARAMS
138 * hinstDLL [I] handle to the 'dlls' instance
139 * fdwReason [I]
140 * lpvReserved [I] reserverd, must be NULL
142 * RETURNS
143 * Success: TRUE
144 * Failure: FALSE
147 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
149 TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
151 switch (fdwReason) {
152 case DLL_PROCESS_ATTACH:
153 DisableThreadLibraryCalls(hinstDLL);
155 COMCTL32_hModule = (HMODULE)hinstDLL;
157 /* create private heap */
158 COMCTL32_hHeap = HeapCreate (0, 0x10000, 0);
159 TRACE("Heap created: %p\n", COMCTL32_hHeap);
161 /* add global subclassing atom (used by 'tooltip' and 'updown') */
162 COMCTL32_aSubclass = (LPSTR)(DWORD)GlobalAddAtomA ("CC32SubclassInfo");
163 TRACE("Subclassing atom added: %p\n", COMCTL32_aSubclass);
165 /* create local pattern brush */
166 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
167 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
169 /* Get all the colors at DLL load */
170 COMCTL32_RefreshSysColors();
172 /* register all Win95 common control classes */
173 ANIMATE_Register ();
174 FLATSB_Register ();
175 HEADER_Register ();
176 HOTKEY_Register ();
177 LISTVIEW_Register ();
178 PROGRESS_Register ();
179 STATUS_Register ();
180 TAB_Register ();
181 TOOLBAR_Register ();
182 TOOLTIPS_Register ();
183 TRACKBAR_Register ();
184 TREEVIEW_Register ();
185 UPDOWN_Register ();
186 break;
188 case DLL_PROCESS_DETACH:
189 /* unregister all common control classes */
190 ANIMATE_Unregister ();
191 COMBOEX_Unregister ();
192 DATETIME_Unregister ();
193 FLATSB_Unregister ();
194 HEADER_Unregister ();
195 HOTKEY_Unregister ();
196 IPADDRESS_Unregister ();
197 LISTVIEW_Unregister ();
198 MONTHCAL_Unregister ();
199 NATIVEFONT_Unregister ();
200 PAGER_Unregister ();
201 PROGRESS_Unregister ();
202 REBAR_Unregister ();
203 STATUS_Unregister ();
204 TAB_Unregister ();
205 TOOLBAR_Unregister ();
206 TOOLTIPS_Unregister ();
207 TRACKBAR_Unregister ();
208 TREEVIEW_Unregister ();
209 UPDOWN_Unregister ();
211 /* delete local pattern brush */
212 DeleteObject (COMCTL32_hPattern55AABrush);
213 COMCTL32_hPattern55AABrush = NULL;
214 DeleteObject (COMCTL32_hPattern55AABitmap);
215 COMCTL32_hPattern55AABitmap = NULL;
217 /* delete global subclassing atom */
218 GlobalDeleteAtom (LOWORD(COMCTL32_aSubclass));
219 TRACE("Subclassing atom deleted: %p\n", COMCTL32_aSubclass);
220 COMCTL32_aSubclass = NULL;
222 /* destroy private heap */
223 HeapDestroy (COMCTL32_hHeap);
224 TRACE("Heap destroyed: %p\n", COMCTL32_hHeap);
225 COMCTL32_hHeap = NULL;
226 break;
229 return TRUE;
233 /***********************************************************************
234 * MenuHelp [COMCTL32.2]
236 * PARAMS
237 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
238 * wParam [I] wParam of the message uMsg
239 * lParam [I] lParam of the message uMsg
240 * hMainMenu [I] handle to the application's main menu
241 * hInst [I] handle to the module that contains string resources
242 * hwndStatus [I] handle to the status bar window
243 * lpwIDs [I] pointer to an array of integers (see NOTES)
245 * RETURNS
246 * No return value
248 * NOTES
249 * The official documentation is incomplete!
250 * This is the correct documentation:
252 * uMsg:
253 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
254 * WM_MENUSELECT messages.
256 * lpwIDs:
257 * (will be written ...)
260 VOID WINAPI
261 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
262 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
264 UINT uMenuID = 0;
266 if (!IsWindow (hwndStatus))
267 return;
269 switch (uMsg) {
270 case WM_MENUSELECT:
271 TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n",
272 wParam, lParam);
274 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
275 /* menu was closed */
276 TRACE("menu was closed!\n");
277 SendMessageA (hwndStatus, SB_SIMPLE, FALSE, 0);
279 else {
280 /* menu item was selected */
281 if (HIWORD(wParam) & MF_POPUP)
282 uMenuID = (UINT)*(lpwIDs+1);
283 else
284 uMenuID = (UINT)LOWORD(wParam);
285 TRACE("uMenuID = %u\n", uMenuID);
287 if (uMenuID) {
288 CHAR szText[256];
290 if (!LoadStringA (hInst, uMenuID, szText, 256))
291 szText[0] = '\0';
293 SendMessageA (hwndStatus, SB_SETTEXTA,
294 255 | SBT_NOBORDERS, (LPARAM)szText);
295 SendMessageA (hwndStatus, SB_SIMPLE, TRUE, 0);
298 break;
300 case WM_COMMAND :
301 TRACE("WM_COMMAND wParam=0x%X lParam=0x%lX\n",
302 wParam, lParam);
303 /* WM_COMMAND is not invalid since it is documented
304 * in the windows api reference. So don't output
305 * any FIXME for WM_COMMAND
307 WARN("We don't care about the WM_COMMAND\n");
308 break;
310 default:
311 FIXME("Invalid Message 0x%x!\n", uMsg);
312 break;
317 /***********************************************************************
318 * ShowHideMenuCtl [COMCTL32.3]
320 * Shows or hides controls and updates the corresponding menu item.
322 * PARAMS
323 * hwnd [I] handle to the client window.
324 * uFlags [I] menu command id.
325 * lpInfo [I] pointer to an array of integers. (See NOTES.)
327 * RETURNS
328 * Success: TRUE
329 * Failure: FALSE
331 * NOTES
332 * The official documentation is incomplete!
333 * This is the correct documentation:
335 * hwnd
336 * Handle to the window that contains the menu and controls.
338 * uFlags
339 * Identifier of the menu item to receive or loose a check mark.
341 * lpInfo
342 * The array of integers contains pairs of values. BOTH values of
343 * the first pair must be the handles to the application's main menu.
344 * Each subsequent pair consists of a menu id and control id.
347 BOOL WINAPI
348 ShowHideMenuCtl (HWND hwnd, UINT uFlags, LPINT lpInfo)
350 LPINT lpMenuId;
352 TRACE("%p, %x, %p\n", hwnd, uFlags, lpInfo);
354 if (lpInfo == NULL)
355 return FALSE;
357 if (!(lpInfo[0]) || !(lpInfo[1]))
358 return FALSE;
360 /* search for control */
361 lpMenuId = &lpInfo[2];
362 while (*lpMenuId != uFlags)
363 lpMenuId += 2;
365 if (GetMenuState ((HMENU)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
366 /* uncheck menu item */
367 CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
369 /* hide control */
370 lpMenuId++;
371 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
372 SWP_HIDEWINDOW);
374 else {
375 /* check menu item */
376 CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
378 /* show control */
379 lpMenuId++;
380 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
381 SWP_SHOWWINDOW);
384 return TRUE;
388 /***********************************************************************
389 * GetEffectiveClientRect [COMCTL32.4]
391 * PARAMS
392 * hwnd [I] handle to the client window.
393 * lpRect [O] pointer to the rectangle of the client window
394 * lpInfo [I] pointer to an array of integers (see NOTES)
396 * RETURNS
397 * No return value.
399 * NOTES
400 * The official documentation is incomplete!
401 * This is the correct documentation:
403 * lpInfo
404 * (will be written ...)
407 VOID WINAPI
408 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo)
410 RECT rcCtrl;
411 INT *lpRun;
412 HWND hwndCtrl;
414 TRACE("(0x%08lx 0x%08lx 0x%08lx)\n",
415 (DWORD)hwnd, (DWORD)lpRect, (DWORD)lpInfo);
417 GetClientRect (hwnd, lpRect);
418 lpRun = lpInfo;
420 do {
421 lpRun += 2;
422 if (*lpRun == 0)
423 return;
424 lpRun++;
425 hwndCtrl = GetDlgItem (hwnd, *lpRun);
426 if (GetWindowLongA (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
427 TRACE("control id 0x%x\n", *lpRun);
428 GetWindowRect (hwndCtrl, &rcCtrl);
429 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
430 SubtractRect (lpRect, lpRect, &rcCtrl);
432 lpRun++;
433 } while (*lpRun);
437 /***********************************************************************
438 * DrawStatusTextW [COMCTL32.@]
440 * Draws text with borders, like in a status bar.
442 * PARAMS
443 * hdc [I] handle to the window's display context
444 * lprc [I] pointer to a rectangle
445 * text [I] pointer to the text
446 * style [I] drawing style
448 * RETURNS
449 * No return value.
451 * NOTES
452 * The style variable can have one of the following values:
453 * (will be written ...)
456 void WINAPI DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style)
458 RECT r = *lprc;
459 UINT border = BDR_SUNKENOUTER;
461 if (style & SBT_POPOUT)
462 border = BDR_RAISEDOUTER;
463 else if (style & SBT_NOBORDERS)
464 border = 0;
466 DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
468 /* now draw text */
469 if (text) {
470 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
471 UINT align = DT_LEFT;
472 if (*text == L'\t') {
473 text++;
474 align = DT_CENTER;
475 if (*text == L'\t') {
476 text++;
477 align = DT_RIGHT;
480 r.left += 3;
481 if (style & SBT_RTLREADING)
482 FIXME("Unsupported RTL style!\n");
483 DrawTextW (hdc, text, -1, &r, align|DT_VCENTER|DT_SINGLELINE);
484 SetBkMode(hdc, oldbkmode);
489 /***********************************************************************
490 * DrawStatusText [COMCTL32.@]
491 * DrawStatusTextA [COMCTL32.5]
493 * Draws text with borders, like in a status bar.
495 * PARAMS
496 * hdc [I] handle to the window's display context
497 * lprc [I] pointer to a rectangle
498 * text [I] pointer to the text
499 * style [I] drawing style
501 * RETURNS
502 * No return value.
505 void WINAPI DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style)
507 INT len;
508 LPWSTR textW = NULL;
510 if ( text ) {
511 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
512 if ( (textW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )) )
513 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
516 DrawStatusTextW( hdc, lprc, textW, style );
517 HeapFree( GetProcessHeap(), 0, textW );
521 /***********************************************************************
522 * CreateStatusWindow [COMCTL32.@]
523 * CreateStatusWindowA [COMCTL32.6]
525 * Creates a status bar
527 * PARAMS
528 * style [I] window style
529 * text [I] pointer to the window text
530 * parent [I] handle to the parent window
531 * wid [I] control id of the status bar
533 * RETURNS
534 * Success: handle to the status window
535 * Failure: 0
538 HWND WINAPI
539 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
541 return CreateWindowA(STATUSCLASSNAMEA, text, style,
542 CW_USEDEFAULT, CW_USEDEFAULT,
543 CW_USEDEFAULT, CW_USEDEFAULT,
544 parent, (HMENU)wid, 0, 0);
548 /***********************************************************************
549 * CreateStatusWindowW [COMCTL32.@] Creates a status bar control
551 * PARAMS
552 * style [I] window style
553 * text [I] pointer to the window text
554 * parent [I] handle to the parent window
555 * wid [I] control id of the status bar
557 * RETURNS
558 * Success: handle to the status window
559 * Failure: 0
562 HWND WINAPI
563 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
565 return CreateWindowW(STATUSCLASSNAMEW, text, style,
566 CW_USEDEFAULT, CW_USEDEFAULT,
567 CW_USEDEFAULT, CW_USEDEFAULT,
568 parent, (HMENU)wid, 0, 0);
572 /***********************************************************************
573 * CreateUpDownControl [COMCTL32.16] Creates an up-down control
575 * PARAMS
576 * style [I] window styles
577 * x [I] horizontal position of the control
578 * y [I] vertical position of the control
579 * cx [I] with of the control
580 * cy [I] height of the control
581 * parent [I] handle to the parent window
582 * id [I] the control's identifier
583 * inst [I] handle to the application's module instance
584 * buddy [I] handle to the buddy window, can be NULL
585 * maxVal [I] upper limit of the control
586 * minVal [I] lower limit of the control
587 * curVal [I] current value of the control
589 * RETURNS
590 * Success: handle to the updown control
591 * Failure: 0
594 HWND WINAPI
595 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
596 HWND parent, INT id, HINSTANCE inst,
597 HWND buddy, INT maxVal, INT minVal, INT curVal)
599 HWND hUD =
600 CreateWindowA (UPDOWN_CLASSA, 0, style, x, y, cx, cy,
601 parent, (HMENU)id, inst, 0);
602 if (hUD) {
603 SendMessageA (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
604 SendMessageA (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
605 SendMessageA (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
608 return hUD;
612 /***********************************************************************
613 * InitCommonControls [COMCTL32.17]
615 * Registers the common controls.
617 * PARAMS
618 * No parameters.
620 * RETURNS
621 * No return values.
623 * NOTES
624 * This function is just a dummy.
625 * The Win95 controls are registered at the DLL's initialization.
626 * To register other controls InitCommonControlsEx() must be used.
629 VOID WINAPI
630 InitCommonControls (void)
635 /***********************************************************************
636 * InitCommonControlsEx [COMCTL32.@]
638 * Registers the common controls.
640 * PARAMS
641 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
643 * RETURNS
644 * Success: TRUE
645 * Failure: FALSE
647 * NOTES
648 * Only the additional common controls are registered by this function.
649 * The Win95 controls are registered at the DLL's initialization.
651 * FIXME
652 * implement the following control classes:
653 * ICC_LINK_CLASS
654 * ICC_STANDARD_CLASSES
657 BOOL WINAPI
658 InitCommonControlsEx (LPINITCOMMONCONTROLSEX lpInitCtrls)
660 INT cCount;
661 DWORD dwMask;
663 if (!lpInitCtrls)
664 return FALSE;
665 if (lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
666 return FALSE;
668 TRACE("(0x%08lx)\n", lpInitCtrls->dwICC);
670 for (cCount = 0; cCount < 32; cCount++) {
671 dwMask = 1 << cCount;
672 if (!(lpInitCtrls->dwICC & dwMask))
673 continue;
675 switch (lpInitCtrls->dwICC & dwMask) {
676 /* dummy initialization */
677 case ICC_ANIMATE_CLASS:
678 case ICC_BAR_CLASSES:
679 case ICC_LISTVIEW_CLASSES:
680 case ICC_TREEVIEW_CLASSES:
681 case ICC_TAB_CLASSES:
682 case ICC_UPDOWN_CLASS:
683 case ICC_PROGRESS_CLASS:
684 case ICC_HOTKEY_CLASS:
685 break;
687 /* advanced classes - not included in Win95 */
688 case ICC_DATE_CLASSES:
689 MONTHCAL_Register ();
690 DATETIME_Register ();
691 break;
693 case ICC_USEREX_CLASSES:
694 COMBOEX_Register ();
695 break;
697 case ICC_COOL_CLASSES:
698 REBAR_Register ();
699 break;
701 case ICC_INTERNET_CLASSES:
702 IPADDRESS_Register ();
703 break;
705 case ICC_PAGESCROLLER_CLASS:
706 PAGER_Register ();
707 break;
709 case ICC_NATIVEFNTCTL_CLASS:
710 NATIVEFONT_Register ();
711 break;
713 default:
714 FIXME("Unknown class! dwICC=0x%lX\n", dwMask);
715 break;
719 return TRUE;
723 /***********************************************************************
724 * CreateToolbarEx [COMCTL32.@] Creates a tool bar window
726 * PARAMS
727 * hwnd
728 * style
729 * wID
730 * nBitmaps
731 * hBMInst
732 * wBMID
733 * lpButtons
734 * iNumButtons
735 * dxButton
736 * dyButton
737 * dxBitmap
738 * dyBitmap
739 * uStructSize
741 * RETURNS
742 * Success: handle to the tool bar control
743 * Failure: 0
746 HWND WINAPI
747 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
748 HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons,
749 INT iNumButtons, INT dxButton, INT dyButton,
750 INT dxBitmap, INT dyBitmap, UINT uStructSize)
752 HWND hwndTB;
754 /* If not position is specified then put it at the top */
755 if ((style & CCS_BOTTOM) == 0) {
756 style|=CCS_TOP;
759 hwndTB =
760 CreateWindowExA (0, TOOLBARCLASSNAMEA, "", style|WS_CHILD, 0, 0, 0, 0,
761 hwnd, (HMENU)wID, 0, NULL);
762 if(hwndTB) {
763 TBADDBITMAP tbab;
765 SendMessageA (hwndTB, TB_BUTTONSTRUCTSIZE,
766 (WPARAM)uStructSize, 0);
768 /* set bitmap and button size */
769 /*If CreateToolbarEx receives 0, windows sets default values*/
770 if (dxBitmap <= 0)
771 dxBitmap = 16;
772 if (dyBitmap <= 0)
773 dyBitmap = 15;
774 SendMessageA (hwndTB, TB_SETBITMAPSIZE, 0,
775 MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap));
777 if (dxButton <= 0)
778 dxButton = 24;
779 if (dyButton <= 0)
780 dyButton = 22;
781 SendMessageA (hwndTB, TB_SETBUTTONSIZE, 0,
782 MAKELPARAM((WORD)dxButton, (WORD)dyButton));
785 /* add bitmaps */
786 if (nBitmaps > 0)
788 tbab.hInst = hBMInst;
789 tbab.nID = wBMID;
791 SendMessageA (hwndTB, TB_ADDBITMAP,
792 (WPARAM)nBitmaps, (LPARAM)&tbab);
794 /* add buttons */
795 if(iNumButtons > 0)
796 SendMessageA (hwndTB, TB_ADDBUTTONSA,
797 (WPARAM)iNumButtons, (LPARAM)lpButtons);
800 return hwndTB;
804 /***********************************************************************
805 * CreateMappedBitmap [COMCTL32.8]
807 * PARAMS
808 * hInstance [I]
809 * idBitmap [I]
810 * wFlags [I]
811 * lpColorMap [I]
812 * iNumMaps [I]
814 * RETURNS
815 * Success: handle to the new bitmap
816 * Failure: 0
819 HBITMAP WINAPI
820 CreateMappedBitmap (HINSTANCE hInstance, INT idBitmap, UINT wFlags,
821 LPCOLORMAP lpColorMap, INT iNumMaps)
823 HGLOBAL hglb;
824 HRSRC hRsrc;
825 LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
826 UINT nSize, nColorTableSize;
827 RGBQUAD *pColorTable;
828 INT iColor, i, iMaps, nWidth, nHeight;
829 HDC hdcScreen;
830 HBITMAP hbm;
831 LPCOLORMAP sysColorMap;
832 COLORREF cRef;
833 COLORMAP internalColorMap[4] =
834 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
836 /* initialize pointer to colortable and default color table */
837 if (lpColorMap) {
838 iMaps = iNumMaps;
839 sysColorMap = lpColorMap;
841 else {
842 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
843 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
844 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
845 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
846 iMaps = 4;
847 sysColorMap = (LPCOLORMAP)internalColorMap;
850 hRsrc = FindResourceA (hInstance, (LPSTR)idBitmap, RT_BITMAPA);
851 if (hRsrc == 0)
852 return 0;
853 hglb = LoadResource (hInstance, hRsrc);
854 if (hglb == 0)
855 return 0;
856 lpBitmap = (LPBITMAPINFOHEADER)LockResource (hglb);
857 if (lpBitmap == NULL)
858 return 0;
860 nColorTableSize = (1 << lpBitmap->biBitCount);
861 nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
862 lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize);
863 if (lpBitmapInfo == NULL)
864 return 0;
865 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
867 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)lpBitmapInfo->biSize);
869 for (iColor = 0; iColor < nColorTableSize; iColor++) {
870 for (i = 0; i < iMaps; i++) {
871 cRef = RGB(pColorTable[iColor].rgbRed,
872 pColorTable[iColor].rgbGreen,
873 pColorTable[iColor].rgbBlue);
874 if ( cRef == sysColorMap[i].from) {
875 #if 0
876 if (wFlags & CBS_MASKED) {
877 if (sysColorMap[i].to != COLOR_BTNTEXT)
878 pColorTable[iColor] = RGB(255, 255, 255);
880 else
881 #endif
882 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
883 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
884 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
885 break;
889 nWidth = (INT)lpBitmapInfo->biWidth;
890 nHeight = (INT)lpBitmapInfo->biHeight;
891 hdcScreen = GetDC (NULL);
892 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
893 if (hbm) {
894 HDC hdcDst = CreateCompatibleDC (hdcScreen);
895 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
896 LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
897 lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
898 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
899 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
900 SRCCOPY);
901 SelectObject (hdcDst, hbmOld);
902 DeleteDC (hdcDst);
904 ReleaseDC (NULL, hdcScreen);
905 GlobalFree ((HGLOBAL)lpBitmapInfo);
906 FreeResource (hglb);
908 return hbm;
912 /***********************************************************************
913 * CreateToolbar [COMCTL32.7] Creates a tool bar control
915 * PARAMS
916 * hwnd
917 * style
918 * wID
919 * nBitmaps
920 * hBMInst
921 * wBMID
922 * lpButtons
923 * iNumButtons
925 * RETURNS
926 * Success: handle to the tool bar control
927 * Failure: 0
929 * NOTES
930 * Do not use this functions anymore. Use CreateToolbarEx instead.
933 HWND WINAPI
934 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
935 HINSTANCE hBMInst, UINT wBMID,
936 LPCTBBUTTON lpButtons,INT iNumButtons)
938 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
939 hBMInst, wBMID, lpButtons,
940 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
944 /***********************************************************************
945 * DllGetVersion [COMCTL32.@]
947 * Retrieves version information of the 'COMCTL32.DLL'
949 * PARAMS
950 * pdvi [O] pointer to version information structure.
952 * RETURNS
953 * Success: S_OK
954 * Failure: E_INVALIDARG
956 * NOTES
957 * Returns version of a comctl32.dll from IE4.01 SP1.
960 HRESULT WINAPI
961 COMCTL32_DllGetVersion (DLLVERSIONINFO *pdvi)
963 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
964 WARN("wrong DLLVERSIONINFO size from app\n");
965 return E_INVALIDARG;
968 pdvi->dwMajorVersion = COMCTL32_VERSION;
969 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
970 pdvi->dwBuildNumber = 2919;
971 pdvi->dwPlatformID = 6304;
973 TRACE("%lu.%lu.%lu.%lu\n",
974 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
975 pdvi->dwBuildNumber, pdvi->dwPlatformID);
977 return S_OK;
980 /***********************************************************************
981 * DllInstall (COMCTL32.@)
983 HRESULT WINAPI COMCTL32_DllInstall(BOOL bInstall, LPCWSTR cmdline)
985 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
986 debugstr_w(cmdline));
988 return S_OK;
991 /***********************************************************************
992 * _TrackMouseEvent [COMCTL32.@]
994 * Requests notification of mouse events
996 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
997 * to the hwnd specified in the ptme structure. After the event message
998 * is posted to the hwnd, the entry in the queue is removed.
1000 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1001 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1002 * immediately and the TME_LEAVE flag being ignored.
1004 * PARAMS
1005 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1007 * RETURNS
1008 * Success: non-zero
1009 * Failure: zero
1011 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1015 BOOL WINAPI
1016 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1018 return TrackMouseEvent (ptme);
1021 /*************************************************************************
1022 * GetMUILanguage [COMCTL32.@]
1024 * FIXME: "Returns the language currently in use by the common controls
1025 * for a particular process." (MSDN)
1028 LANGID WINAPI GetMUILanguage (VOID)
1030 return COMCTL32_uiLang;
1034 /*************************************************************************
1035 * InitMUILanguage [COMCTL32.@]
1037 * FIXME: "Enables an application to specify a language to be used with
1038 * the common controls that is different than the system language." (MSDN)
1042 VOID WINAPI InitMUILanguage (LANGID uiLang)
1044 COMCTL32_uiLang = uiLang;
1048 /***********************************************************************
1049 * SetWindowSubclass [COMCTL32.410]
1051 * Starts a window subclass
1053 * PARAMS
1054 * hWnd [in] handle to window subclass.
1055 * pfnSubclass [in] Pointer to new window procedure.
1056 * uIDSubclass [in] Unique identifier of sublass together with pfnSubclass.
1057 * dwRef [in] Reference data to pass to window procedure.
1059 * RETURNS
1060 * Success: non-zero
1061 * Failure: zero
1063 * BUGS
1064 * If an application manually subclasses a window after subclassing it with
1065 * this API and then with this API again, then none of the previous
1066 * subclasses get called or the origional window procedure.
1069 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1070 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1072 LPSUBCLASS_INFO stack;
1073 int newnum, n;
1075 TRACE ("(%p, %p, %x, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1077 /* Since the window procedure that we set here has two additional arguments,
1078 * we can't simply set it as the new window procedure of the window. So we
1079 * set our own window procedure and then calculate the other two arguments
1080 * from there. */
1082 /* See if we have been called for this window */
1083 stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1084 if (!stack) {
1085 /* allocate stack */
1086 stack = (LPSUBCLASS_INFO)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY,
1087 sizeof(SUBCLASS_INFO));
1088 if (!stack) {
1089 ERR ("Failed to allocate our Subclassing stack");
1090 return FALSE;
1092 SetPropA (hWnd, COMCTL32_aSubclass, (HANDLE)stack);
1094 /* set window procedure to our own and save the current one */
1095 if (IsWindowUnicode (hWnd))
1096 stack->origproc = (WNDPROC)SetWindowLongW (hWnd, GWL_WNDPROC,
1097 (LONG)DefSubclassProc);
1098 else
1099 stack->origproc = (WNDPROC)SetWindowLongA (hWnd, GWL_WNDPROC,
1100 (LONG)DefSubclassProc);
1101 } else {
1102 WNDPROC current;
1103 if (IsWindowUnicode (hWnd))
1104 current = (WNDPROC)GetWindowLongW (hWnd, GWL_WNDPROC);
1105 else
1106 current = (WNDPROC)GetWindowLongA (hWnd, GWL_WNDPROC);
1108 if (current != DefSubclassProc) {
1109 ERR ("Application has subclassed with our procedure, then manually, then with us again. The current implementation can't handle this.\n");
1110 return FALSE;
1114 /* Check to see if we have called this function with the same uIDSubClass
1115 * and pfnSubclass */
1116 for (n = 0; n <= stack->stacknum + stack->stacknew - 1; n++)
1117 if ((stack->SubclassProcs[n].id == uIDSubclass) &&
1118 (stack->SubclassProcs[n].subproc == pfnSubclass)) {
1119 stack->SubclassProcs[n].ref = dwRef;
1120 return TRUE;
1123 if ((stack->stacknum + stack->stacknew) >= 32) {
1124 ERR ("We have a Subclass stack overflow, please increment size");
1125 return FALSE;
1128 /* we can't simply increment both stackpos and stacknum because there might
1129 * be a window procedure running lower in the stack, we can only get them
1130 * up to date once the last window procedure has run */
1131 if (stack->stacknum == stack->stackpos) {
1132 stack->stacknum++;
1133 stack->stackpos++;
1134 } else
1135 stack->stacknew++;
1137 newnum = stack->stacknew + stack->stacknum - 1;
1139 stack->SubclassProcs[newnum].subproc = pfnSubclass;
1140 stack->SubclassProcs[newnum].ref = dwRef;
1141 stack->SubclassProcs[newnum].id = uIDSubclass;
1143 return TRUE;
1147 /***********************************************************************
1148 * GetWindowSubclass [COMCTL32.411]
1150 * Gets the Reference data from a subclass.
1152 * PARAMS
1153 * hWnd [in] Handle to window which were subclassing
1154 * pfnSubclass [in] Pointer to the subclass procedure
1155 * uID [in] Unique indentifier of the subclassing procedure
1156 * pdwRef [out] Pointer to the reference data
1158 * RETURNS
1159 * Success: Non-zero
1160 * Failure: 0
1163 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1164 UINT_PTR uID, DWORD_PTR *pdwRef)
1166 LPSUBCLASS_INFO stack;
1167 int n;
1169 TRACE ("(%p, %p, %x, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1171 /* See if we have been called for this window */
1172 stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1173 if (!stack)
1174 return FALSE;
1176 for (n = 0; n <= stack->stacknum + stack->stacknew - 1; n++)
1177 if ((stack->SubclassProcs[n].id == uID) &&
1178 (stack->SubclassProcs[n].subproc == pfnSubclass)) {
1179 *pdwRef = stack->SubclassProcs[n].ref;
1180 return TRUE;
1183 return FALSE;
1187 /***********************************************************************
1188 * RemoveWindowSubclass [COMCTL32.412]
1190 * Removes a window subclass.
1192 * PARAMS
1193 * hWnd [in] Handle to the window were subclassing
1194 * pfnSubclass [in] Pointer to the subclass procedure
1195 * uID [in] Unique identifier of this subclass
1197 * RETURNS
1198 * Success: non-zero
1199 * Failure: zero
1202 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1204 LPSUBCLASS_INFO stack;
1205 int n;
1207 TRACE ("(%p, %p, %x)\n", hWnd, pfnSubclass, uID);
1209 /* Find the Subclass to remove */
1210 stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1211 if (!stack)
1212 return FALSE;
1214 if ((stack->stacknum == stack->stackpos == 1) && !stack->stacknew) {
1215 TRACE("Last Subclass removed, cleaning up\n");
1216 /* clean up our heap and reset the origional window procedure */
1217 if (IsWindowUnicode (hWnd))
1218 SetWindowLongW (hWnd, GWL_WNDPROC, (LONG)stack->origproc);
1219 else
1220 SetWindowLongA (hWnd, GWL_WNDPROC, (LONG)stack->origproc);
1221 HeapFree (GetProcessHeap (), 0, stack);
1222 RemovePropA( hWnd, COMCTL32_aSubclass );
1223 return TRUE;
1226 for (n = stack->stacknum + stack->stacknew - 1; n >= 0; n--)
1227 if ((stack->SubclassProcs[n].id == uID) &&
1228 (stack->SubclassProcs[n].subproc == pfnSubclass)) {
1229 if (n != (stack->stacknum + stack->stacknew))
1230 /* Fill the hole in the stack */
1231 memmove (&stack->SubclassProcs[n], &stack->SubclassProcs[n + 1],
1232 sizeof(stack->SubclassProcs[0]) * (stack->stacknew + stack->stacknum - n));
1233 stack->SubclassProcs[n].subproc = NULL;
1234 stack->SubclassProcs[n].ref = 0;
1235 stack->SubclassProcs[n].id = 0;
1237 /* If we are currently running a window procedure we have to manipulate
1238 * the stack position pointers so that we don't corrupt the stack */
1239 if ((n < stack->stackpos) || (stack->stackpos == stack->stacknum)) {
1240 stack->stacknum--;
1241 stack->stackpos--;
1242 } else if (n >= stack->stackpos)
1243 stack->stacknew--;
1244 return TRUE;
1247 return FALSE;
1251 /***********************************************************************
1252 * DefSubclassProc [COMCTL32.413]
1254 * Calls the next window procedure (ie. the one before this subclass)
1256 * PARAMS
1257 * hWnd [in] The window that we're subclassing
1258 * uMsg [in] Message
1259 * wParam [in] WPARAM
1260 * lParam [in] LPARAM
1262 * RETURNS
1263 * Success: non-zero
1264 * Failure: zero
1267 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1269 LPSUBCLASS_INFO stack;
1270 int stackpos;
1271 LRESULT ret;
1273 /* retrieve our little stack from the Properties */
1274 stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1275 if (!stack) {
1276 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1277 return 0;
1280 /* If we are at pos 0 then we have to call the origional window procedure */
1281 if (stack->stackpos == 0) {
1282 if (IsWindowUnicode (hWnd))
1283 return CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1284 else
1285 return CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1288 stackpos = --stack->stackpos;
1289 /* call the Subclass procedure from the stack */
1290 ret = stack->SubclassProcs[stackpos].subproc (hWnd, uMsg, wParam, lParam,
1291 stack->SubclassProcs[stackpos].id, stack->SubclassProcs[stackpos].ref);
1292 stack->stackpos++;
1294 if ((stack->stackpos == stack->stacknum) && stack->stacknew) {
1295 stack->stacknum += stack->stacknew;
1296 stack->stackpos += stack->stacknew;
1297 stack->stacknew = 0;
1300 /* If we removed the last entry in our stack while a window procedure was
1301 * running then we have to clean up */
1302 if (stack->stackpos == stack->stacknum == 0) {
1303 TRACE("Last Subclass removed, cleaning up\n");
1304 /* clean up our heap and reset the origional window procedure */
1305 if (IsWindowUnicode (hWnd))
1306 SetWindowLongW (hWnd, GWL_WNDPROC, (LONG)stack->origproc);
1307 else
1308 SetWindowLongA (hWnd, GWL_WNDPROC, (LONG)stack->origproc);
1309 HeapFree (GetProcessHeap (), 0, stack);
1310 RemovePropA( hWnd, COMCTL32_aSubclass );
1311 return TRUE;
1314 return ret;
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.
1324 * PARAMS
1325 * hwndOwner [I] Handle to the window that will own the tool tip.
1327 * RETURNS
1328 * Success: Handle of tool tip window.
1329 * Failure: NULL
1332 HWND
1333 COMCTL32_CreateToolTip(HWND hwndOwner)
1335 HWND hwndToolTip;
1337 hwndToolTip = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
1338 CW_USEDEFAULT, CW_USEDEFAULT,
1339 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1340 0, 0, 0);
1342 /* Send NM_TOOLTIPSCREATED notification */
1343 if (hwndToolTip)
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 = GetWindowLongA(hwndTrueOwner, GWL_ID);
1350 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1351 nmttc.hwndToolTips = hwndToolTip;
1353 SendMessageA(GetParent(hwndTrueOwner), WM_NOTIFY,
1354 (WPARAM)GetWindowLongA(hwndTrueOwner, GWL_ID),
1355 (LPARAM)&nmttc);
1358 return hwndToolTip;
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
1368 * PARAMS
1369 * none
1371 * RETURNS
1372 * none
1375 VOID
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);