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