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