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