comctl32: Register all the controls in DllMain.
[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  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * NOTES
22  * 
23  * This code was audited for completeness against the documented features
24  * of Comctl32.dll version 6.0 on Oct. 21, 2002, by Christian Neumair.
25  *
26  * Unless otherwise noted, we believe this code to be complete, as per
27  * the specification mentioned above.
28  * If you discover missing features, or bugs, please note them below.
29  *
30  * TODO
31  *   -- implement GetMUILanguage + InitMUILanguage
32  *   -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW
33  *   -- FIXMEs + BUGS (search for them)
34  *
35  * Control Classes
36  *   -- ICC_ANIMATE_CLASS
37  *   -- ICC_BAR_CLASSES
38  *   -- ICC_COOL_CLASSES
39  *   -- ICC_DATE_CLASSES
40  *   -- ICC_HOTKEY_CLASS
41  *   -- ICC_INTERNET_CLASSES
42  *   -- ICC_LINK_CLASS
43  *   -- ICC_LISTVIEW_CLASSES
44  *   -- ICC_NATIVEFNTCTL_CLASS
45  *   -- ICC_PAGESCROLLER_CLASS
46  *   -- ICC_PROGRESS_CLASS
47  *   -- ICC_STANDARD_CLASSES (not yet implemented)
48  *   -- ICC_TAB_CLASSES
49  *   -- ICC_TREEVIEW_CLASSES
50  *   -- ICC_UPDOWN_CLASS
51  *   -- ICC_USEREX_CLASSES
52  *   -- ICC_WIN95_CLASSES
53  */
54
55 #include <stdarg.h>
56 #include <string.h>
57 #include <stdlib.h>
58
59 #include "windef.h"
60 #include "winbase.h"
61 #include "wingdi.h"
62 #include "winuser.h"
63 #include "winnls.h"
64 #include "commctrl.h"
65 #include "winerror.h"
66 #include "winreg.h"
67 #define NO_SHLWAPI_STREAM
68 #include "shlwapi.h"
69 #include "comctl32.h"
70 #include "wine/debug.h"
71
72 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
73
74 LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
75
76 LPWSTR  COMCTL32_wSubclass = NULL;
77 HMODULE COMCTL32_hModule = 0;
78 LANGID  COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
79 HBRUSH  COMCTL32_hPattern55AABrush = NULL;
80 COMCTL32_SysColor  comctl32_color;
81
82 static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
83
84 static const WORD wPattern55AA[] =
85 {
86     0x5555, 0xaaaa, 0x5555, 0xaaaa,
87     0x5555, 0xaaaa, 0x5555, 0xaaaa
88 };
89
90 static const WCHAR strCC32SubclassInfo[] = {
91     'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
92 };
93
94 /***********************************************************************
95  * DllMain [Internal]
96  *
97  * Initializes the internal 'COMCTL32.DLL'.
98  *
99  * PARAMS
100  *     hinstDLL    [I] handle to the 'dlls' instance
101  *     fdwReason   [I]
102  *     lpvReserved [I] reserverd, must be NULL
103  *
104  * RETURNS
105  *     Success: TRUE
106  *     Failure: FALSE
107  */
108
109 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
110 {
111     TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
112
113     switch (fdwReason) {
114         case DLL_PROCESS_ATTACH:
115             DisableThreadLibraryCalls(hinstDLL);
116
117             COMCTL32_hModule = (HMODULE)hinstDLL;
118
119             /* add global subclassing atom (used by 'tooltip' and 'updown') */
120             COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
121             TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
122
123             /* create local pattern brush */
124             COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
125             COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
126
127             /* Get all the colors at DLL load */
128             COMCTL32_RefreshSysColors();
129
130             /* like comctl32 5.82+ register all the common control classes */
131             ANIMATE_Register ();
132             COMBOEX_Register ();
133             DATETIME_Register ();
134             FLATSB_Register ();
135             HEADER_Register ();
136             HOTKEY_Register ();
137             IPADDRESS_Register ();
138             LISTVIEW_Register ();
139             MONTHCAL_Register ();
140             NATIVEFONT_Register ();
141             PAGER_Register ();
142             PROGRESS_Register ();
143             REBAR_Register ();
144             STATUS_Register ();
145             SYSLINK_Register ();
146             TAB_Register ();
147             TOOLBAR_Register ();
148             TOOLTIPS_Register ();
149             TRACKBAR_Register ();
150             TREEVIEW_Register ();
151             UPDOWN_Register ();
152
153             /* subclass user32 controls */
154             THEMING_Initialize ();
155             break;
156
157         case DLL_PROCESS_DETACH:
158             /* clean up subclassing */ 
159             THEMING_Uninitialize();
160
161             /* unregister all common control classes */
162             ANIMATE_Unregister ();
163             COMBOEX_Unregister ();
164             DATETIME_Unregister ();
165             FLATSB_Unregister ();
166             HEADER_Unregister ();
167             HOTKEY_Unregister ();
168             IPADDRESS_Unregister ();
169             LISTVIEW_Unregister ();
170             MONTHCAL_Unregister ();
171             NATIVEFONT_Unregister ();
172             PAGER_Unregister ();
173             PROGRESS_Unregister ();
174             REBAR_Unregister ();
175             STATUS_Unregister ();
176             SYSLINK_Unregister ();
177             TAB_Unregister ();
178             TOOLBAR_Unregister ();
179             TOOLTIPS_Unregister ();
180             TRACKBAR_Unregister ();
181             TREEVIEW_Unregister ();
182             UPDOWN_Unregister ();
183
184             /* delete local pattern brush */
185             DeleteObject (COMCTL32_hPattern55AABrush);
186             COMCTL32_hPattern55AABrush = NULL;
187             DeleteObject (COMCTL32_hPattern55AABitmap);
188             COMCTL32_hPattern55AABitmap = NULL;
189
190             /* delete global subclassing atom */
191             GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
192             TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
193             COMCTL32_wSubclass = NULL;
194             break;
195     }
196
197     return TRUE;
198 }
199
200
201 /***********************************************************************
202  * MenuHelp [COMCTL32.2]
203  *
204  * Handles the setting of status bar help messages when the user
205  * selects menu items.
206  *
207  * PARAMS
208  *     uMsg       [I] message (WM_MENUSELECT) (see NOTES)
209  *     wParam     [I] wParam of the message uMsg
210  *     lParam     [I] lParam of the message uMsg
211  *     hMainMenu  [I] handle to the application's main menu
212  *     hInst      [I] handle to the module that contains string resources
213  *     hwndStatus [I] handle to the status bar window
214  *     lpwIDs     [I] pointer to an array of integers (see NOTES)
215  *
216  * RETURNS
217  *     No return value
218  *
219  * NOTES
220  *     The official documentation is incomplete!
221  *     This is the correct documentation:
222  *
223  *     uMsg:
224  *     MenuHelp() does NOT handle WM_COMMAND messages! It only handles
225  *     WM_MENUSELECT messages.
226  *
227  *     lpwIDs:
228  *     (will be written ...)
229  */
230
231 VOID WINAPI
232 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
233           HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
234 {
235     UINT uMenuID = 0;
236
237     if (!IsWindow (hwndStatus))
238         return;
239
240     switch (uMsg) {
241         case WM_MENUSELECT:
242             TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n",
243                    wParam, lParam);
244
245             if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
246                 /* menu was closed */
247                 TRACE("menu was closed!\n");
248                 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
249             }
250             else {
251                 /* menu item was selected */
252                 if (HIWORD(wParam) & MF_POPUP)
253                     uMenuID = (UINT)*(lpwIDs+1);
254                 else
255                     uMenuID = (UINT)LOWORD(wParam);
256                 TRACE("uMenuID = %u\n", uMenuID);
257
258                 if (uMenuID) {
259                     WCHAR szText[256];
260
261                     if (!LoadStringW (hInst, uMenuID, szText, sizeof(szText)/sizeof(szText[0])))
262                         szText[0] = '\0';
263
264                     SendMessageW (hwndStatus, SB_SETTEXTW,
265                                     255 | SBT_NOBORDERS, (LPARAM)szText);
266                     SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
267                 }
268             }
269             break;
270
271         case WM_COMMAND :
272             TRACE("WM_COMMAND wParam=0x%X lParam=0x%lX\n",
273                    wParam, lParam);
274             /* WM_COMMAND is not invalid since it is documented
275              * in the windows api reference. So don't output
276              * any FIXME for WM_COMMAND
277              */
278             WARN("We don't care about the WM_COMMAND\n");
279             break;
280
281         default:
282             FIXME("Invalid Message 0x%x!\n", uMsg);
283             break;
284     }
285 }
286
287
288 /***********************************************************************
289  * ShowHideMenuCtl [COMCTL32.3]
290  *
291  * Shows or hides controls and updates the corresponding menu item.
292  *
293  * PARAMS
294  *     hwnd   [I] handle to the client window.
295  *     uFlags [I] menu command id.
296  *     lpInfo [I] pointer to an array of integers. (See NOTES.)
297  *
298  * RETURNS
299  *     Success: TRUE
300  *     Failure: FALSE
301  *
302  * NOTES
303  *     The official documentation is incomplete!
304  *     This is the correct documentation:
305  *
306  *     hwnd
307  *     Handle to the window that contains the menu and controls.
308  *
309  *     uFlags
310  *     Identifier of the menu item to receive or lose a check mark.
311  *
312  *     lpInfo
313  *     The array of integers contains pairs of values. BOTH values of
314  *     the first pair must be the handles to the application's main menu.
315  *     Each subsequent pair consists of a menu id and control id.
316  */
317
318 BOOL WINAPI
319 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
320 {
321     LPINT lpMenuId;
322
323     TRACE("%p, %x, %p\n", hwnd, uFlags, lpInfo);
324
325     if (lpInfo == NULL)
326         return FALSE;
327
328     if (!(lpInfo[0]) || !(lpInfo[1]))
329         return FALSE;
330
331     /* search for control */
332     lpMenuId = &lpInfo[2];
333     while (*lpMenuId != uFlags)
334         lpMenuId += 2;
335
336     if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
337         /* uncheck menu item */
338         CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
339
340         /* hide control */
341         lpMenuId++;
342         SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
343                         SWP_HIDEWINDOW);
344     }
345     else {
346         /* check menu item */
347         CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
348
349         /* show control */
350         lpMenuId++;
351         SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
352                         SWP_SHOWWINDOW);
353     }
354
355     return TRUE;
356 }
357
358
359 /***********************************************************************
360  * GetEffectiveClientRect [COMCTL32.4]
361  *
362  * Calculates the coordinates of a rectangle in the client area.
363  *
364  * PARAMS
365  *     hwnd   [I] handle to the client window.
366  *     lpRect [O] pointer to the rectangle of the client window
367  *     lpInfo [I] pointer to an array of integers (see NOTES)
368  *
369  * RETURNS
370  *     No return value.
371  *
372  * NOTES
373  *     The official documentation is incomplete!
374  *     This is the correct documentation:
375  *
376  *     lpInfo
377  *     (will be written ...)
378  */
379
380 VOID WINAPI
381 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo)
382 {
383     RECT rcCtrl;
384     INT  *lpRun;
385     HWND hwndCtrl;
386
387     TRACE("(%p %p %p)\n",
388            hwnd, lpRect, lpInfo);
389
390     GetClientRect (hwnd, lpRect);
391     lpRun = lpInfo;
392
393     do {
394         lpRun += 2;
395         if (*lpRun == 0)
396             return;
397         lpRun++;
398         hwndCtrl = GetDlgItem (hwnd, *lpRun);
399         if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
400             TRACE("control id 0x%x\n", *lpRun);
401             GetWindowRect (hwndCtrl, &rcCtrl);
402             MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
403             SubtractRect (lpRect, lpRect, &rcCtrl);
404         }
405         lpRun++;
406     } while (*lpRun);
407 }
408
409
410 /***********************************************************************
411  * DrawStatusTextW [COMCTL32.@]
412  *
413  * Draws text with borders, like in a status bar.
414  *
415  * PARAMS
416  *     hdc   [I] handle to the window's display context
417  *     lprc  [I] pointer to a rectangle
418  *     text  [I] pointer to the text
419  *     style [I] drawing style
420  *
421  * RETURNS
422  *     No return value.
423  *
424  * NOTES
425  *     The style variable can have one of the following values:
426  *     (will be written ...)
427  */
428
429 void WINAPI DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style)
430 {
431     RECT r = *lprc;
432     UINT border = BDR_SUNKENOUTER;
433
434     if (style & SBT_POPOUT)
435         border = BDR_RAISEDOUTER;
436     else if (style & SBT_NOBORDERS)
437         border = 0;
438
439     DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
440
441     /* now draw text */
442     if (text) {
443         int oldbkmode = SetBkMode (hdc, TRANSPARENT);
444         UINT align = DT_LEFT;
445         if (*text == L'\t') {
446             text++;
447             align = DT_CENTER;
448             if (*text == L'\t') {
449                 text++;
450                 align = DT_RIGHT;
451             }
452         }
453         r.left += 3;
454         if (style & SBT_RTLREADING)
455             FIXME("Unsupported RTL style!\n");
456         DrawTextW (hdc, text, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
457         SetBkMode(hdc, oldbkmode);
458     }
459 }
460
461
462 /***********************************************************************
463  * DrawStatusText  [COMCTL32.@]
464  * DrawStatusTextA [COMCTL32.5]
465  *
466  * Draws text with borders, like in a status bar.
467  *
468  * PARAMS
469  *     hdc   [I] handle to the window's display context
470  *     lprc  [I] pointer to a rectangle
471  *     text  [I] pointer to the text
472  *     style [I] drawing style
473  *
474  * RETURNS
475  *     No return value.
476  */
477
478 void WINAPI DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style)
479 {
480     INT len;
481     LPWSTR textW = NULL;
482
483     if ( text ) {
484         if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
485             if ( (textW = Alloc( len * sizeof(WCHAR) )) )
486                 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
487         }
488     }
489     DrawStatusTextW( hdc, lprc, textW, style );
490     Free( textW );
491 }
492
493
494 /***********************************************************************
495  * CreateStatusWindow  [COMCTL32.@]
496  * CreateStatusWindowA [COMCTL32.6]
497  *
498  * Creates a status bar
499  *
500  * PARAMS
501  *     style  [I] window style
502  *     text   [I] pointer to the window text
503  *     parent [I] handle to the parent window
504  *     wid    [I] control id of the status bar
505  *
506  * RETURNS
507  *     Success: handle to the status window
508  *     Failure: 0
509  */
510
511 HWND WINAPI
512 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
513 {
514     return CreateWindowA(STATUSCLASSNAMEA, text, style,
515                            CW_USEDEFAULT, CW_USEDEFAULT,
516                            CW_USEDEFAULT, CW_USEDEFAULT,
517                            parent, (HMENU)(DWORD_PTR)wid, 0, 0);
518 }
519
520
521 /***********************************************************************
522  * CreateStatusWindowW [COMCTL32.@]
523  *
524  * Creates a status bar control
525  *
526  * PARAMS
527  *     style  [I] window style
528  *     text   [I] pointer to the window text
529  *     parent [I] handle to the parent window
530  *     wid    [I] control id of the status bar
531  *
532  * RETURNS
533  *     Success: handle to the status window
534  *     Failure: 0
535  */
536
537 HWND WINAPI
538 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
539 {
540     return CreateWindowW(STATUSCLASSNAMEW, text, style,
541                            CW_USEDEFAULT, CW_USEDEFAULT,
542                            CW_USEDEFAULT, CW_USEDEFAULT,
543                            parent, (HMENU)(DWORD_PTR)wid, 0, 0);
544 }
545
546
547 /***********************************************************************
548  * CreateUpDownControl [COMCTL32.16]
549  *
550  * Creates an up-down control
551  *
552  * PARAMS
553  *     style  [I] window styles
554  *     x      [I] horizontal position of the control
555  *     y      [I] vertical position of the control
556  *     cx     [I] with of the control
557  *     cy     [I] height of the control
558  *     parent [I] handle to the parent window
559  *     id     [I] the control's identifier
560  *     inst   [I] handle to the application's module instance
561  *     buddy  [I] handle to the buddy window, can be NULL
562  *     maxVal [I] upper limit of the control
563  *     minVal [I] lower limit of the control
564  *     curVal [I] current value of the control
565  *
566  * RETURNS
567  *     Success: handle to the updown control
568  *     Failure: 0
569  */
570
571 HWND WINAPI
572 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
573                      HWND parent, INT id, HINSTANCE inst,
574                      HWND buddy, INT maxVal, INT minVal, INT curVal)
575 {
576     HWND hUD =
577         CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
578                          parent, (HMENU)(DWORD_PTR)id, inst, 0);
579     if (hUD) {
580         SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
581         SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
582         SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
583     }
584
585     return hUD;
586 }
587
588
589 /***********************************************************************
590  * InitCommonControls [COMCTL32.17]
591  *
592  * Registers the common controls.
593  *
594  * PARAMS
595  *     No parameters.
596  *
597  * RETURNS
598  *     No return values.
599  *
600  * NOTES
601  *     This function is just a dummy - all the controls are registered at
602  *     the DLL's initialization. See InitCommonContolsEx for details.
603  */
604
605 VOID WINAPI
606 InitCommonControls (void)
607 {
608 }
609
610
611 /***********************************************************************
612  * InitCommonControlsEx [COMCTL32.@]
613  *
614  * Registers the common controls.
615  *
616  * PARAMS
617  *     lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
618  *
619  * RETURNS
620  *     Success: TRUE
621  *     Failure: FALSE
622  *
623  * NOTES
624  *     Probaly all versions of comctl32 initializes the Win95 controls in DllMain
625  *     during DLL initializaiton. Starting from comctl32 v5.82 all the controls
626  *     are initialized there. We follow this behaviour and this function is just
627  *     a dummy.
628  *
629  *     Note: when writing programs under Windows, if you don't call any function
630  *     from comctl32 the linker may not link this DLL. If InitCommonControlsEx
631  *     was the only comctl32 function you were calling and you remove it you may
632  *     have a false impression that InitCommonControlsEx actually did something.
633  */
634
635 BOOL WINAPI
636 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
637 {
638     if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
639         return FALSE;
640
641     TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
642     return TRUE;
643 }
644
645
646 /***********************************************************************
647  * CreateToolbarEx [COMCTL32.@]
648  *
649  * Creates a toolbar window.
650  *
651  * PARAMS
652  *     hwnd
653  *     style
654  *     wID
655  *     nBitmaps
656  *     hBMInst
657  *     wBMID
658  *     lpButtons
659  *     iNumButtons
660  *     dxButton
661  *     dyButton
662  *     dxBitmap
663  *     dyBitmap
664  *     uStructSize
665  *
666  * RETURNS
667  *     Success: handle to the tool bar control
668  *     Failure: 0
669  */
670
671 HWND WINAPI
672 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
673                  HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons,
674                  INT iNumButtons, INT dxButton, INT dyButton,
675                  INT dxBitmap, INT dyBitmap, UINT uStructSize)
676 {
677     HWND hwndTB;
678
679     hwndTB =
680         CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
681                         hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
682     if(hwndTB) {
683         TBADDBITMAP tbab;
684
685         SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM)uStructSize, 0);
686
687        /* set bitmap and button size */
688        /*If CreateToolbarEx receives 0, windows sets default values*/
689        if (dxBitmap <= 0)
690            dxBitmap = 16;
691        if (dyBitmap <= 0)
692            dyBitmap = 15;
693        SendMessageW (hwndTB, TB_SETBITMAPSIZE, 0,
694                      MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap));
695
696        if (dxButton <= 0)
697            dxButton = 24;
698        if (dyButton <= 0)
699            dyButton = 22;
700        SendMessageW (hwndTB, TB_SETBUTTONSIZE, 0,
701                      MAKELPARAM((WORD)dxButton, (WORD)dyButton));
702
703
704         /* add bitmaps */
705         if (nBitmaps > 0)
706         {
707             tbab.hInst = hBMInst;
708             tbab.nID   = wBMID;
709
710             SendMessageW (hwndTB, TB_ADDBITMAP, (WPARAM)nBitmaps, (LPARAM)&tbab);
711         }
712         /* add buttons */
713         if(iNumButtons > 0)
714         SendMessageW (hwndTB, TB_ADDBUTTONSW,
715                         (WPARAM)iNumButtons, (LPARAM)lpButtons);
716     }
717
718     return hwndTB;
719 }
720
721
722 /***********************************************************************
723  * CreateMappedBitmap [COMCTL32.8]
724  *
725  * Loads a bitmap resource using a colour map.
726  *
727  * PARAMS
728  *     hInstance  [I] Handle to the module containing the bitmap.
729  *     idBitmap   [I] The bitmap resource ID.
730  *     wFlags     [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
731  *     lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
732  *     iNumMaps   [I] Number of COLORMAP's pointed to by lpColorMap.
733  *
734  * RETURNS
735  *     Success: handle to the new bitmap
736  *     Failure: 0
737  */
738
739 HBITMAP WINAPI
740 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
741                     LPCOLORMAP lpColorMap, INT iNumMaps)
742 {
743     HGLOBAL hglb;
744     HRSRC hRsrc;
745     LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
746     UINT nSize, nColorTableSize, iColor;
747     RGBQUAD *pColorTable;
748     INT i, iMaps, nWidth, nHeight;
749     HDC hdcScreen;
750     HBITMAP hbm;
751     LPCOLORMAP sysColorMap;
752     COLORREF cRef;
753     COLORMAP internalColorMap[4] =
754         {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
755
756     /* initialize pointer to colortable and default color table */
757     if (lpColorMap) {
758         iMaps = iNumMaps;
759         sysColorMap = lpColorMap;
760     }
761     else {
762         internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
763         internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
764         internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
765         internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
766         iMaps = 4;
767         sysColorMap = (LPCOLORMAP)internalColorMap;
768     }
769
770     hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
771     if (hRsrc == 0)
772         return 0;
773     hglb = LoadResource (hInstance, hRsrc);
774     if (hglb == 0)
775         return 0;
776     lpBitmap = (LPBITMAPINFOHEADER)LockResource (hglb);
777     if (lpBitmap == NULL)
778         return 0;
779
780     if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
781         nColorTableSize = lpBitmap->biClrUsed;
782     else if (lpBitmap->biBitCount <= 8) 
783         nColorTableSize = (1 << lpBitmap->biBitCount);
784     else
785         nColorTableSize = 0;
786     nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
787     lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize);
788     if (lpBitmapInfo == NULL)
789         return 0;
790     RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
791
792     pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)lpBitmapInfo->biSize);
793
794     for (iColor = 0; iColor < nColorTableSize; iColor++) {
795         for (i = 0; i < iMaps; i++) {
796             cRef = RGB(pColorTable[iColor].rgbRed,
797                        pColorTable[iColor].rgbGreen,
798                        pColorTable[iColor].rgbBlue);
799             if ( cRef  == sysColorMap[i].from) {
800 #if 0
801                 if (wFlags & CBS_MASKED) {
802                     if (sysColorMap[i].to != COLOR_BTNTEXT)
803                         pColorTable[iColor] = RGB(255, 255, 255);
804                 }
805                 else
806 #endif
807                     pColorTable[iColor].rgbBlue  = GetBValue(sysColorMap[i].to);
808                     pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
809                     pColorTable[iColor].rgbRed   = GetRValue(sysColorMap[i].to);
810                 break;
811             }
812         }
813     }
814     nWidth  = (INT)lpBitmapInfo->biWidth;
815     nHeight = (INT)lpBitmapInfo->biHeight;
816     hdcScreen = GetDC (NULL);
817     hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
818     if (hbm) {
819         HDC hdcDst = CreateCompatibleDC (hdcScreen);
820         HBITMAP hbmOld = SelectObject (hdcDst, hbm);
821         LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
822         lpBits += nColorTableSize * sizeof(RGBQUAD);
823         StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
824                          lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
825                          SRCCOPY);
826         SelectObject (hdcDst, hbmOld);
827         DeleteDC (hdcDst);
828     }
829     ReleaseDC (NULL, hdcScreen);
830     GlobalFree ((HGLOBAL)lpBitmapInfo);
831     FreeResource (hglb);
832
833     return hbm;
834 }
835
836
837 /***********************************************************************
838  * CreateToolbar [COMCTL32.7]
839  *
840  * Creates a toolbar control.
841  *
842  * PARAMS
843  *     hwnd
844  *     style
845  *     wID
846  *     nBitmaps
847  *     hBMInst
848  *     wBMID
849  *     lpButtons
850  *     iNumButtons
851  *
852  * RETURNS
853  *     Success: handle to the tool bar control
854  *     Failure: 0
855  *
856  * NOTES
857  *     Do not use this functions anymore. Use CreateToolbarEx instead.
858  */
859
860 HWND WINAPI
861 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
862                HINSTANCE hBMInst, UINT wBMID,
863                LPCTBBUTTON lpButtons,INT iNumButtons)
864 {
865     return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
866                             hBMInst, wBMID, lpButtons,
867                             iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
868 }
869
870
871 /***********************************************************************
872  * DllGetVersion [COMCTL32.@]
873  *
874  * Retrieves version information of the 'COMCTL32.DLL'
875  *
876  * PARAMS
877  *     pdvi [O] pointer to version information structure.
878  *
879  * RETURNS
880  *     Success: S_OK
881  *     Failure: E_INVALIDARG
882  *
883  * NOTES
884  *     Returns version of a comctl32.dll from IE4.01 SP1.
885  */
886
887 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
888 {
889     if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
890         WARN("wrong DLLVERSIONINFO size from app\n");
891         return E_INVALIDARG;
892     }
893
894     pdvi->dwMajorVersion = COMCTL32_VERSION;
895     pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
896     pdvi->dwBuildNumber = 2919;
897     pdvi->dwPlatformID = 6304;
898
899     TRACE("%u.%u.%u.%u\n",
900            pdvi->dwMajorVersion, pdvi->dwMinorVersion,
901            pdvi->dwBuildNumber, pdvi->dwPlatformID);
902
903     return S_OK;
904 }
905
906 /***********************************************************************
907  *              DllInstall (COMCTL32.@)
908  *
909  * Installs the ComCtl32 DLL.
910  *
911  * RETURNS
912  *     Success: S_OK
913  *     Failure: A HRESULT error
914  */
915 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
916 {
917   FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
918         debugstr_w(cmdline));
919
920   return S_OK;
921 }
922
923 /***********************************************************************
924  * _TrackMouseEvent [COMCTL32.@]
925  *
926  * Requests notification of mouse events
927  *
928  * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
929  * to the hwnd specified in the ptme structure.  After the event message
930  * is posted to the hwnd, the entry in the queue is removed.
931  *
932  * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
933  * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
934  * immediately and the TME_LEAVE flag being ignored.
935  *
936  * PARAMS
937  *     ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
938  *
939  * RETURNS
940  *     Success: non-zero
941  *     Failure: zero
942  *
943  * IMPLEMENTATION moved to USER32.TrackMouseEvent
944  *
945  */
946
947 BOOL WINAPI
948 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
949 {
950     return TrackMouseEvent (ptme);
951 }
952
953 /*************************************************************************
954  * GetMUILanguage [COMCTL32.@]
955  *
956  * Returns the user interface language in use by the current process.
957  *
958  * RETURNS
959  *      Language ID in use by the current process.
960  */
961 LANGID WINAPI GetMUILanguage (VOID)
962 {
963     return COMCTL32_uiLang;
964 }
965
966
967 /*************************************************************************
968  * InitMUILanguage [COMCTL32.@]
969  *
970  * Sets the user interface language to be used by the current process.
971  *
972  * RETURNS
973  *      Nothing.
974  */
975 VOID WINAPI InitMUILanguage (LANGID uiLang)
976 {
977    COMCTL32_uiLang = uiLang;
978 }
979
980
981 /***********************************************************************
982  * SetWindowSubclass [COMCTL32.410]
983  *
984  * Starts a window subclass
985  *
986  * PARAMS
987  *     hWnd [in] handle to window subclass.
988  *     pfnSubclass [in] Pointer to new window procedure.
989  *     uIDSubclass [in] Unique identifier of sublass together with pfnSubclass.
990  *     dwRef [in] Reference data to pass to window procedure.
991  *
992  * RETURNS
993  *     Success: non-zero
994  *     Failure: zero
995  *
996  * BUGS
997  *     If an application manually subclasses a window after subclassing it with
998  *     this API and then with this API again, then none of the previous 
999  *     subclasses get called or the origional window procedure.
1000  */
1001
1002 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1003                         UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1004 {
1005    LPSUBCLASS_INFO stack;
1006    LPSUBCLASSPROCS proc;
1007
1008    TRACE ("(%p, %p, %x, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1009
1010    /* Since the window procedure that we set here has two additional arguments,
1011     * we can't simply set it as the new window procedure of the window. So we
1012     * set our own window procedure and then calculate the other two arguments
1013     * from there. */
1014
1015    /* See if we have been called for this window */
1016    stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1017    if (!stack) {
1018       /* allocate stack */
1019       stack = Alloc (sizeof(SUBCLASS_INFO));
1020       if (!stack) {
1021          ERR ("Failed to allocate our Subclassing stack\n");
1022          return FALSE;
1023       }
1024       SetPropW (hWnd, COMCTL32_wSubclass, (HANDLE)stack);
1025
1026       /* set window procedure to our own and save the current one */
1027       if (IsWindowUnicode (hWnd))
1028          stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1029                                                    (DWORD_PTR)COMCTL32_SubclassProc);
1030       else
1031          stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1032                                                    (DWORD_PTR)COMCTL32_SubclassProc);
1033    }
1034    else {
1035       /* Check to see if we have called this function with the same uIDSubClass
1036        * and pfnSubclass */
1037       proc = stack->SubclassProcs;
1038       while (proc) {
1039          if ((proc->id == uIDSubclass) &&
1040             (proc->subproc == pfnSubclass)) {
1041             proc->ref = dwRef;
1042             return TRUE;
1043          }
1044          proc = proc->next;
1045       }
1046    }
1047    
1048    proc = Alloc(sizeof(SUBCLASSPROCS));
1049    if (!proc) {
1050       ERR ("Failed to allocate subclass entry in stack\n");
1051       if (IsWindowUnicode (hWnd))
1052          SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1053       else
1054          SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1055       Free (stack);
1056       RemovePropW( hWnd, COMCTL32_wSubclass );
1057       return FALSE;
1058    }
1059    
1060    proc->subproc = pfnSubclass;
1061    proc->ref = dwRef;
1062    proc->id = uIDSubclass;
1063    proc->next = stack->SubclassProcs;
1064    stack->SubclassProcs = proc;
1065
1066    return TRUE;
1067 }
1068
1069
1070 /***********************************************************************
1071  * GetWindowSubclass [COMCTL32.411]
1072  *
1073  * Gets the Reference data from a subclass.
1074  *
1075  * PARAMS
1076  *     hWnd [in] Handle to window which were subclassing
1077  *     pfnSubclass [in] Pointer to the subclass procedure
1078  *     uID [in] Unique indentifier of the subclassing procedure
1079  *     pdwRef [out] Pointer to the reference data
1080  *
1081  * RETURNS
1082  *     Success: Non-zero
1083  *     Failure: 0
1084  */
1085
1086 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1087                               UINT_PTR uID, DWORD_PTR *pdwRef)
1088 {
1089    LPSUBCLASS_INFO stack;
1090    LPSUBCLASSPROCS proc;
1091
1092    TRACE ("(%p, %p, %x, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1093
1094    /* See if we have been called for this window */
1095    stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1096    if (!stack)
1097       return FALSE;
1098
1099    proc = stack->SubclassProcs;
1100    while (proc) {
1101       if ((proc->id == uID) &&
1102          (proc->subproc == pfnSubclass)) {
1103          *pdwRef = proc->ref;
1104          return TRUE;
1105       }
1106       proc = proc->next;
1107    }
1108
1109    return FALSE;
1110 }
1111
1112
1113 /***********************************************************************
1114  * RemoveWindowSubclass [COMCTL32.412]
1115  *
1116  * Removes a window subclass.
1117  *
1118  * PARAMS
1119  *     hWnd [in] Handle to the window were subclassing
1120  *     pfnSubclass [in] Pointer to the subclass procedure
1121  *     uID [in] Unique identifier of this subclass
1122  *
1123  * RETURNS
1124  *     Success: non-zero
1125  *     Failure: zero
1126  */
1127
1128 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1129 {
1130    LPSUBCLASS_INFO stack;
1131    LPSUBCLASSPROCS prevproc = NULL;
1132    LPSUBCLASSPROCS proc;
1133    BOOL ret = FALSE;
1134
1135    TRACE ("(%p, %p, %x)\n", hWnd, pfnSubclass, uID);
1136
1137    /* Find the Subclass to remove */
1138    stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1139    if (!stack)
1140       return FALSE;
1141
1142    proc = stack->SubclassProcs;
1143    while (proc) {
1144       if ((proc->id == uID) &&
1145          (proc->subproc == pfnSubclass)) {
1146          
1147          if (!prevproc)
1148             stack->SubclassProcs = proc->next;
1149          else
1150             prevproc->next = proc->next;
1151           
1152          if (stack->stackpos == proc)
1153             stack->stackpos = stack->stackpos->next;
1154             
1155          Free (proc);
1156          ret = TRUE;
1157          break;
1158       }
1159       prevproc = proc;
1160       proc = proc->next;
1161    }
1162    
1163    if (!stack->SubclassProcs && !stack->running) {
1164       TRACE("Last Subclass removed, cleaning up\n");
1165       /* clean up our heap and reset the origional window procedure */
1166       if (IsWindowUnicode (hWnd))
1167          SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1168       else
1169          SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1170       Free (stack);
1171       RemovePropW( hWnd, COMCTL32_wSubclass );
1172    }
1173    
1174    return ret;
1175 }
1176
1177 /***********************************************************************
1178  * COMCTL32_SubclassProc (internal)
1179  *
1180  * Window procedure for all subclassed windows. 
1181  * Saves the current subclassing stack position to support nested messages
1182  */
1183 LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1184 {
1185    LPSUBCLASS_INFO stack;
1186    LPSUBCLASSPROCS proc;
1187    LRESULT ret;
1188     
1189    TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1190
1191    stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1192    if (!stack) {
1193       ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1194       return 0;
1195    }
1196     
1197    /* Save our old stackpos to properly handle nested messages */
1198    proc = stack->stackpos;
1199    stack->stackpos = stack->SubclassProcs;
1200    stack->running++;
1201    ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1202    stack->running--;
1203    stack->stackpos = proc;
1204     
1205    if (!stack->SubclassProcs && !stack->running) {
1206       TRACE("Last Subclass removed, cleaning up\n");
1207       /* clean up our heap and reset the origional window procedure */
1208       if (IsWindowUnicode (hWnd))
1209          SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1210       else
1211          SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1212       Free (stack);
1213       RemovePropW( hWnd, COMCTL32_wSubclass );
1214    }
1215    return ret;
1216 }
1217
1218 /***********************************************************************
1219  * DefSubclassProc [COMCTL32.413]
1220  *
1221  * Calls the next window procedure (ie. the one before this subclass)
1222  *
1223  * PARAMS
1224  *     hWnd [in] The window that we're subclassing
1225  *     uMsg [in] Message
1226  *     wParam [in] WPARAM
1227  *     lParam [in] LPARAM
1228  *
1229  * RETURNS
1230  *     Success: non-zero
1231  *     Failure: zero
1232  */
1233
1234 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1235 {
1236    LPSUBCLASS_INFO stack;
1237    LRESULT ret;
1238    
1239    TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1240
1241    /* retrieve our little stack from the Properties */
1242    stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1243    if (!stack) {
1244       ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1245       return 0;
1246    }
1247
1248    /* If we are at the end of stack then we have to call the original
1249     * window procedure */
1250    if (!stack->stackpos) {
1251       if (IsWindowUnicode (hWnd))
1252          ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1253       else
1254          ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1255    } else {
1256       LPSUBCLASSPROCS proc = stack->stackpos;
1257       stack->stackpos = stack->stackpos->next; 
1258       /* call the Subclass procedure from the stack */
1259       ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1260             proc->id, proc->ref);
1261    }
1262
1263    return ret;
1264 }
1265
1266
1267 /***********************************************************************
1268  * COMCTL32_CreateToolTip [NOT AN API]
1269  *
1270  * Creates a tooltip for the control specified in hwnd and does all
1271  * necessary setup and notifications.
1272  *
1273  * PARAMS
1274  *     hwndOwner [I] Handle to the window that will own the tool tip.
1275  *
1276  * RETURNS
1277  *     Success: Handle of tool tip window.
1278  *     Failure: NULL
1279  */
1280
1281 HWND
1282 COMCTL32_CreateToolTip(HWND hwndOwner)
1283 {
1284     HWND hwndToolTip;
1285
1286     hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1287                                   CW_USEDEFAULT, CW_USEDEFAULT,
1288                                   CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1289                                   0, 0, 0);
1290
1291     /* Send NM_TOOLTIPSCREATED notification */
1292     if (hwndToolTip)
1293     {
1294         NMTOOLTIPSCREATED nmttc;
1295         /* true owner can be different if hwndOwner is a child window */
1296         HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1297         nmttc.hdr.hwndFrom = hwndTrueOwner;
1298         nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1299         nmttc.hdr.code = NM_TOOLTIPSCREATED;
1300         nmttc.hwndToolTips = hwndToolTip;
1301
1302        SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1303                     (WPARAM)GetWindowLongPtrW(hwndTrueOwner, GWLP_ID),
1304                     (LPARAM)&nmttc);
1305     }
1306
1307     return hwndToolTip;
1308 }
1309
1310
1311 /***********************************************************************
1312  * COMCTL32_RefreshSysColors [NOT AN API]
1313  *
1314  * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1315  * refresh the color values in the color structure
1316  *
1317  * PARAMS
1318  *     none
1319  *
1320  * RETURNS
1321  *     none
1322  */
1323
1324 VOID
1325 COMCTL32_RefreshSysColors(void)
1326 {
1327     comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1328     comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1329     comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1330     comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1331     comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1332     comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1333     comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1334     comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1335     comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1336     comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1337     comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1338     comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1339     comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1340     comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1341     comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1342     comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1343 }
1344
1345 /***********************************************************************
1346  * COMCTL32_DrawInsertMark [NOT AN API]
1347  *
1348  * Draws an insertion mark (which looks similar to an 'I').
1349  *
1350  * PARAMS
1351  *     hDC           [I] Device context to draw onto.
1352  *     lpRect        [I] Co-ordinates of insertion mark.
1353  *     clrInsertMark [I] Colour of the insertion mark.
1354  *     bHorizontal   [I] True if insert mark should be drawn horizontally,
1355  *                       vertical otherwise.
1356  *
1357  * RETURNS
1358  *     none
1359  *
1360  * NOTES
1361  *     Draws up to but not including the bottom co-ordinate when drawing
1362  *     vertically or the right co-ordinate when horizontal.
1363  */
1364 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1365 {
1366     HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1367     HPEN hOldPen;
1368     static const DWORD adwPolyPoints[] = {4,4,4};
1369     LONG lCentre = (bHorizontal ? 
1370         lpRect->top + (lpRect->bottom - lpRect->top)/2 : 
1371         lpRect->left + (lpRect->right - lpRect->left)/2);
1372     LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1373     LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1374     const POINT aptInsertMark[] =
1375     {
1376         /* top (V) or left (H) arrow */
1377         {lCentre    , l1 + 2},
1378         {lCentre - 2, l1    },
1379         {lCentre + 3, l1    },
1380         {lCentre + 1, l1 + 2},
1381         /* middle line */
1382         {lCentre    , l2 - 2},
1383         {lCentre    , l1 - 1},
1384         {lCentre + 1, l1 - 1},
1385         {lCentre + 1, l2 - 2},
1386         /* bottom (V) or right (H) arrow */
1387         {lCentre    , l2 - 3},
1388         {lCentre - 2, l2 - 1},
1389         {lCentre + 3, l2 - 1},
1390         {lCentre + 1, l2 - 3},
1391     };
1392     hOldPen = SelectObject(hDC, hPen);
1393     PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0]));
1394     SelectObject(hDC, hOldPen);
1395     DeleteObject(hPen);
1396 }
1397
1398 /***********************************************************************
1399  * COMCTL32_EnsureBitmapSize [internal]
1400  *
1401  * If needed enlarge the bitmap so that the width is at least cxMinWidth
1402  * the height is at least cyMinHeight. If the bitmap already have these
1403  * dimensions nothing changes.
1404  *
1405  * PARAMS
1406  *     hBitmap       [I/O] Bitmap to modify. The handle may change
1407  *     cxMinWidth    [I]   If the width of the bitmap is smaller then it will
1408  *                         be enlarged to this value
1409  *     cyMinHeight   [I]   If the height of the bitmap is smaller then it will
1410  *                         be enlarged to this value
1411  *     cyBackground  [I]   The color with which the new area will be filled
1412  *
1413  * RETURNS
1414  *     none
1415  */
1416 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1417 {
1418     int cxNew, cyNew;
1419     BITMAP bmp;
1420     HBITMAP hNewBitmap;
1421     HBITMAP hNewDCBitmap, hOldDCBitmap;
1422     HBRUSH hNewDCBrush;
1423     HDC hdcNew, hdcOld;
1424
1425     if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1426         return;
1427     cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1428     cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1429     if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1430         return;
1431
1432     hdcNew = CreateCompatibleDC(NULL);
1433     hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1434     hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1435     hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1436
1437     hdcOld = CreateCompatibleDC(NULL);
1438     hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1439
1440     BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1441     if (bmp.bmWidth < cxMinWidth)
1442         PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1443     if (bmp.bmHeight < cyMinHeight)
1444         PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1445     if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1446         PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1447
1448     SelectObject(hdcNew, hNewDCBitmap);
1449     DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1450     DeleteDC(hdcNew);
1451     SelectObject(hdcOld, hOldDCBitmap);
1452     DeleteDC(hdcOld);
1453
1454     DeleteObject(*pBitmap);    
1455     *pBitmap = hNewBitmap;
1456     return;
1457 }
1458
1459 /***********************************************************************
1460  * MirrorIcon [COMCTL32.414]
1461  *
1462  * Mirrors an icon so that it will appear correctly on a mirrored DC.
1463  *
1464  * PARAMS
1465  *     phicon1 [I/O] Icon.
1466  *     phicon2 [I/O] Icon.
1467  *
1468  * RETURNS
1469  *     Success: TRUE.
1470  *     Failure: FALSE.
1471  */
1472 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1473 {
1474     FIXME("(%p, %p): stub\n", phicon1, phicon2);
1475     return FALSE;
1476 }
1477
1478 static inline int IsDelimiter(WCHAR c)
1479 {
1480     switch(c)
1481     {
1482         case '/':
1483         case '\\':
1484         case '.':
1485         case ' ':
1486             return TRUE;
1487     }
1488     return FALSE;
1489 }
1490
1491 static int CALLBACK PathWordBreakProc(LPWSTR lpch, int ichCurrent, int cch, int code)
1492 {
1493     if (code == WB_ISDELIMITER)
1494         return IsDelimiter(lpch[ichCurrent]);
1495     else
1496     {
1497         int dir = (code == WB_LEFT) ? -1 : 1;
1498         for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1499             if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1500     }
1501     return ichCurrent;
1502 }
1503
1504 /***********************************************************************
1505  * SetPathWordBreakProc [COMCTL32.384]
1506  *
1507  * Sets the word break procedure for an edit control to one that understands
1508  * paths so that the user can jump over directories.
1509  *
1510  * PARAMS
1511  *     hwnd [I] Handle to edit control.
1512  *     bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1513  *
1514  * RETURNS
1515  *     Result from EM_SETWORDBREAKPROC message.
1516  */
1517 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1518 {
1519     return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1520         (LPARAM)(bSet ? PathWordBreakProc : NULL));
1521 }