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