Avoid using the MAKEPOINTS macro, it's broken on big endian.
[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 LPSTR    COMCTL32_aSubclass = 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
136 /***********************************************************************
137  * DllMain [Internal]
138  *
139  * Initializes the internal 'COMCTL32.DLL'.
140  *
141  * PARAMS
142  *     hinstDLL    [I] handle to the 'dlls' instance
143  *     fdwReason   [I]
144  *     lpvReserved [I] reserverd, must be NULL
145  *
146  * RETURNS
147  *     Success: TRUE
148  *     Failure: FALSE
149  */
150
151 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
152 {
153     TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
154
155     switch (fdwReason) {
156         case DLL_PROCESS_ATTACH:
157             DisableThreadLibraryCalls(hinstDLL);
158
159             COMCTL32_hModule = (HMODULE)hinstDLL;
160
161             /* add global subclassing atom (used by 'tooltip' and 'updown') */
162             COMCTL32_aSubclass = (LPSTR)(DWORD)GlobalAddAtomA ("CC32SubclassInfo");
163             TRACE("Subclassing atom added: %p\n", COMCTL32_aSubclass);
164
165             /* create local pattern brush */
166             COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
167             COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
168
169             /* Get all the colors at DLL load */
170             COMCTL32_RefreshSysColors();
171
172             /* register all Win95 common control classes */
173             ANIMATE_Register ();
174             FLATSB_Register ();
175             HEADER_Register ();
176             HOTKEY_Register ();
177             LISTVIEW_Register ();
178             PROGRESS_Register ();
179             STATUS_Register ();
180             SYSLINK_Register ();
181             TAB_Register ();
182             TOOLBAR_Register ();
183             TOOLTIPS_Register ();
184             TRACKBAR_Register ();
185             TREEVIEW_Register ();
186             UPDOWN_Register ();
187             break;
188
189         case DLL_PROCESS_DETACH:
190             /* unregister all common control classes */
191             ANIMATE_Unregister ();
192             COMBOEX_Unregister ();
193             DATETIME_Unregister ();
194             FLATSB_Unregister ();
195             HEADER_Unregister ();
196             HOTKEY_Unregister ();
197             IPADDRESS_Unregister ();
198             LISTVIEW_Unregister ();
199             MONTHCAL_Unregister ();
200             NATIVEFONT_Unregister ();
201             PAGER_Unregister ();
202             PROGRESS_Unregister ();
203             REBAR_Unregister ();
204             STATUS_Unregister ();
205             SYSLINK_Unregister ();
206             TAB_Unregister ();
207             TOOLBAR_Unregister ();
208             TOOLTIPS_Unregister ();
209             TRACKBAR_Unregister ();
210             TREEVIEW_Unregister ();
211             UPDOWN_Unregister ();
212
213             /* delete local pattern brush */
214             DeleteObject (COMCTL32_hPattern55AABrush);
215             COMCTL32_hPattern55AABrush = NULL;
216             DeleteObject (COMCTL32_hPattern55AABitmap);
217             COMCTL32_hPattern55AABitmap = NULL;
218
219             /* delete global subclassing atom */
220             GlobalDeleteAtom (LOWORD(COMCTL32_aSubclass));
221             TRACE("Subclassing atom deleted: %p\n", COMCTL32_aSubclass);
222             COMCTL32_aSubclass = NULL;
223             break;
224     }
225
226     return TRUE;
227 }
228
229
230 /***********************************************************************
231  * MenuHelp [COMCTL32.2]
232  *
233  * Handles the setting of status bar help messages when the user
234  * selects menu items.
235  *
236  * PARAMS
237  *     uMsg       [I] message (WM_MENUSELECT) (see NOTES)
238  *     wParam     [I] wParam of the message uMsg
239  *     lParam     [I] lParam of the message uMsg
240  *     hMainMenu  [I] handle to the application's main menu
241  *     hInst      [I] handle to the module that contains string resources
242  *     hwndStatus [I] handle to the status bar window
243  *     lpwIDs     [I] pointer to an array of integers (see NOTES)
244  *
245  * RETURNS
246  *     No return value
247  *
248  * NOTES
249  *     The official documentation is incomplete!
250  *     This is the correct documentation:
251  *
252  *     uMsg:
253  *     MenuHelp() does NOT handle WM_COMMAND messages! It only handles
254  *     WM_MENUSELECT messages.
255  *
256  *     lpwIDs:
257  *     (will be written ...)
258  */
259
260 VOID WINAPI
261 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
262           HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
263 {
264     UINT uMenuID = 0;
265
266     if (!IsWindow (hwndStatus))
267         return;
268
269     switch (uMsg) {
270         case WM_MENUSELECT:
271             TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n",
272                    wParam, lParam);
273
274             if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
275                 /* menu was closed */
276                 TRACE("menu was closed!\n");
277                 SendMessageA (hwndStatus, SB_SIMPLE, FALSE, 0);
278             }
279             else {
280                 /* menu item was selected */
281                 if (HIWORD(wParam) & MF_POPUP)
282                     uMenuID = (UINT)*(lpwIDs+1);
283                 else
284                     uMenuID = (UINT)LOWORD(wParam);
285                 TRACE("uMenuID = %u\n", uMenuID);
286
287                 if (uMenuID) {
288                     CHAR szText[256];
289
290                     if (!LoadStringA (hInst, uMenuID, szText, 256))
291                         szText[0] = '\0';
292
293                     SendMessageA (hwndStatus, SB_SETTEXTA,
294                                     255 | SBT_NOBORDERS, (LPARAM)szText);
295                     SendMessageA (hwndStatus, SB_SIMPLE, TRUE, 0);
296                 }
297             }
298             break;
299
300         case WM_COMMAND :
301             TRACE("WM_COMMAND wParam=0x%X lParam=0x%lX\n",
302                    wParam, lParam);
303             /* WM_COMMAND is not invalid since it is documented
304              * in the windows api reference. So don't output
305              * any FIXME for WM_COMMAND
306              */
307             WARN("We don't care about the WM_COMMAND\n");
308             break;
309
310         default:
311             FIXME("Invalid Message 0x%x!\n", uMsg);
312             break;
313     }
314 }
315
316
317 /***********************************************************************
318  * ShowHideMenuCtl [COMCTL32.3]
319  *
320  * Shows or hides controls and updates the corresponding menu item.
321  *
322  * PARAMS
323  *     hwnd   [I] handle to the client window.
324  *     uFlags [I] menu command id.
325  *     lpInfo [I] pointer to an array of integers. (See NOTES.)
326  *
327  * RETURNS
328  *     Success: TRUE
329  *     Failure: FALSE
330  *
331  * NOTES
332  *     The official documentation is incomplete!
333  *     This is the correct documentation:
334  *
335  *     hwnd
336  *     Handle to the window that contains the menu and controls.
337  *
338  *     uFlags
339  *     Identifier of the menu item to receive or loose a check mark.
340  *
341  *     lpInfo
342  *     The array of integers contains pairs of values. BOTH values of
343  *     the first pair must be the handles to the application's main menu.
344  *     Each subsequent pair consists of a menu id and control id.
345  */
346
347 BOOL WINAPI
348 ShowHideMenuCtl (HWND hwnd, UINT uFlags, LPINT lpInfo)
349 {
350     LPINT lpMenuId;
351
352     TRACE("%p, %x, %p\n", hwnd, uFlags, lpInfo);
353
354     if (lpInfo == NULL)
355         return FALSE;
356
357     if (!(lpInfo[0]) || !(lpInfo[1]))
358         return FALSE;
359
360     /* search for control */
361     lpMenuId = &lpInfo[2];
362     while (*lpMenuId != uFlags)
363         lpMenuId += 2;
364
365     if (GetMenuState ((HMENU)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
366         /* uncheck menu item */
367         CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
368
369         /* hide control */
370         lpMenuId++;
371         SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
372                         SWP_HIDEWINDOW);
373     }
374     else {
375         /* check menu item */
376         CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
377
378         /* show control */
379         lpMenuId++;
380         SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
381                         SWP_SHOWWINDOW);
382     }
383
384     return TRUE;
385 }
386
387
388 /***********************************************************************
389  * GetEffectiveClientRect [COMCTL32.4]
390  *
391  * Calculates the coordinates of a rectangle in the client area.
392  *
393  * PARAMS
394  *     hwnd   [I] handle to the client window.
395  *     lpRect [O] pointer to the rectangle of the client window
396  *     lpInfo [I] pointer to an array of integers (see NOTES)
397  *
398  * RETURNS
399  *     No return value.
400  *
401  * NOTES
402  *     The official documentation is incomplete!
403  *     This is the correct documentation:
404  *
405  *     lpInfo
406  *     (will be written ...)
407  */
408
409 VOID WINAPI
410 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo)
411 {
412     RECT rcCtrl;
413     INT  *lpRun;
414     HWND hwndCtrl;
415
416     TRACE("(0x%08lx 0x%08lx 0x%08lx)\n",
417            (DWORD)hwnd, (DWORD)lpRect, (DWORD)lpInfo);
418
419     GetClientRect (hwnd, lpRect);
420     lpRun = lpInfo;
421
422     do {
423         lpRun += 2;
424         if (*lpRun == 0)
425             return;
426         lpRun++;
427         hwndCtrl = GetDlgItem (hwnd, *lpRun);
428         if (GetWindowLongA (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
429             TRACE("control id 0x%x\n", *lpRun);
430             GetWindowRect (hwndCtrl, &rcCtrl);
431             MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
432             SubtractRect (lpRect, lpRect, &rcCtrl);
433         }
434         lpRun++;
435     } while (*lpRun);
436 }
437
438
439 /***********************************************************************
440  * DrawStatusTextW [COMCTL32.@]
441  *
442  * Draws text with borders, like in a status bar.
443  *
444  * PARAMS
445  *     hdc   [I] handle to the window's display context
446  *     lprc  [I] pointer to a rectangle
447  *     text  [I] pointer to the text
448  *     style [I] drawing style
449  *
450  * RETURNS
451  *     No return value.
452  *
453  * NOTES
454  *     The style variable can have one of the following values:
455  *     (will be written ...)
456  */
457
458 void WINAPI DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style)
459 {
460     RECT r = *lprc;
461     UINT border = BDR_SUNKENOUTER;
462
463     if (style & SBT_POPOUT)
464         border = BDR_RAISEDOUTER;
465     else if (style & SBT_NOBORDERS)
466         border = 0;
467
468     DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
469
470     /* now draw text */
471     if (text) {
472         int oldbkmode = SetBkMode (hdc, TRANSPARENT);
473         UINT align = DT_LEFT;
474         if (*text == L'\t') {
475             text++;
476             align = DT_CENTER;
477             if (*text == L'\t') {
478                 text++;
479                 align = DT_RIGHT;
480             }
481         }
482         r.left += 3;
483         if (style & SBT_RTLREADING)
484             FIXME("Unsupported RTL style!\n");
485         DrawTextW (hdc, text, -1, &r, align|DT_VCENTER|DT_SINGLELINE);
486         SetBkMode(hdc, oldbkmode);
487     }
488 }
489
490
491 /***********************************************************************
492  * DrawStatusText  [COMCTL32.@]
493  * DrawStatusTextA [COMCTL32.5]
494  *
495  * Draws text with borders, like in a status bar.
496  *
497  * PARAMS
498  *     hdc   [I] handle to the window's display context
499  *     lprc  [I] pointer to a rectangle
500  *     text  [I] pointer to the text
501  *     style [I] drawing style
502  *
503  * RETURNS
504  *     No return value.
505  */
506
507 void WINAPI DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style)
508 {
509     INT len;
510     LPWSTR textW = NULL;
511
512     if ( text ) {
513         if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
514             if ( (textW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )) )
515                 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
516         }
517     }
518     DrawStatusTextW( hdc, lprc, textW, style );
519     HeapFree( GetProcessHeap(), 0, textW );
520 }
521
522
523 /***********************************************************************
524  * CreateStatusWindow  [COMCTL32.@]
525  * CreateStatusWindowA [COMCTL32.6]
526  *
527  * Creates a status bar
528  *
529  * PARAMS
530  *     style  [I] window style
531  *     text   [I] pointer to the window text
532  *     parent [I] handle to the parent window
533  *     wid    [I] control id of the status bar
534  *
535  * RETURNS
536  *     Success: handle to the status window
537  *     Failure: 0
538  */
539
540 HWND WINAPI
541 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
542 {
543     return CreateWindowA(STATUSCLASSNAMEA, text, style,
544                            CW_USEDEFAULT, CW_USEDEFAULT,
545                            CW_USEDEFAULT, CW_USEDEFAULT,
546                            parent, (HMENU)wid, 0, 0);
547 }
548
549
550 /***********************************************************************
551  * CreateStatusWindowW [COMCTL32.@]
552  *
553  * Creates a status bar control
554  *
555  * PARAMS
556  *     style  [I] window style
557  *     text   [I] pointer to the window text
558  *     parent [I] handle to the parent window
559  *     wid    [I] control id of the status bar
560  *
561  * RETURNS
562  *     Success: handle to the status window
563  *     Failure: 0
564  */
565
566 HWND WINAPI
567 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
568 {
569     return CreateWindowW(STATUSCLASSNAMEW, text, style,
570                            CW_USEDEFAULT, CW_USEDEFAULT,
571                            CW_USEDEFAULT, CW_USEDEFAULT,
572                            parent, (HMENU)wid, 0, 0);
573 }
574
575
576 /***********************************************************************
577  * CreateUpDownControl [COMCTL32.16]
578  *
579  * Creates an up-down control
580  *
581  * PARAMS
582  *     style  [I] window styles
583  *     x      [I] horizontal position of the control
584  *     y      [I] vertical position of the control
585  *     cx     [I] with of the control
586  *     cy     [I] height of the control
587  *     parent [I] handle to the parent window
588  *     id     [I] the control's identifier
589  *     inst   [I] handle to the application's module instance
590  *     buddy  [I] handle to the buddy window, can be NULL
591  *     maxVal [I] upper limit of the control
592  *     minVal [I] lower limit of the control
593  *     curVal [I] current value of the control
594  *
595  * RETURNS
596  *     Success: handle to the updown control
597  *     Failure: 0
598  */
599
600 HWND WINAPI
601 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
602                      HWND parent, INT id, HINSTANCE inst,
603                      HWND buddy, INT maxVal, INT minVal, INT curVal)
604 {
605     HWND hUD =
606         CreateWindowA (UPDOWN_CLASSA, 0, style, x, y, cx, cy,
607                          parent, (HMENU)id, inst, 0);
608     if (hUD) {
609         SendMessageA (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
610         SendMessageA (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
611         SendMessageA (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
612     }
613
614     return hUD;
615 }
616
617
618 /***********************************************************************
619  * InitCommonControls [COMCTL32.17]
620  *
621  * Registers the common controls.
622  *
623  * PARAMS
624  *     No parameters.
625  *
626  * RETURNS
627  *     No return values.
628  *
629  * NOTES
630  *     This function is just a dummy.
631  *     The Win95 controls are registered at the DLL's initialization.
632  *     To register other controls InitCommonControlsEx() must be used.
633  */
634
635 VOID WINAPI
636 InitCommonControls (void)
637 {
638 }
639
640
641 /***********************************************************************
642  * InitCommonControlsEx [COMCTL32.@]
643  *
644  * Registers the common controls.
645  *
646  * PARAMS
647  *     lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
648  *
649  * RETURNS
650  *     Success: TRUE
651  *     Failure: FALSE
652  *
653  * NOTES
654  *     Only the additional common controls are registered by this function.
655  *     The Win95 controls are registered at the DLL's initialization.
656  *
657  * FIXME
658  *     implement the following control classes:
659  *       ICC_LINK_CLASS
660  *       ICC_STANDARD_CLASSES
661  */
662
663 BOOL WINAPI
664 InitCommonControlsEx (LPINITCOMMONCONTROLSEX lpInitCtrls)
665 {
666     INT cCount;
667     DWORD dwMask;
668
669     if (!lpInitCtrls)
670         return FALSE;
671     if (lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
672         return FALSE;
673
674     TRACE("(0x%08lx)\n", lpInitCtrls->dwICC);
675
676     for (cCount = 0; cCount < 32; cCount++) {
677         dwMask = 1 << cCount;
678         if (!(lpInitCtrls->dwICC & dwMask))
679             continue;
680
681         switch (lpInitCtrls->dwICC & dwMask) {
682             /* dummy initialization */
683             case ICC_ANIMATE_CLASS:
684             case ICC_BAR_CLASSES:
685             case ICC_LISTVIEW_CLASSES:
686             case ICC_TREEVIEW_CLASSES:
687             case ICC_TAB_CLASSES:
688             case ICC_UPDOWN_CLASS:
689             case ICC_PROGRESS_CLASS:
690             case ICC_HOTKEY_CLASS:
691                 break;
692
693             /* advanced classes - not included in Win95 */
694             case ICC_DATE_CLASSES:
695                 MONTHCAL_Register ();
696                 DATETIME_Register ();
697                 break;
698
699             case ICC_USEREX_CLASSES:
700                 COMBOEX_Register ();
701                 break;
702
703             case ICC_COOL_CLASSES:
704                 REBAR_Register ();
705                 break;
706
707             case ICC_INTERNET_CLASSES:
708                 IPADDRESS_Register ();
709                 break;
710
711             case ICC_PAGESCROLLER_CLASS:
712                 PAGER_Register ();
713                 break;
714
715             case ICC_NATIVEFNTCTL_CLASS:
716                 NATIVEFONT_Register ();
717                 break;
718
719             case ICC_LINK_CLASS:
720                 SYSLINK_Register ();
721                 break;
722
723             default:
724                 FIXME("Unknown class! dwICC=0x%lX\n", dwMask);
725                 break;
726         }
727     }
728
729     return TRUE;
730 }
731
732
733 /***********************************************************************
734  * CreateToolbarEx [COMCTL32.@]
735  *
736  * Creates a toolbar window.
737  *
738  * PARAMS
739  *     hwnd
740  *     style
741  *     wID
742  *     nBitmaps
743  *     hBMInst
744  *     wBMID
745  *     lpButtons
746  *     iNumButtons
747  *     dxButton
748  *     dyButton
749  *     dxBitmap
750  *     dyBitmap
751  *     uStructSize
752  *
753  * RETURNS
754  *     Success: handle to the tool bar control
755  *     Failure: 0
756  */
757
758 HWND WINAPI
759 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
760                  HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons,
761                  INT iNumButtons, INT dxButton, INT dyButton,
762                  INT dxBitmap, INT dyBitmap, UINT uStructSize)
763 {
764     HWND hwndTB;
765
766     hwndTB =
767         CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL, style|WS_CHILD, 0,0,100,30,
768                         hwnd, (HMENU)wID, COMCTL32_hModule, NULL);
769     if(hwndTB) {
770         TBADDBITMAP tbab;
771
772         SendMessageA (hwndTB, TB_BUTTONSTRUCTSIZE,
773                         (WPARAM)uStructSize, 0);
774
775        /* set bitmap and button size */
776        /*If CreateToolbarEx receives 0, windows sets default values*/
777        if (dxBitmap <= 0)
778            dxBitmap = 16;
779        if (dyBitmap <= 0)
780            dyBitmap = 15;
781        SendMessageA (hwndTB, TB_SETBITMAPSIZE, 0,
782                        MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap));
783
784        if (dxButton <= 0)
785            dxButton = 24;
786        if (dyButton <= 0)
787            dyButton = 22;
788        SendMessageA (hwndTB, TB_SETBUTTONSIZE, 0,
789                        MAKELPARAM((WORD)dxButton, (WORD)dyButton));
790
791
792         /* add bitmaps */
793         if (nBitmaps > 0)
794         {
795         tbab.hInst = hBMInst;
796         tbab.nID   = wBMID;
797
798         SendMessageA (hwndTB, TB_ADDBITMAP,
799                         (WPARAM)nBitmaps, (LPARAM)&tbab);
800         }
801         /* add buttons */
802         if(iNumButtons > 0)
803         SendMessageA (hwndTB, TB_ADDBUTTONSA,
804                         (WPARAM)iNumButtons, (LPARAM)lpButtons);
805     }
806
807     return hwndTB;
808 }
809
810
811 /***********************************************************************
812  * CreateMappedBitmap [COMCTL32.8]
813  *
814  * Loads a bitmap resource using a colour map.
815  *
816  * PARAMS
817  *     hInstance  [I] Handle to the module containing the bitmap.
818  *     idBitmap   [I] The bitmap resource ID.
819  *     wFlags     [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
820  *     lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
821  *     iNumMaps   [I] Number of COLORMAP's pointed to by lpColorMap.
822  *
823  * RETURNS
824  *     Success: handle to the new bitmap
825  *     Failure: 0
826  */
827
828 HBITMAP WINAPI
829 CreateMappedBitmap (HINSTANCE hInstance, INT idBitmap, UINT wFlags,
830                     LPCOLORMAP lpColorMap, INT iNumMaps)
831 {
832     HGLOBAL hglb;
833     HRSRC hRsrc;
834     LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
835     UINT nSize, nColorTableSize, iColor;
836     RGBQUAD *pColorTable;
837     INT i, iMaps, nWidth, nHeight;
838     HDC hdcScreen;
839     HBITMAP hbm;
840     LPCOLORMAP sysColorMap;
841     COLORREF cRef;
842     COLORMAP internalColorMap[4] =
843         {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
844
845     /* initialize pointer to colortable and default color table */
846     if (lpColorMap) {
847         iMaps = iNumMaps;
848         sysColorMap = lpColorMap;
849     }
850     else {
851         internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
852         internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
853         internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
854         internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
855         iMaps = 4;
856         sysColorMap = (LPCOLORMAP)internalColorMap;
857     }
858
859     hRsrc = FindResourceA (hInstance, (LPSTR)idBitmap, (LPSTR)RT_BITMAP);
860     if (hRsrc == 0)
861         return 0;
862     hglb = LoadResource (hInstance, hRsrc);
863     if (hglb == 0)
864         return 0;
865     lpBitmap = (LPBITMAPINFOHEADER)LockResource (hglb);
866     if (lpBitmap == NULL)
867         return 0;
868
869     if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
870         nColorTableSize = lpBitmap->biClrUsed;
871     else if (lpBitmap->biBitCount <= 8) 
872         nColorTableSize = (1 << lpBitmap->biBitCount);
873     else
874         nColorTableSize = 0;
875     nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
876     lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize);
877     if (lpBitmapInfo == NULL)
878         return 0;
879     RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
880
881     pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)lpBitmapInfo->biSize);
882
883     for (iColor = 0; iColor < nColorTableSize; iColor++) {
884         for (i = 0; i < iMaps; i++) {
885             cRef = RGB(pColorTable[iColor].rgbRed,
886                        pColorTable[iColor].rgbGreen,
887                        pColorTable[iColor].rgbBlue);
888             if ( cRef  == sysColorMap[i].from) {
889 #if 0
890                 if (wFlags & CBS_MASKED) {
891                     if (sysColorMap[i].to != COLOR_BTNTEXT)
892                         pColorTable[iColor] = RGB(255, 255, 255);
893                 }
894                 else
895 #endif
896                     pColorTable[iColor].rgbBlue  = GetBValue(sysColorMap[i].to);
897                     pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
898                     pColorTable[iColor].rgbRed   = GetRValue(sysColorMap[i].to);
899                 break;
900             }
901         }
902     }
903     nWidth  = (INT)lpBitmapInfo->biWidth;
904     nHeight = (INT)lpBitmapInfo->biHeight;
905     hdcScreen = GetDC (NULL);
906     hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
907     if (hbm) {
908         HDC hdcDst = CreateCompatibleDC (hdcScreen);
909         HBITMAP hbmOld = SelectObject (hdcDst, hbm);
910         LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
911         lpBits += nColorTableSize * sizeof(RGBQUAD);
912         StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
913                          lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
914                          SRCCOPY);
915         SelectObject (hdcDst, hbmOld);
916         DeleteDC (hdcDst);
917     }
918     ReleaseDC (NULL, hdcScreen);
919     GlobalFree ((HGLOBAL)lpBitmapInfo);
920     FreeResource (hglb);
921
922     return hbm;
923 }
924
925
926 /***********************************************************************
927  * CreateToolbar [COMCTL32.7]
928  *
929  * Creates a toolbar control.
930  *
931  * PARAMS
932  *     hwnd
933  *     style
934  *     wID
935  *     nBitmaps
936  *     hBMInst
937  *     wBMID
938  *     lpButtons
939  *     iNumButtons
940  *
941  * RETURNS
942  *     Success: handle to the tool bar control
943  *     Failure: 0
944  *
945  * NOTES
946  *     Do not use this functions anymore. Use CreateToolbarEx instead.
947  */
948
949 HWND WINAPI
950 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
951                HINSTANCE hBMInst, UINT wBMID,
952                LPCTBBUTTON lpButtons,INT iNumButtons)
953 {
954     return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
955                             hBMInst, wBMID, lpButtons,
956                             iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
957 }
958
959
960 /***********************************************************************
961  * DllGetVersion [COMCTL32.@]
962  *
963  * Retrieves version information of the 'COMCTL32.DLL'
964  *
965  * PARAMS
966  *     pdvi [O] pointer to version information structure.
967  *
968  * RETURNS
969  *     Success: S_OK
970  *     Failure: E_INVALIDARG
971  *
972  * NOTES
973  *     Returns version of a comctl32.dll from IE4.01 SP1.
974  */
975
976 HRESULT WINAPI
977 COMCTL32_DllGetVersion (DLLVERSIONINFO *pdvi)
978 {
979     if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
980         WARN("wrong DLLVERSIONINFO size from app\n");
981         return E_INVALIDARG;
982     }
983
984     pdvi->dwMajorVersion = COMCTL32_VERSION;
985     pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
986     pdvi->dwBuildNumber = 2919;
987     pdvi->dwPlatformID = 6304;
988
989     TRACE("%lu.%lu.%lu.%lu\n",
990            pdvi->dwMajorVersion, pdvi->dwMinorVersion,
991            pdvi->dwBuildNumber, pdvi->dwPlatformID);
992
993     return S_OK;
994 }
995
996 /***********************************************************************
997  *              DllInstall (COMCTL32.@)
998  *
999  * Installs the ComCtl32 DLL.
1000  *
1001  * RETURNS
1002  *     Success: S_OK
1003  *     Failure: A HRESULT error
1004  */
1005 HRESULT WINAPI COMCTL32_DllInstall(BOOL bInstall, LPCWSTR cmdline)
1006 {
1007   FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
1008         debugstr_w(cmdline));
1009
1010   return S_OK;
1011 }
1012
1013 /***********************************************************************
1014  * _TrackMouseEvent [COMCTL32.@]
1015  *
1016  * Requests notification of mouse events
1017  *
1018  * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1019  * to the hwnd specified in the ptme structure.  After the event message
1020  * is posted to the hwnd, the entry in the queue is removed.
1021  *
1022  * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1023  * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1024  * immediately and the TME_LEAVE flag being ignored.
1025  *
1026  * PARAMS
1027  *     ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1028  *
1029  * RETURNS
1030  *     Success: non-zero
1031  *     Failure: zero
1032  *
1033  * IMPLEMENTATION moved to USER32.TrackMouseEvent
1034  *
1035  */
1036
1037 BOOL WINAPI
1038 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1039 {
1040     return TrackMouseEvent (ptme);
1041 }
1042
1043 /*************************************************************************
1044  * GetMUILanguage [COMCTL32.@]
1045  *
1046  * Returns the user interface language in use by the current process.
1047  *
1048  * RETURNS
1049  *      Language ID in use by the current process.
1050  */
1051 LANGID WINAPI GetMUILanguage (VOID)
1052 {
1053     return COMCTL32_uiLang;
1054 }
1055
1056
1057 /*************************************************************************
1058  * InitMUILanguage [COMCTL32.@]
1059  *
1060  * Sets the user interface language to be used by the current process.
1061  *
1062  * RETURNS
1063  *      Nothing.
1064  */
1065 VOID WINAPI InitMUILanguage (LANGID uiLang)
1066 {
1067    COMCTL32_uiLang = uiLang;
1068 }
1069
1070
1071 /***********************************************************************
1072  * SetWindowSubclass [COMCTL32.410]
1073  *
1074  * Starts a window subclass
1075  *
1076  * PARAMS
1077  *     hWnd [in] handle to window subclass.
1078  *     pfnSubclass [in] Pointer to new window procedure.
1079  *     uIDSubclass [in] Unique identifier of sublass together with pfnSubclass.
1080  *     dwRef [in] Reference data to pass to window procedure.
1081  *
1082  * RETURNS
1083  *     Success: non-zero
1084  *     Failure: zero
1085  *
1086  * BUGS
1087  *     If an application manually subclasses a window after subclassing it with
1088  *     this API and then with this API again, then none of the previous 
1089  *     subclasses get called or the origional window procedure.
1090  */
1091
1092 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1093                         UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1094 {
1095    LPSUBCLASS_INFO stack;
1096    LPSUBCLASSPROCS proc;
1097
1098    TRACE ("(%p, %p, %x, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1099
1100    /* Since the window procedure that we set here has two additional arguments,
1101     * we can't simply set it as the new window procedure of the window. So we
1102     * set our own window procedure and then calculate the other two arguments
1103     * from there. */
1104
1105    /* See if we have been called for this window */
1106    stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass);
1107    if (!stack) {
1108       /* allocate stack */
1109       stack = (LPSUBCLASS_INFO)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY,
1110                                          sizeof(SUBCLASS_INFO));
1111       if (!stack) {
1112          ERR ("Failed to allocate our Subclassing stack\n");
1113          return FALSE;
1114       }
1115       SetPropA (hWnd, COMCTL32_aSubclass, (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 = HeapAlloc(GetProcessHeap(), 0, 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       HeapFree (GetProcessHeap (), 0, stack);
1147       RemovePropA( hWnd, COMCTL32_aSubclass );
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)GetPropA (hWnd, COMCTL32_aSubclass);
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)GetPropA (hWnd, COMCTL32_aSubclass);
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          HeapFree (GetProcessHeap (), 0, 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       HeapFree (GetProcessHeap (), 0, stack);
1262       RemovePropA( hWnd, COMCTL32_aSubclass );
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)GetPropA (hWnd, COMCTL32_aSubclass);
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       HeapFree (GetProcessHeap (), 0, stack);
1304       RemovePropA( hWnd, COMCTL32_aSubclass );
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)GetPropA (hWnd, COMCTL32_aSubclass);
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 = CreateWindowExA(0, TOOLTIPS_CLASSA, 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        SendMessageA(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 }