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