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