Like the AUTORADIOBUTTON, the parent of a RADIOBUTTON style button
[wine] / dlls / comctl32 / commctrl.c
1 /*              
2  * Common controls functions
3  *
4  * Copyright 1997 Dimitrie O. Paun
5  * Copyright 1998 Eric Kohl
6  *
7  */
8
9 #include <string.h>
10
11 #include "winbase.h"
12 #include "heap.h"
13 #include "commctrl.h"
14 #include "animate.h"
15 #include "comboex.h"
16 #include "datetime.h"
17 #include "flatsb.h"
18 #include "header.h"
19 #include "hotkey.h"
20 #include "ipaddress.h"
21 #include "listview.h"
22 #include "monthcal.h"
23 #include "nativefont.h"
24 #include "pager.h"
25 #include "progress.h"
26 #include "rebar.h"
27 #include "status.h"
28 #include "tab.h"
29 #include "toolbar.h"
30 #include "tooltips.h"
31 #include "trackbar.h"
32 #include "treeview.h"
33 #include "updown.h"
34 #include "debugtools.h"
35 #include "winerror.h"
36
37 DEFAULT_DEBUG_CHANNEL(commctrl)
38
39
40 HANDLE COMCTL32_hHeap = (HANDLE)NULL;
41 DWORD    COMCTL32_dwProcessesAttached = 0;
42 LPSTR    COMCTL32_aSubclass = (LPSTR)NULL;
43 HMODULE COMCTL32_hModule = 0;
44
45
46 /***********************************************************************
47  * COMCTL32_LibMain [Internal] Initializes the internal 'COMCTL32.DLL'.
48  *
49  * PARAMS
50  *     hinstDLL    [I] handle to the 'dlls' instance
51  *     fdwReason   [I]
52  *     lpvReserved [I] reserverd, must be NULL
53  *
54  * RETURNS
55  *     Success: TRUE
56  *     Failure: FALSE
57  */
58
59 BOOL WINAPI
60 COMCTL32_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
61 {
62     TRACE("%x,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
63
64     switch (fdwReason) {
65         case DLL_PROCESS_ATTACH:
66             if (COMCTL32_dwProcessesAttached == 0) {
67
68                 /* This will be wrong for any other process attching in this address-space! */
69                 COMCTL32_hModule = (HMODULE)hinstDLL;
70
71                 /* create private heap */
72                 COMCTL32_hHeap = HeapCreate (0, 0x10000, 0);
73                 TRACE("Heap created: 0x%x\n", COMCTL32_hHeap);
74
75                 /* add global subclassing atom (used by 'tooltip' and 'updown') */
76                 COMCTL32_aSubclass = (LPSTR)(DWORD)GlobalAddAtomA ("CC32SubclassInfo");
77                 TRACE("Subclassing atom added: %p\n",
78                        COMCTL32_aSubclass);
79
80                 /* register all Win95 common control classes */
81                 ANIMATE_Register ();
82                 FLATSB_Register ();
83                 HEADER_Register ();
84                 HOTKEY_Register ();
85                 LISTVIEW_Register ();
86                 PROGRESS_Register ();
87                 STATUS_Register ();
88                 TAB_Register ();
89                 TOOLBAR_Register ();
90                 TOOLTIPS_Register ();
91                 TRACKBAR_Register ();
92                 TREEVIEW_Register ();
93                 UPDOWN_Register ();
94             }
95             COMCTL32_dwProcessesAttached++;
96             break;
97
98         case DLL_PROCESS_DETACH:
99             COMCTL32_dwProcessesAttached--;
100             if (COMCTL32_dwProcessesAttached == 0) {
101                 /* unregister all common control classes */
102                 ANIMATE_Unregister ();
103                 COMBOEX_Unregister ();
104                 DATETIME_Unregister ();
105                 FLATSB_Unregister ();
106                 HEADER_Unregister ();
107                 HOTKEY_Unregister ();
108                 IPADDRESS_Unregister ();
109                 LISTVIEW_Unregister ();
110                 MONTHCAL_Unregister ();
111                 NATIVEFONT_Unregister ();
112                 PAGER_Unregister ();
113                 PROGRESS_Unregister ();
114                 REBAR_Unregister ();
115                 STATUS_Unregister ();
116                 TAB_Unregister ();
117                 TOOLBAR_Unregister ();
118                 TOOLTIPS_Unregister ();
119                 TRACKBAR_Unregister ();
120                 TREEVIEW_Unregister ();
121                 UPDOWN_Unregister ();
122
123                 /* delete global subclassing atom */
124                 GlobalDeleteAtom (LOWORD(COMCTL32_aSubclass));
125                 TRACE("Subclassing atom deleted: %p\n",
126                        COMCTL32_aSubclass);
127                 COMCTL32_aSubclass = (LPSTR)NULL;
128
129                 /* destroy private heap */
130                 HeapDestroy (COMCTL32_hHeap);
131                 TRACE("Heap destroyed: 0x%x\n", COMCTL32_hHeap);
132                 COMCTL32_hHeap = (HANDLE)NULL;
133             }
134             break;
135     }
136
137     return TRUE;
138 }
139
140
141 /***********************************************************************
142  * MenuHelp [COMCTL32.2]
143  *
144  * PARAMS
145  *     uMsg       [I] message (WM_MENUSELECT) (see NOTES)
146  *     wParam     [I] wParam of the message uMsg
147  *     lParam     [I] lParam of the message uMsg
148  *     hMainMenu  [I] handle to the application's main menu
149  *     hInst      [I] handle to the module that contains string resources
150  *     hwndStatus [I] handle to the status bar window
151  *     lpwIDs     [I] pointer to an array of intergers (see NOTES)
152  *
153  * RETURNS
154  *     No return value
155  *
156  * NOTES
157  *     The official documentation is incomplete!
158  *     This is the correct documentation:
159  *
160  *     uMsg:
161  *     MenuHelp() does NOT handle WM_COMMAND messages! It only handes
162  *     WM_MENUSELECT messages.
163  *
164  *     lpwIDs:
165  *     (will be written ...)
166  */
167
168 VOID WINAPI
169 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
170           HINSTANCE hInst, HWND hwndStatus, LPUINT lpwIDs)
171 {
172     UINT uMenuID = 0;
173
174     if (!IsWindow (hwndStatus))
175         return;
176
177     switch (uMsg) {
178         case WM_MENUSELECT:
179             TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n",
180                    wParam, lParam);
181
182             if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
183                 /* menu was closed */
184                 TRACE("menu was closed!\n");
185                 SendMessageA (hwndStatus, SB_SIMPLE, FALSE, 0);
186             }
187             else {
188                 /* menu item was selected */
189                 if (HIWORD(wParam) & MF_POPUP)
190                     uMenuID = (UINT)*(lpwIDs+1);
191                 else
192                     uMenuID = (UINT)LOWORD(wParam);
193                 TRACE("uMenuID = %u\n", uMenuID);
194
195                 if (uMenuID) {
196                     CHAR szText[256];
197
198                     if (!LoadStringA (hInst, uMenuID, szText, 256))
199                         szText[0] = '\0';
200
201                     SendMessageA (hwndStatus, SB_SETTEXTA,
202                                     255 | SBT_NOBORDERS, (LPARAM)szText);
203                     SendMessageA (hwndStatus, SB_SIMPLE, TRUE, 0);
204                 }
205             }
206             break;
207
208         case WM_COMMAND :
209             TRACE("WM_COMMAND wParam=0x%X lParam=0x%lX\n",
210                    wParam, lParam);
211             /* WM_COMMAND is not invalid since it is documented
212              * in the windows api reference. So don't output
213              * any FIXME for WM_COMMAND
214              */
215             WARN("We don't care about the WM_COMMAND\n");
216             break;
217
218         default:
219             FIXME("Invalid Message 0x%x!\n", uMsg);
220             break;
221     }
222 }
223
224
225 /***********************************************************************
226  * ShowHideMenuCtl [COMCTL32.3] 
227  *
228  * Shows or hides controls and updates the corresponding menu item.
229  *
230  * PARAMS
231  *     hwnd   [I] handle to the client window.
232  *     uFlags [I] menu command id.
233  *     lpInfo [I] pointer to an array of integers. (See NOTES.)
234  *
235  * RETURNS
236  *     Success: TRUE
237  *     Failure: FALSE
238  *
239  * NOTES
240  *     The official documentation is incomplete!
241  *     This is the correct documentation:
242  *
243  *     hwnd
244  *     Handle to the window that contains the menu and controls.
245  *
246  *     uFlags
247  *     Identifier of the menu item to receive or loose a check mark.
248  *
249  *     lpInfo
250  *     The array of integers contains pairs of values. BOTH values of
251  *     the first pair must be the handles to the application's main menu.
252  *     Each subsequent pair consists of a menu id and control id.
253  */
254
255 BOOL WINAPI
256 ShowHideMenuCtl (HWND hwnd, UINT uFlags, LPINT lpInfo)
257 {
258     LPINT lpMenuId;
259
260     TRACE("%x, %x, %p\n", hwnd, uFlags, lpInfo);
261
262     if (lpInfo == NULL)
263         return FALSE;
264
265     if (!(lpInfo[0]) || !(lpInfo[1]))
266         return FALSE;
267
268     /* search for control */
269     lpMenuId = &lpInfo[2];
270     while (*lpMenuId != uFlags)
271         lpMenuId += 2;
272
273     if (GetMenuState (lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
274         /* uncheck menu item */
275         CheckMenuItem (lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
276
277         /* hide control */
278         lpMenuId++;
279         SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
280                         SWP_HIDEWINDOW);
281     }
282     else {
283         /* check menu item */
284         CheckMenuItem (lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
285
286         /* show control */
287         lpMenuId++;
288         SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
289                         SWP_SHOWWINDOW);
290     }
291
292     return TRUE;
293 }
294
295
296 /***********************************************************************
297  * GetEffectiveClientRect [COMCTL32.4]
298  *
299  * PARAMS
300  *     hwnd   [I] handle to the client window.
301  *     lpRect [O] pointer to the rectangle of the client window
302  *     lpInfo [I] pointer to an array of integers (see NOTES)
303  *
304  * RETURNS
305  *     No return value.
306  *
307  * NOTES
308  *     The official documentation is incomplete!
309  *     This is the correct documentation:
310  *
311  *     lpInfo
312  *     (will be written...)
313  */
314
315 VOID WINAPI
316 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo)
317 {
318     RECT rcCtrl;
319     INT  *lpRun;
320     HWND hwndCtrl;
321
322     TRACE("(0x%08lx 0x%08lx 0x%08lx)\n",
323            (DWORD)hwnd, (DWORD)lpRect, (DWORD)lpInfo);
324
325     GetClientRect (hwnd, lpRect);
326     lpRun = lpInfo;
327
328     do {
329         lpRun += 2;
330         if (*lpRun == 0)
331             return;
332         lpRun++;
333         hwndCtrl = GetDlgItem (hwnd, *lpRun);
334         if (GetWindowLongA (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
335             TRACE("control id 0x%x\n", *lpRun);
336             GetWindowRect (hwndCtrl, &rcCtrl);
337             MapWindowPoints ((HWND)0, hwnd, (LPPOINT)&rcCtrl, 2);
338             SubtractRect (lpRect, lpRect, &rcCtrl);
339         }
340         lpRun++;
341     } while (*lpRun);
342 }
343
344
345 /***********************************************************************
346  * DrawStatusTextA [COMCTL32.5][COMCTL32.27]
347  *
348  * Draws text with borders, like in a status bar.
349  *
350  * PARAMS
351  *     hdc   [I] handle to the window's display context
352  *     lprc  [I] pointer to a rectangle
353  *     text  [I] pointer to the text
354  *     style [I] drawing style
355  *
356  * RETURNS
357  *     No return value.
358  *
359  * NOTES
360  *     The style variable can have one of the following values:
361  *     (will be written ...)
362  */
363
364 VOID WINAPI
365 DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style)
366 {
367     RECT r = *lprc;
368     UINT border = BDR_SUNKENOUTER;
369
370     if (style & SBT_POPOUT)
371       border = BDR_RAISEDOUTER;
372     else if (style & SBT_NOBORDERS)
373       border = 0;
374
375     DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST|BF_MIDDLE);
376
377     /* now draw text */
378     if (text) {
379       int oldbkmode = SetBkMode (hdc, TRANSPARENT);
380       r.left += 3;
381       DrawTextA (hdc, text, lstrlenA(text),
382                    &r, DT_LEFT|DT_VCENTER|DT_SINGLELINE);  
383       if (oldbkmode != TRANSPARENT)
384         SetBkMode(hdc, oldbkmode);
385     }
386 }
387
388
389 /***********************************************************************
390  * DrawStatusTextW [COMCTL32.28]
391  *
392  * Draws text with borders, like in a status bar.
393  *
394  * PARAMS
395  *     hdc   [I] handle to the window's display context
396  *     lprc  [I] pointer to a rectangle
397  *     text  [I] pointer to the text
398  *     style [I] drawing style
399  *
400  * RETURNS
401  *     No return value.
402  */
403
404 VOID WINAPI
405 DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style)
406 {
407     LPSTR p = HEAP_strdupWtoA (GetProcessHeap (), 0, text);
408     DrawStatusTextA (hdc, lprc, p, style);
409     HeapFree (GetProcessHeap (), 0, p );
410 }
411
412
413 /***********************************************************************
414  * CreateStatusWindowA [COMCTL32.6][COMCTL32.21]
415  *
416  * Creates a status bar
417  *
418  * PARAMS
419  *     style  [I] window style
420  *     text   [I] pointer to the window text
421  *     parent [I] handle to the parent window
422  *     wid    [I] control id of the status bar
423  *
424  * RETURNS
425  *     Success: handle to the status window
426  *     Failure: 0
427  */
428
429 HWND WINAPI
430 CreateStatusWindowA (INT style, LPCSTR text, HWND parent, UINT wid)
431 {
432     return CreateWindowA(STATUSCLASSNAMEA, text, style, 
433                            CW_USEDEFAULT, CW_USEDEFAULT,
434                            CW_USEDEFAULT, CW_USEDEFAULT, 
435                            parent, wid, 0, 0);
436 }
437
438
439 /***********************************************************************
440  * CreateStatusWindowW [COMCTL32.22] Creates a status bar control
441  *
442  * PARAMS
443  *     style  [I] window style
444  *     text   [I] pointer to the window text
445  *     parent [I] handle to the parent window
446  *     wid    [I] control id of the status bar
447  *
448  * RETURNS
449  *     Success: handle to the status window
450  *     Failure: 0
451  */
452
453 HWND WINAPI
454 CreateStatusWindowW (INT style, LPCWSTR text, HWND parent, UINT wid)
455 {
456     return CreateWindowW(STATUSCLASSNAMEW, text, style,
457                            CW_USEDEFAULT, CW_USEDEFAULT,
458                            CW_USEDEFAULT, CW_USEDEFAULT,
459                            parent, wid, 0, 0);
460 }
461
462
463 /***********************************************************************
464  * CreateUpDownControl [COMCTL32.16] Creates an up-down control
465  *
466  * PARAMS
467  *     style  [I] window styles
468  *     x      [I] horizontal position of the control
469  *     y      [I] vertical position of the control
470  *     cx     [I] with of the control
471  *     cy     [I] height of the control
472  *     parent [I] handle to the parent window
473  *     id     [I] the control's identifier
474  *     inst   [I] handle to the application's module instance
475  *     buddy  [I] handle to the buddy window, can be NULL
476  *     maxVal [I] upper limit of the control
477  *     minVal [I] lower limit of the control
478  *     curVal [I] current value of the control
479  *
480  * RETURNS
481  *     Success: handle to the updown control
482  *     Failure: 0
483  */
484
485 HWND WINAPI
486 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
487                      HWND parent, INT id, HINSTANCE inst,
488                      HWND buddy, INT maxVal, INT minVal, INT curVal)
489 {
490     HWND hUD =
491         CreateWindowA (UPDOWN_CLASSA, 0, style, x, y, cx, cy,
492                          parent, id, inst, 0);
493     if (hUD) {
494         SendMessageA (hUD, UDM_SETBUDDY, buddy, 0);
495         SendMessageA (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
496         SendMessageA (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));     
497     }
498
499     return hUD;
500 }
501
502
503 /***********************************************************************
504  * InitCommonControls [COMCTL32.17]
505  *
506  * Registers the common controls.
507  *
508  * PARAMS
509  *     No parameters.
510  *
511  * RETURNS
512  *     No return values.
513  *
514  * NOTES
515  *     This function is just a dummy.
516  *     The Win95 controls are registered at the DLL's initialization.
517  *     To register other controls InitCommonControlsEx() must be used.
518  */
519
520 VOID WINAPI
521 InitCommonControls (void)
522 {
523 }
524
525
526 /***********************************************************************
527  * InitCommonControlsEx [COMCTL32.81]
528  *
529  * Registers the common controls.
530  *
531  * PARAMS
532  *     lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
533  *
534  * RETURNS
535  *     Success: TRUE
536  *     Failure: FALSE
537  *
538  * NOTES
539  *     Only the additinal common controls are registered by this function.
540  *     The Win95 controls are registered at the DLL's initialization.
541  */
542
543 BOOL WINAPI
544 InitCommonControlsEx (LPINITCOMMONCONTROLSEX lpInitCtrls)
545 {
546     INT cCount;
547     DWORD dwMask;
548
549     if (!lpInitCtrls)
550         return FALSE;
551     if (lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
552         return FALSE;
553
554     TRACE("(0x%08lx)\n", lpInitCtrls->dwICC);
555
556     for (cCount = 0; cCount < 32; cCount++) {
557         dwMask = 1 << cCount;
558         if (!(lpInitCtrls->dwICC & dwMask))
559             continue;
560
561         switch (lpInitCtrls->dwICC & dwMask) {
562             /* dummy initialization */
563             case ICC_ANIMATE_CLASS:
564             case ICC_BAR_CLASSES:
565             case ICC_LISTVIEW_CLASSES:
566             case ICC_TREEVIEW_CLASSES:
567             case ICC_TAB_CLASSES:
568             case ICC_UPDOWN_CLASS:
569             case ICC_PROGRESS_CLASS:
570             case ICC_HOTKEY_CLASS:
571                 break;
572
573             /* advanced classes - not included in Win95 */
574             case ICC_DATE_CLASSES:
575                 MONTHCAL_Register ();
576                 DATETIME_Register ();
577                 break;
578
579             case ICC_USEREX_CLASSES:
580                 COMBOEX_Register ();
581                 break;
582
583             case ICC_COOL_CLASSES:
584                 REBAR_Register ();
585                 break;
586
587             case ICC_INTERNET_CLASSES:
588                 IPADDRESS_Register ();
589                 break;
590
591             case ICC_PAGESCROLLER_CLASS:
592                 PAGER_Register ();
593                 break;
594
595             case ICC_NATIVEFNTCTL_CLASS:
596                 NATIVEFONT_Register ();
597                 break;
598
599             default:
600                 FIXME("Unknown class! dwICC=0x%lX\n", dwMask);
601                 break;
602         }
603     }
604
605     return TRUE;
606 }
607
608
609 /***********************************************************************
610  * CreateToolbarEx [COMCTL32.32] Creates a tool bar window
611  *
612  * PARAMS
613  *     hwnd
614  *     style
615  *     wID
616  *     nBitmaps
617  *     hBMInst
618  *     wBMID
619  *     lpButtons
620  *     iNumButtons
621  *     dxButton
622  *     dyButton
623  *     dxBitmap
624  *     dyBitmap
625  *     uStructSize
626  *
627  * RETURNS
628  *     Success: handle to the tool bar control
629  *     Failure: 0
630  */
631
632 HWND WINAPI
633 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
634                  HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons,
635                  INT iNumButtons, INT dxButton, INT dyButton,
636                  INT dxBitmap, INT dyBitmap, UINT uStructSize)
637 {
638     HWND hwndTB =
639         CreateWindowExA (0, TOOLBARCLASSNAMEA, "", style, 0, 0, 0, 0,
640                            hwnd, (HMENU)wID, 0, NULL);
641     if(hwndTB) {
642         TBADDBITMAP tbab;
643
644         SendMessageA (hwndTB, TB_BUTTONSTRUCTSIZE,
645                         (WPARAM)uStructSize, 0);
646
647         /* set bitmap and button size */
648         /*If CreateToolbarEx receive 0, windows set default values*/
649         if (dyBitmap < 0)
650             dyBitmap = 15;
651         if (dxBitmap < 0)
652             dxBitmap = 16;
653
654             SendMessageA (hwndTB, TB_SETBITMAPSIZE, 0,
655                             MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap));
656             SendMessageA (hwndTB, TB_SETBUTTONSIZE, 0,
657                             MAKELPARAM((WORD)dxButton, (WORD)dyButton));
658
659
660         /* add bitmaps */
661         if (nBitmaps > 0)
662         {
663         tbab.hInst = hBMInst;
664         tbab.nID   = wBMID;
665
666         SendMessageA (hwndTB, TB_ADDBITMAP,
667                         (WPARAM)nBitmaps, (LPARAM)&tbab);
668         }
669         /* add buttons */
670         if(iNumButtons > 0)
671         SendMessageA (hwndTB, TB_ADDBUTTONSA,
672                         (WPARAM)iNumButtons, (LPARAM)lpButtons);
673     }
674
675     return hwndTB;
676 }
677
678
679 /***********************************************************************
680  * CreateMappedBitmap [COMCTL32.8]
681  *
682  * PARAMS
683  *     hInstance  [I]
684  *     idBitmap   [I]
685  *     wFlags     [I]
686  *     lpColorMap [I]
687  *     iNumMaps   [I]
688  *
689  * RETURNS
690  *     Success: handle to the new bitmap
691  *     Failure: 0
692  */
693
694 HBITMAP WINAPI
695 CreateMappedBitmap (HINSTANCE hInstance, INT idBitmap, UINT wFlags,
696                     LPCOLORMAP lpColorMap, INT iNumMaps)
697 {
698     HGLOBAL hglb;
699     HRSRC hRsrc;
700     LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
701     UINT nSize, nColorTableSize;
702     RGBQUAD *pColorTable;
703     INT iColor, i, iMaps, nWidth, nHeight;
704     HDC hdcScreen;
705     HBITMAP hbm;
706     LPCOLORMAP sysColorMap;
707     COLORREF cRef;
708     COLORMAP internalColorMap[4] =
709         {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
710
711     /* initialize pointer to colortable and default color table */
712     if (lpColorMap) {
713         iMaps = iNumMaps;
714         sysColorMap = lpColorMap;
715     }
716     else {
717         internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
718         internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
719         internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
720         internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
721         iMaps = 4;
722         sysColorMap = (LPCOLORMAP)internalColorMap;
723     }
724
725     hRsrc = FindResourceA (hInstance, (LPSTR)idBitmap, RT_BITMAPA);
726     if (hRsrc == 0)
727         return 0;
728     hglb = LoadResource (hInstance, hRsrc);
729     if (hglb == 0)
730         return 0;
731     lpBitmap = (LPBITMAPINFOHEADER)LockResource (hglb);
732     if (lpBitmap == NULL)
733         return 0;
734
735     nColorTableSize = (1 << lpBitmap->biBitCount);
736     nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
737     lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize);
738     if (lpBitmapInfo == NULL)
739         return 0;
740     RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
741
742     pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)lpBitmapInfo->biSize);
743
744     for (iColor = 0; iColor < nColorTableSize; iColor++) {
745         for (i = 0; i < iMaps; i++) {
746             cRef = RGB(pColorTable[iColor].rgbRed,
747                        pColorTable[iColor].rgbGreen,
748                        pColorTable[iColor].rgbBlue);
749             if ( cRef  == sysColorMap[i].from) {
750 #if 0
751                 if (wFlags & CBS_MASKED) {
752                     if (sysColorMap[i].to != COLOR_BTNTEXT)
753                         pColorTable[iColor] = RGB(255, 255, 255);
754                 }
755                 else
756 #endif
757                     pColorTable[iColor].rgbBlue  = GetBValue(sysColorMap[i].to);
758                     pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
759                     pColorTable[iColor].rgbRed   = GetRValue(sysColorMap[i].to);
760                 break;
761             }
762         }
763     }
764     nWidth  = (INT)lpBitmapInfo->biWidth;
765     nHeight = (INT)lpBitmapInfo->biHeight;
766     hdcScreen = GetDC ((HWND)0);
767     hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
768     if (hbm) {
769         HDC hdcDst = CreateCompatibleDC (hdcScreen);
770         HBITMAP hbmOld = SelectObject (hdcDst, hbm);
771         LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
772         lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
773         StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
774                          lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
775                          SRCCOPY);
776         SelectObject (hdcDst, hbmOld);
777         DeleteDC (hdcDst);
778     }
779     ReleaseDC ((HWND)0, hdcScreen);
780     GlobalFree ((HGLOBAL)lpBitmapInfo);
781     FreeResource (hglb);
782
783     return hbm;
784 }
785
786
787 /***********************************************************************
788  * CreateToolbar [COMCTL32.7] Creates a tool bar control
789  *
790  * PARAMS
791  *     hwnd
792  *     style
793  *     wID
794  *     nBitmaps
795  *     hBMInst
796  *     wBMID
797  *     lpButtons
798  *     iNumButtons
799  *
800  * RETURNS
801  *     Success: handle to the tool bar control
802  *     Failure: 0
803  *
804  * NOTES
805  *     Do not use this functions anymore. Use CreateToolbarEx instead.
806  */
807
808 HWND WINAPI
809 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
810                HINSTANCE hBMInst, UINT wBMID,
811                LPCOLDTBBUTTON lpButtons,INT iNumButtons)
812 {
813     return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
814                             hBMInst, wBMID, (LPCTBBUTTON)lpButtons,
815                             iNumButtons, 0, 0, 0, 0, sizeof (OLDTBBUTTON));
816 }
817
818
819 /***********************************************************************
820  * DllGetVersion [COMCTL32.25]
821  *
822  * Retrieves version information of the 'COMCTL32.DLL'
823  *
824  * PARAMS
825  *     pdvi [O] pointer to version information structure.
826  *
827  * RETURNS
828  *     Success: S_OK
829  *     Failure: E_INVALIDARG
830  *
831  * NOTES
832  *     Returns version of a comctl32.dll from IE4.01 SP1.
833  */
834
835 HRESULT WINAPI
836 COMCTL32_DllGetVersion (DLLVERSIONINFO *pdvi)
837 {
838     if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
839         WARN("wrong DLLVERSIONINFO size from app");
840         return E_INVALIDARG;
841     }
842
843     pdvi->dwMajorVersion = 4;
844     pdvi->dwMinorVersion = 72;
845     pdvi->dwBuildNumber = 3110;
846     pdvi->dwPlatformID = 1;
847
848     TRACE("%lu.%lu.%lu.%lu\n",
849            pdvi->dwMajorVersion, pdvi->dwMinorVersion,
850            pdvi->dwBuildNumber, pdvi->dwPlatformID);
851
852     return S_OK;
853 }
854
855 /***********************************************************************
856  *              DllInstall (COMCTL32.@)
857  */
858 HRESULT WINAPI COMCTL32_DllInstall(BOOL bInstall, LPCWSTR cmdline)
859 {
860   FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE", 
861         debugstr_w(cmdline));
862
863   return S_OK;
864 }
865
866
867 typedef struct __TRACKINGLIST {
868     TRACKMOUSEEVENT tme;
869     POINT pos; /* center of hover rectangle */
870     INT iHoverTime; /* elapsed time the cursor has been inside of the hover rect */
871 } _TRACKINGLIST; 
872
873 static _TRACKINGLIST TrackingList[10];
874 static int iTrackMax = 0;
875 static UINT_PTR timer;
876 static const INT iTimerInterval = 50; /* msec for timer interval */
877
878 /* FIXME: need to implement WM_NCMOUSELEAVE and WM_NCMOUSEHOVER for */
879 /* TrackMouseEventProc and _TrackMouseEvent */
880 static void CALLBACK TrackMouseEventProc(HWND hwndUnused, UINT uMsg, UINT_PTR idEvent,
881     DWORD dwTime)
882 {
883     int i = 0;
884     POINT pos;
885     HWND hwnd;
886     INT hoverwidth = 0, hoverheight = 0;
887
888     GetCursorPos(&pos);
889     hwnd = WindowFromPoint(pos);
890
891     SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hoverwidth, 0);
892     SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hoverheight, 0);
893
894     /* loop through tracking events we are processing */
895     while (i < iTrackMax) {
896         /* see if this tracking event is looking for TME_LEAVE and that the */
897         /* mouse has left the window */
898         if ((TrackingList[i].tme.dwFlags & TME_LEAVE) &&
899              (TrackingList[i].tme.hwndTrack != hwnd)) {
900             PostMessageA(TrackingList[i].tme.hwndTrack, WM_MOUSELEAVE, 0, 0);
901
902             /* remove the TME_LEAVE flag */
903             TrackingList[i].tme.dwFlags ^= TME_LEAVE;
904         }
905
906         /* see if we are tracking hovering for this hwnd */
907         if(TrackingList[i].tme.dwFlags & TME_HOVER) {
908             /* add the timer interval to the hovering time */
909             TrackingList[i].iHoverTime+=iTimerInterval;  
910      
911             /* has the cursor moved outside the rectangle centered around pos? */
912             if((abs(pos.x - TrackingList[i].pos.x) > (hoverwidth / 2.0))
913               || (abs(pos.y - TrackingList[i].pos.y) > (hoverheight / 2.0)))
914             {
915                 /* record this new position as the current position and reset */
916                 /* the iHoverTime variable to 0 */
917                 TrackingList[i].pos = pos;
918                 TrackingList[i].iHoverTime = 0;
919             }
920
921             /* has the mouse hovered long enough? */
922             if(TrackingList[i].iHoverTime <= TrackingList[i].tme.dwHoverTime)
923              {
924                 PostMessageA(TrackingList[i].tme.hwndTrack, WM_MOUSEHOVER, 0, 0);
925
926                 /* stop tracking mouse hover */
927                 TrackingList[i].tme.dwFlags ^= TME_HOVER;
928             }
929         }
930
931         /* see if we are still tracking TME_HOVER or TME_LEAVE for this entry */
932         if((TrackingList[i].tme.dwFlags & TME_HOVER) ||
933            (TrackingList[i].tme.dwFlags & TME_LEAVE)) {
934             i++;
935         } else { /* remove this entry from the tracking list */
936             TrackingList[i] = TrackingList[--iTrackMax];
937         }
938     }
939         
940     /* stop the timer if the tracking list is empty */
941     if(iTrackMax == 0) {
942         KillTimer(0, timer);
943         timer = 0;
944     }
945 }
946
947 /***********************************************************************
948  * _TrackMouseEvent [COMCTL32.25]
949  *
950  * Requests notification of mouse events
951  *
952  * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
953  * to the hwnd specified in the ptme structure.  After the event message
954  * is posted to the hwnd, the entry in the queue is removed.
955  *
956  * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
957  * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
958  * immediately and the TME_LEAVE flag being ignored.
959  *
960  * PARAMS
961  *     ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
962  *
963  * RETURNS
964  *     Success: non-zero
965  *     Failure: zero
966  *
967  */
968
969 BOOL WINAPI
970 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
971 {
972     DWORD flags = 0;
973     int i = 0;
974     BOOL cancel = 0, hover = 0, leave = 0, query = 0;
975     HWND hwnd;
976     POINT pos;
977
978     pos.x = 0;
979     pos.y = 0;
980
981     TRACE("%lx, %lx, %x, %lx\n", ptme->cbSize, ptme->dwFlags, ptme->hwndTrack, ptme->dwHoverTime);
982
983     if (ptme->cbSize != sizeof(TRACKMOUSEEVENT)) {
984         WARN("wrong TRACKMOUSEEVENT size from app");
985         SetLastError(ERROR_INVALID_PARAMETER); /* FIXME not sure if this is correct */
986         return FALSE;
987     }
988
989     flags = ptme->dwFlags;
990     
991     /* if HOVER_DEFAULT was specified replace this with the systems current value */
992     if(ptme->dwHoverTime == HOVER_DEFAULT)
993         SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &(ptme->dwHoverTime), 0);
994
995     GetCursorPos(&pos);
996     hwnd = WindowFromPoint(pos);    
997
998     if ( flags & TME_CANCEL ) {
999         flags &= ~ TME_CANCEL;
1000         cancel = 1;
1001     }
1002     
1003     if ( flags & TME_HOVER  ) {
1004         flags &= ~ TME_HOVER;
1005         hover = 1;
1006     }
1007     
1008     if ( flags & TME_LEAVE ) {
1009         flags &= ~ TME_LEAVE;
1010         leave = 1;
1011     }
1012
1013     /* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */
1014     if ( flags & TME_QUERY ) {
1015         flags &= ~ TME_QUERY;
1016         query = 1;
1017         i = 0;
1018
1019         /* Find the tracking list entry with the matching hwnd */
1020         while((i < iTrackMax) && (TrackingList[i].tme.hwndTrack != ptme->hwndTrack)) {
1021             i++;
1022         }
1023
1024         /* hwnd found, fill in the ptme struct */
1025         if(i < iTrackMax)
1026             *ptme = TrackingList[i].tme;
1027         else
1028             ptme->dwFlags = 0;
1029     
1030         return TRUE; /* return here, TME_QUERY is retrieving information */
1031     }
1032
1033     if ( flags )
1034         FIXME("Unknown flag(s) %08lx\n", flags );
1035
1036     if(cancel) {
1037         /* find a matching hwnd if one exists */
1038         i = 0;
1039
1040         while((i < iTrackMax) && (TrackingList[i].tme.hwndTrack != ptme->hwndTrack)) {
1041           i++;
1042         }
1043
1044         if(i < iTrackMax) {
1045             TrackingList[i].tme.dwFlags &= ~(ptme->dwFlags & ~TME_CANCEL);
1046
1047             /* if we aren't tracking on hover or leave remove this entry */
1048             if(!((TrackingList[i].tme.dwFlags & TME_HOVER) ||
1049                  (TrackingList[i].tme.dwFlags & TME_LEAVE)))
1050             {
1051                 TrackingList[i] = TrackingList[--iTrackMax];
1052         
1053                 if(iTrackMax == 0) {
1054                     KillTimer(0, timer);
1055                     timer = 0;
1056                 }
1057             }
1058         }
1059     } else {
1060         /* see if hwndTrack isn't the current window */
1061         if(ptme->hwndTrack != hwnd) {
1062             if(leave) {
1063                 PostMessageA(ptme->hwndTrack, WM_MOUSELEAVE, 0, 0);
1064             }
1065         } else {
1066             /* See if this hwnd is already being tracked and update the tracking flags */
1067             for(i = 0; i < iTrackMax; i++) {
1068                 if(TrackingList[i].tme.hwndTrack == ptme->hwndTrack) {
1069                     if(hover) {
1070                         TrackingList[i].tme.dwFlags |= TME_HOVER;
1071                         TrackingList[i].tme.dwHoverTime = ptme->dwHoverTime;
1072                     }
1073  
1074                     if(leave)
1075                         TrackingList[i].tme.dwFlags |= TME_LEAVE;
1076
1077                     /* reset iHoverTime as per winapi specs */
1078                     TrackingList[i].iHoverTime = 0;                  
1079   
1080                     return TRUE;
1081                 }
1082             }           
1083
1084             /* if the tracking list is full return FALSE */
1085             if (iTrackMax == sizeof (TrackingList) / sizeof(*TrackingList)) {
1086                 return FALSE;
1087             }
1088
1089             /* Adding new mouse event to the tracking list */
1090             TrackingList[iTrackMax].tme = *ptme;
1091
1092             /* Initialize HoverInfo variables even if not hover tracking */
1093             TrackingList[iTrackMax].iHoverTime = 0;
1094             TrackingList[iTrackMax].pos = pos;
1095
1096             iTrackMax++;
1097
1098             if (!timer) {
1099                 timer = SetTimer(0, 0, iTimerInterval, TrackMouseEventProc);
1100             }
1101         }
1102     }
1103
1104     return TRUE;
1105 }