shell32: Replace inline static with static inline.
[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 = dxBitmap;
698        if (dyButton < 0)
699            dyButton = dyBitmap;
700        /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
701        if (dxButton != 0 && dyButton != 0)
702             SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
703
704
705         /* add bitmaps */
706         if (nBitmaps > 0)
707         {
708             tbab.hInst = hBMInst;
709             tbab.nID   = wBMID;
710
711             SendMessageW (hwndTB, TB_ADDBITMAP, (WPARAM)nBitmaps, (LPARAM)&tbab);
712         }
713         /* add buttons */
714         if(iNumButtons > 0)
715         SendMessageW (hwndTB, TB_ADDBUTTONSW,
716                         (WPARAM)iNumButtons, (LPARAM)lpButtons);
717     }
718
719     return hwndTB;
720 }
721
722
723 /***********************************************************************
724  * CreateMappedBitmap [COMCTL32.8]
725  *
726  * Loads a bitmap resource using a colour map.
727  *
728  * PARAMS
729  *     hInstance  [I] Handle to the module containing the bitmap.
730  *     idBitmap   [I] The bitmap resource ID.
731  *     wFlags     [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
732  *     lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
733  *     iNumMaps   [I] Number of COLORMAP's pointed to by lpColorMap.
734  *
735  * RETURNS
736  *     Success: handle to the new bitmap
737  *     Failure: 0
738  */
739
740 HBITMAP WINAPI
741 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
742                     LPCOLORMAP lpColorMap, INT iNumMaps)
743 {
744     HGLOBAL hglb;
745     HRSRC hRsrc;
746     LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
747     UINT nSize, nColorTableSize, iColor;
748     RGBQUAD *pColorTable;
749     INT i, iMaps, nWidth, nHeight;
750     HDC hdcScreen;
751     HBITMAP hbm;
752     LPCOLORMAP sysColorMap;
753     COLORREF cRef;
754     COLORMAP internalColorMap[4] =
755         {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
756
757     /* initialize pointer to colortable and default color table */
758     if (lpColorMap) {
759         iMaps = iNumMaps;
760         sysColorMap = lpColorMap;
761     }
762     else {
763         internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
764         internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
765         internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
766         internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
767         iMaps = 4;
768         sysColorMap = (LPCOLORMAP)internalColorMap;
769     }
770
771     hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
772     if (hRsrc == 0)
773         return 0;
774     hglb = LoadResource (hInstance, hRsrc);
775     if (hglb == 0)
776         return 0;
777     lpBitmap = (LPBITMAPINFOHEADER)LockResource (hglb);
778     if (lpBitmap == NULL)
779         return 0;
780
781     if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
782         nColorTableSize = lpBitmap->biClrUsed;
783     else if (lpBitmap->biBitCount <= 8) 
784         nColorTableSize = (1 << lpBitmap->biBitCount);
785     else
786         nColorTableSize = 0;
787     nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
788     lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize);
789     if (lpBitmapInfo == NULL)
790         return 0;
791     RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
792
793     pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)lpBitmapInfo->biSize);
794
795     for (iColor = 0; iColor < nColorTableSize; iColor++) {
796         for (i = 0; i < iMaps; i++) {
797             cRef = RGB(pColorTable[iColor].rgbRed,
798                        pColorTable[iColor].rgbGreen,
799                        pColorTable[iColor].rgbBlue);
800             if ( cRef  == sysColorMap[i].from) {
801 #if 0
802                 if (wFlags & CBS_MASKED) {
803                     if (sysColorMap[i].to != COLOR_BTNTEXT)
804                         pColorTable[iColor] = RGB(255, 255, 255);
805                 }
806                 else
807 #endif
808                     pColorTable[iColor].rgbBlue  = GetBValue(sysColorMap[i].to);
809                     pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
810                     pColorTable[iColor].rgbRed   = GetRValue(sysColorMap[i].to);
811                 break;
812             }
813         }
814     }
815     nWidth  = (INT)lpBitmapInfo->biWidth;
816     nHeight = (INT)lpBitmapInfo->biHeight;
817     hdcScreen = GetDC (NULL);
818     hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
819     if (hbm) {
820         HDC hdcDst = CreateCompatibleDC (hdcScreen);
821         HBITMAP hbmOld = SelectObject (hdcDst, hbm);
822         LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
823         lpBits += nColorTableSize * sizeof(RGBQUAD);
824         StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
825                          lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
826                          SRCCOPY);
827         SelectObject (hdcDst, hbmOld);
828         DeleteDC (hdcDst);
829     }
830     ReleaseDC (NULL, hdcScreen);
831     GlobalFree ((HGLOBAL)lpBitmapInfo);
832     FreeResource (hglb);
833
834     return hbm;
835 }
836
837
838 /***********************************************************************
839  * CreateToolbar [COMCTL32.7]
840  *
841  * Creates a toolbar control.
842  *
843  * PARAMS
844  *     hwnd
845  *     style
846  *     wID
847  *     nBitmaps
848  *     hBMInst
849  *     wBMID
850  *     lpButtons
851  *     iNumButtons
852  *
853  * RETURNS
854  *     Success: handle to the tool bar control
855  *     Failure: 0
856  *
857  * NOTES
858  *     Do not use this functions anymore. Use CreateToolbarEx instead.
859  */
860
861 HWND WINAPI
862 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
863                HINSTANCE hBMInst, UINT wBMID,
864                LPCTBBUTTON lpButtons,INT iNumButtons)
865 {
866     return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
867                             hBMInst, wBMID, lpButtons,
868                             iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
869 }
870
871
872 /***********************************************************************
873  * DllGetVersion [COMCTL32.@]
874  *
875  * Retrieves version information of the 'COMCTL32.DLL'
876  *
877  * PARAMS
878  *     pdvi [O] pointer to version information structure.
879  *
880  * RETURNS
881  *     Success: S_OK
882  *     Failure: E_INVALIDARG
883  *
884  * NOTES
885  *     Returns version of a comctl32.dll from IE4.01 SP1.
886  */
887
888 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
889 {
890     if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
891         WARN("wrong DLLVERSIONINFO size from app\n");
892         return E_INVALIDARG;
893     }
894
895     pdvi->dwMajorVersion = COMCTL32_VERSION;
896     pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
897     pdvi->dwBuildNumber = 2919;
898     pdvi->dwPlatformID = 6304;
899
900     TRACE("%u.%u.%u.%u\n",
901            pdvi->dwMajorVersion, pdvi->dwMinorVersion,
902            pdvi->dwBuildNumber, pdvi->dwPlatformID);
903
904     return S_OK;
905 }
906
907 /***********************************************************************
908  *              DllInstall (COMCTL32.@)
909  *
910  * Installs the ComCtl32 DLL.
911  *
912  * RETURNS
913  *     Success: S_OK
914  *     Failure: A HRESULT error
915  */
916 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
917 {
918   FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
919         debugstr_w(cmdline));
920
921   return S_OK;
922 }
923
924 /***********************************************************************
925  * _TrackMouseEvent [COMCTL32.@]
926  *
927  * Requests notification of mouse events
928  *
929  * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
930  * to the hwnd specified in the ptme structure.  After the event message
931  * is posted to the hwnd, the entry in the queue is removed.
932  *
933  * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
934  * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
935  * immediately and the TME_LEAVE flag being ignored.
936  *
937  * PARAMS
938  *     ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
939  *
940  * RETURNS
941  *     Success: non-zero
942  *     Failure: zero
943  *
944  * IMPLEMENTATION moved to USER32.TrackMouseEvent
945  *
946  */
947
948 BOOL WINAPI
949 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
950 {
951     return TrackMouseEvent (ptme);
952 }
953
954 /*************************************************************************
955  * GetMUILanguage [COMCTL32.@]
956  *
957  * Returns the user interface language in use by the current process.
958  *
959  * RETURNS
960  *      Language ID in use by the current process.
961  */
962 LANGID WINAPI GetMUILanguage (VOID)
963 {
964     return COMCTL32_uiLang;
965 }
966
967
968 /*************************************************************************
969  * InitMUILanguage [COMCTL32.@]
970  *
971  * Sets the user interface language to be used by the current process.
972  *
973  * RETURNS
974  *      Nothing.
975  */
976 VOID WINAPI InitMUILanguage (LANGID uiLang)
977 {
978    COMCTL32_uiLang = uiLang;
979 }
980
981
982 /***********************************************************************
983  * SetWindowSubclass [COMCTL32.410]
984  *
985  * Starts a window subclass
986  *
987  * PARAMS
988  *     hWnd [in] handle to window subclass.
989  *     pfnSubclass [in] Pointer to new window procedure.
990  *     uIDSubclass [in] Unique identifier of sublass together with pfnSubclass.
991  *     dwRef [in] Reference data to pass to window procedure.
992  *
993  * RETURNS
994  *     Success: non-zero
995  *     Failure: zero
996  *
997  * BUGS
998  *     If an application manually subclasses a window after subclassing it with
999  *     this API and then with this API again, then none of the previous 
1000  *     subclasses get called or the origional window procedure.
1001  */
1002
1003 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1004                         UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1005 {
1006    LPSUBCLASS_INFO stack;
1007    LPSUBCLASSPROCS proc;
1008
1009    TRACE ("(%p, %p, %x, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1010
1011    /* Since the window procedure that we set here has two additional arguments,
1012     * we can't simply set it as the new window procedure of the window. So we
1013     * set our own window procedure and then calculate the other two arguments
1014     * from there. */
1015
1016    /* See if we have been called for this window */
1017    stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1018    if (!stack) {
1019       /* allocate stack */
1020       stack = Alloc (sizeof(SUBCLASS_INFO));
1021       if (!stack) {
1022          ERR ("Failed to allocate our Subclassing stack\n");
1023          return FALSE;
1024       }
1025       SetPropW (hWnd, COMCTL32_wSubclass, (HANDLE)stack);
1026
1027       /* set window procedure to our own and save the current one */
1028       if (IsWindowUnicode (hWnd))
1029          stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1030                                                    (DWORD_PTR)COMCTL32_SubclassProc);
1031       else
1032          stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1033                                                    (DWORD_PTR)COMCTL32_SubclassProc);
1034    }
1035    else {
1036       /* Check to see if we have called this function with the same uIDSubClass
1037        * and pfnSubclass */
1038       proc = stack->SubclassProcs;
1039       while (proc) {
1040          if ((proc->id == uIDSubclass) &&
1041             (proc->subproc == pfnSubclass)) {
1042             proc->ref = dwRef;
1043             return TRUE;
1044          }
1045          proc = proc->next;
1046       }
1047    }
1048    
1049    proc = Alloc(sizeof(SUBCLASSPROCS));
1050    if (!proc) {
1051       ERR ("Failed to allocate subclass entry in stack\n");
1052       if (IsWindowUnicode (hWnd))
1053          SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1054       else
1055          SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1056       Free (stack);
1057       RemovePropW( hWnd, COMCTL32_wSubclass );
1058       return FALSE;
1059    }
1060    
1061    proc->subproc = pfnSubclass;
1062    proc->ref = dwRef;
1063    proc->id = uIDSubclass;
1064    proc->next = stack->SubclassProcs;
1065    stack->SubclassProcs = proc;
1066
1067    return TRUE;
1068 }
1069
1070
1071 /***********************************************************************
1072  * GetWindowSubclass [COMCTL32.411]
1073  *
1074  * Gets the Reference data from a subclass.
1075  *
1076  * PARAMS
1077  *     hWnd [in] Handle to window which were subclassing
1078  *     pfnSubclass [in] Pointer to the subclass procedure
1079  *     uID [in] Unique indentifier of the subclassing procedure
1080  *     pdwRef [out] Pointer to the reference data
1081  *
1082  * RETURNS
1083  *     Success: Non-zero
1084  *     Failure: 0
1085  */
1086
1087 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1088                               UINT_PTR uID, DWORD_PTR *pdwRef)
1089 {
1090    LPSUBCLASS_INFO stack;
1091    LPSUBCLASSPROCS proc;
1092
1093    TRACE ("(%p, %p, %x, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1094
1095    /* See if we have been called for this window */
1096    stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1097    if (!stack)
1098       return FALSE;
1099
1100    proc = stack->SubclassProcs;
1101    while (proc) {
1102       if ((proc->id == uID) &&
1103          (proc->subproc == pfnSubclass)) {
1104          *pdwRef = proc->ref;
1105          return TRUE;
1106       }
1107       proc = proc->next;
1108    }
1109
1110    return FALSE;
1111 }
1112
1113
1114 /***********************************************************************
1115  * RemoveWindowSubclass [COMCTL32.412]
1116  *
1117  * Removes a window subclass.
1118  *
1119  * PARAMS
1120  *     hWnd [in] Handle to the window were subclassing
1121  *     pfnSubclass [in] Pointer to the subclass procedure
1122  *     uID [in] Unique identifier of this subclass
1123  *
1124  * RETURNS
1125  *     Success: non-zero
1126  *     Failure: zero
1127  */
1128
1129 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1130 {
1131    LPSUBCLASS_INFO stack;
1132    LPSUBCLASSPROCS prevproc = NULL;
1133    LPSUBCLASSPROCS proc;
1134    BOOL ret = FALSE;
1135
1136    TRACE ("(%p, %p, %x)\n", hWnd, pfnSubclass, uID);
1137
1138    /* Find the Subclass to remove */
1139    stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1140    if (!stack)
1141       return FALSE;
1142
1143    proc = stack->SubclassProcs;
1144    while (proc) {
1145       if ((proc->id == uID) &&
1146          (proc->subproc == pfnSubclass)) {
1147          
1148          if (!prevproc)
1149             stack->SubclassProcs = proc->next;
1150          else
1151             prevproc->next = proc->next;
1152           
1153          if (stack->stackpos == proc)
1154             stack->stackpos = stack->stackpos->next;
1155             
1156          Free (proc);
1157          ret = TRUE;
1158          break;
1159       }
1160       prevproc = proc;
1161       proc = proc->next;
1162    }
1163    
1164    if (!stack->SubclassProcs && !stack->running) {
1165       TRACE("Last Subclass removed, cleaning up\n");
1166       /* clean up our heap and reset the origional window procedure */
1167       if (IsWindowUnicode (hWnd))
1168          SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1169       else
1170          SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1171       Free (stack);
1172       RemovePropW( hWnd, COMCTL32_wSubclass );
1173    }
1174    
1175    return ret;
1176 }
1177
1178 /***********************************************************************
1179  * COMCTL32_SubclassProc (internal)
1180  *
1181  * Window procedure for all subclassed windows. 
1182  * Saves the current subclassing stack position to support nested messages
1183  */
1184 LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1185 {
1186    LPSUBCLASS_INFO stack;
1187    LPSUBCLASSPROCS proc;
1188    LRESULT ret;
1189     
1190    TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1191
1192    stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1193    if (!stack) {
1194       ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1195       return 0;
1196    }
1197     
1198    /* Save our old stackpos to properly handle nested messages */
1199    proc = stack->stackpos;
1200    stack->stackpos = stack->SubclassProcs;
1201    stack->running++;
1202    ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1203    stack->running--;
1204    stack->stackpos = proc;
1205     
1206    if (!stack->SubclassProcs && !stack->running) {
1207       TRACE("Last Subclass removed, cleaning up\n");
1208       /* clean up our heap and reset the origional window procedure */
1209       if (IsWindowUnicode (hWnd))
1210          SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1211       else
1212          SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1213       Free (stack);
1214       RemovePropW( hWnd, COMCTL32_wSubclass );
1215    }
1216    return ret;
1217 }
1218
1219 /***********************************************************************
1220  * DefSubclassProc [COMCTL32.413]
1221  *
1222  * Calls the next window procedure (ie. the one before this subclass)
1223  *
1224  * PARAMS
1225  *     hWnd [in] The window that we're subclassing
1226  *     uMsg [in] Message
1227  *     wParam [in] WPARAM
1228  *     lParam [in] LPARAM
1229  *
1230  * RETURNS
1231  *     Success: non-zero
1232  *     Failure: zero
1233  */
1234
1235 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1236 {
1237    LPSUBCLASS_INFO stack;
1238    LRESULT ret;
1239    
1240    TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1241
1242    /* retrieve our little stack from the Properties */
1243    stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
1244    if (!stack) {
1245       ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1246       return 0;
1247    }
1248
1249    /* If we are at the end of stack then we have to call the original
1250     * window procedure */
1251    if (!stack->stackpos) {
1252       if (IsWindowUnicode (hWnd))
1253          ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1254       else
1255          ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1256    } else {
1257       LPSUBCLASSPROCS proc = stack->stackpos;
1258       stack->stackpos = stack->stackpos->next; 
1259       /* call the Subclass procedure from the stack */
1260       ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1261             proc->id, proc->ref);
1262    }
1263
1264    return ret;
1265 }
1266
1267
1268 /***********************************************************************
1269  * COMCTL32_CreateToolTip [NOT AN API]
1270  *
1271  * Creates a tooltip for the control specified in hwnd and does all
1272  * necessary setup and notifications.
1273  *
1274  * PARAMS
1275  *     hwndOwner [I] Handle to the window that will own the tool tip.
1276  *
1277  * RETURNS
1278  *     Success: Handle of tool tip window.
1279  *     Failure: NULL
1280  */
1281
1282 HWND
1283 COMCTL32_CreateToolTip(HWND hwndOwner)
1284 {
1285     HWND hwndToolTip;
1286
1287     hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1288                                   CW_USEDEFAULT, CW_USEDEFAULT,
1289                                   CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1290                                   0, 0, 0);
1291
1292     /* Send NM_TOOLTIPSCREATED notification */
1293     if (hwndToolTip)
1294     {
1295         NMTOOLTIPSCREATED nmttc;
1296         /* true owner can be different if hwndOwner is a child window */
1297         HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1298         nmttc.hdr.hwndFrom = hwndTrueOwner;
1299         nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1300         nmttc.hdr.code = NM_TOOLTIPSCREATED;
1301         nmttc.hwndToolTips = hwndToolTip;
1302
1303        SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1304                     (WPARAM)GetWindowLongPtrW(hwndTrueOwner, GWLP_ID),
1305                     (LPARAM)&nmttc);
1306     }
1307
1308     return hwndToolTip;
1309 }
1310
1311
1312 /***********************************************************************
1313  * COMCTL32_RefreshSysColors [NOT AN API]
1314  *
1315  * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1316  * refresh the color values in the color structure
1317  *
1318  * PARAMS
1319  *     none
1320  *
1321  * RETURNS
1322  *     none
1323  */
1324
1325 VOID
1326 COMCTL32_RefreshSysColors(void)
1327 {
1328     comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1329     comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1330     comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1331     comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1332     comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1333     comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1334     comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1335     comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1336     comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1337     comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1338     comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1339     comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1340     comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1341     comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1342     comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1343     comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1344 }
1345
1346 /***********************************************************************
1347  * COMCTL32_DrawInsertMark [NOT AN API]
1348  *
1349  * Draws an insertion mark (which looks similar to an 'I').
1350  *
1351  * PARAMS
1352  *     hDC           [I] Device context to draw onto.
1353  *     lpRect        [I] Co-ordinates of insertion mark.
1354  *     clrInsertMark [I] Colour of the insertion mark.
1355  *     bHorizontal   [I] True if insert mark should be drawn horizontally,
1356  *                       vertical otherwise.
1357  *
1358  * RETURNS
1359  *     none
1360  *
1361  * NOTES
1362  *     Draws up to but not including the bottom co-ordinate when drawing
1363  *     vertically or the right co-ordinate when horizontal.
1364  */
1365 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1366 {
1367     HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1368     HPEN hOldPen;
1369     static const DWORD adwPolyPoints[] = {4,4,4};
1370     LONG lCentre = (bHorizontal ? 
1371         lpRect->top + (lpRect->bottom - lpRect->top)/2 : 
1372         lpRect->left + (lpRect->right - lpRect->left)/2);
1373     LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1374     LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1375     const POINT aptInsertMark[] =
1376     {
1377         /* top (V) or left (H) arrow */
1378         {lCentre    , l1 + 2},
1379         {lCentre - 2, l1    },
1380         {lCentre + 3, l1    },
1381         {lCentre + 1, l1 + 2},
1382         /* middle line */
1383         {lCentre    , l2 - 2},
1384         {lCentre    , l1 - 1},
1385         {lCentre + 1, l1 - 1},
1386         {lCentre + 1, l2 - 2},
1387         /* bottom (V) or right (H) arrow */
1388         {lCentre    , l2 - 3},
1389         {lCentre - 2, l2 - 1},
1390         {lCentre + 3, l2 - 1},
1391         {lCentre + 1, l2 - 3},
1392     };
1393     hOldPen = SelectObject(hDC, hPen);
1394     PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0]));
1395     SelectObject(hDC, hOldPen);
1396     DeleteObject(hPen);
1397 }
1398
1399 /***********************************************************************
1400  * COMCTL32_EnsureBitmapSize [internal]
1401  *
1402  * If needed enlarge the bitmap so that the width is at least cxMinWidth
1403  * the height is at least cyMinHeight. If the bitmap already have these
1404  * dimensions nothing changes.
1405  *
1406  * PARAMS
1407  *     hBitmap       [I/O] Bitmap to modify. The handle may change
1408  *     cxMinWidth    [I]   If the width of the bitmap is smaller then it will
1409  *                         be enlarged to this value
1410  *     cyMinHeight   [I]   If the height of the bitmap is smaller then it will
1411  *                         be enlarged to this value
1412  *     cyBackground  [I]   The color with which the new area will be filled
1413  *
1414  * RETURNS
1415  *     none
1416  */
1417 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1418 {
1419     int cxNew, cyNew;
1420     BITMAP bmp;
1421     HBITMAP hNewBitmap;
1422     HBITMAP hNewDCBitmap, hOldDCBitmap;
1423     HBRUSH hNewDCBrush;
1424     HDC hdcNew, hdcOld;
1425
1426     if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1427         return;
1428     cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1429     cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1430     if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1431         return;
1432
1433     hdcNew = CreateCompatibleDC(NULL);
1434     hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1435     hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1436     hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1437
1438     hdcOld = CreateCompatibleDC(NULL);
1439     hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1440
1441     BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1442     if (bmp.bmWidth < cxMinWidth)
1443         PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1444     if (bmp.bmHeight < cyMinHeight)
1445         PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1446     if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1447         PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1448
1449     SelectObject(hdcNew, hNewDCBitmap);
1450     DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1451     DeleteDC(hdcNew);
1452     SelectObject(hdcOld, hOldDCBitmap);
1453     DeleteDC(hdcOld);
1454
1455     DeleteObject(*pBitmap);    
1456     *pBitmap = hNewBitmap;
1457     return;
1458 }
1459
1460 /***********************************************************************
1461  * MirrorIcon [COMCTL32.414]
1462  *
1463  * Mirrors an icon so that it will appear correctly on a mirrored DC.
1464  *
1465  * PARAMS
1466  *     phicon1 [I/O] Icon.
1467  *     phicon2 [I/O] Icon.
1468  *
1469  * RETURNS
1470  *     Success: TRUE.
1471  *     Failure: FALSE.
1472  */
1473 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1474 {
1475     FIXME("(%p, %p): stub\n", phicon1, phicon2);
1476     return FALSE;
1477 }
1478
1479 static inline int IsDelimiter(WCHAR c)
1480 {
1481     switch(c)
1482     {
1483         case '/':
1484         case '\\':
1485         case '.':
1486         case ' ':
1487             return TRUE;
1488     }
1489     return FALSE;
1490 }
1491
1492 static int CALLBACK PathWordBreakProc(LPWSTR lpch, int ichCurrent, int cch, int code)
1493 {
1494     if (code == WB_ISDELIMITER)
1495         return IsDelimiter(lpch[ichCurrent]);
1496     else
1497     {
1498         int dir = (code == WB_LEFT) ? -1 : 1;
1499         for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1500             if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1501     }
1502     return ichCurrent;
1503 }
1504
1505 /***********************************************************************
1506  * SetPathWordBreakProc [COMCTL32.384]
1507  *
1508  * Sets the word break procedure for an edit control to one that understands
1509  * paths so that the user can jump over directories.
1510  *
1511  * PARAMS
1512  *     hwnd [I] Handle to edit control.
1513  *     bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1514  *
1515  * RETURNS
1516  *     Result from EM_SETWORDBREAKPROC message.
1517  */
1518 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1519 {
1520     return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1521         (LPARAM)(bSet ? PathWordBreakProc : NULL));
1522 }