kernel32: Add some parameter checking to FileTimeToDosDateTime.
[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.2600.2982"
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 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
127
128 static LPWSTR COMCTL32_wSubclass = NULL;
129 HMODULE COMCTL32_hModule = 0;
130 static 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 = 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 = *(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         int strCnt = 0;
539
540         if (style & SBT_RTLREADING)
541             FIXME("Unsupported RTL style!\n");
542         r.left += 3;
543         do {
544             if (*text == '\t') {
545                 if (strCnt) {
546                     DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
547                     strCnt = 0;
548                 }
549                 if (align==DT_RIGHT) {
550                     break;
551                 }
552                 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
553             } else {
554                 strCnt++;
555             }
556         } while(*text++);
557
558         if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
559         SetBkMode(hdc, oldbkmode);
560     }
561 }
562
563
564 /***********************************************************************
565  * DrawStatusText  [COMCTL32.@]
566  * DrawStatusTextA [COMCTL32.5]
567  *
568  * Draws text with borders, like in a status bar.
569  *
570  * PARAMS
571  *     hdc   [I] handle to the window's display context
572  *     lprc  [I] pointer to a rectangle
573  *     text  [I] pointer to the text
574  *     style [I] drawing style
575  *
576  * RETURNS
577  *     No return value.
578  */
579
580 void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
581 {
582     INT len;
583     LPWSTR textW = NULL;
584
585     if ( text ) {
586         if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
587             if ( (textW = Alloc( len * sizeof(WCHAR) )) )
588                 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
589         }
590     }
591     DrawStatusTextW( hdc, lprc, textW, style );
592     Free( textW );
593 }
594
595
596 /***********************************************************************
597  * CreateStatusWindow  [COMCTL32.@]
598  * CreateStatusWindowA [COMCTL32.6]
599  *
600  * Creates a status bar
601  *
602  * PARAMS
603  *     style  [I] window style
604  *     text   [I] pointer to the window text
605  *     parent [I] handle to the parent window
606  *     wid    [I] control id of the status bar
607  *
608  * RETURNS
609  *     Success: handle to the status window
610  *     Failure: 0
611  */
612
613 HWND WINAPI
614 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
615 {
616     return CreateWindowA(STATUSCLASSNAMEA, text, style,
617                            CW_USEDEFAULT, CW_USEDEFAULT,
618                            CW_USEDEFAULT, CW_USEDEFAULT,
619                            parent, (HMENU)(DWORD_PTR)wid, 0, 0);
620 }
621
622
623 /***********************************************************************
624  * CreateStatusWindowW [COMCTL32.@]
625  *
626  * Creates a status bar control
627  *
628  * PARAMS
629  *     style  [I] window style
630  *     text   [I] pointer to the window text
631  *     parent [I] handle to the parent window
632  *     wid    [I] control id of the status bar
633  *
634  * RETURNS
635  *     Success: handle to the status window
636  *     Failure: 0
637  */
638
639 HWND WINAPI
640 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
641 {
642     return CreateWindowW(STATUSCLASSNAMEW, text, style,
643                            CW_USEDEFAULT, CW_USEDEFAULT,
644                            CW_USEDEFAULT, CW_USEDEFAULT,
645                            parent, (HMENU)(DWORD_PTR)wid, 0, 0);
646 }
647
648
649 /***********************************************************************
650  * CreateUpDownControl [COMCTL32.16]
651  *
652  * Creates an up-down control
653  *
654  * PARAMS
655  *     style  [I] window styles
656  *     x      [I] horizontal position of the control
657  *     y      [I] vertical position of the control
658  *     cx     [I] with of the control
659  *     cy     [I] height of the control
660  *     parent [I] handle to the parent window
661  *     id     [I] the control's identifier
662  *     inst   [I] handle to the application's module instance
663  *     buddy  [I] handle to the buddy window, can be NULL
664  *     maxVal [I] upper limit of the control
665  *     minVal [I] lower limit of the control
666  *     curVal [I] current value of the control
667  *
668  * RETURNS
669  *     Success: handle to the updown control
670  *     Failure: 0
671  */
672
673 HWND WINAPI
674 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
675                      HWND parent, INT id, HINSTANCE inst,
676                      HWND buddy, INT maxVal, INT minVal, INT curVal)
677 {
678     HWND hUD =
679         CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
680                          parent, (HMENU)(DWORD_PTR)id, inst, 0);
681     if (hUD) {
682         SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
683         SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
684         SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
685     }
686
687     return hUD;
688 }
689
690
691 /***********************************************************************
692  * InitCommonControls [COMCTL32.17]
693  *
694  * Registers the common controls.
695  *
696  * PARAMS
697  *     No parameters.
698  *
699  * RETURNS
700  *     No return values.
701  *
702  * NOTES
703  *     This function is just a dummy - all the controls are registered at
704  *     the DLL's initialization. See InitCommonContolsEx for details.
705  */
706
707 VOID WINAPI
708 InitCommonControls (void)
709 {
710 }
711
712
713 /***********************************************************************
714  * InitCommonControlsEx [COMCTL32.@]
715  *
716  * Registers the common controls.
717  *
718  * PARAMS
719  *     lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
720  *
721  * RETURNS
722  *     Success: TRUE
723  *     Failure: FALSE
724  *
725  * NOTES
726  *     Probably all versions of comctl32 initializes the Win95 controls in DllMain
727  *     during DLL initialization. Starting from comctl32 v5.82 all the controls
728  *     are initialized there. We follow this behaviour and this function is just
729  *     a dummy.
730  *
731  *     Note: when writing programs under Windows, if you don't call any function
732  *     from comctl32 the linker may not link this DLL. If InitCommonControlsEx
733  *     was the only comctl32 function you were calling and you remove it you may
734  *     have a false impression that InitCommonControlsEx actually did something.
735  */
736
737 BOOL WINAPI
738 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
739 {
740     if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
741         return FALSE;
742
743     TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
744     return TRUE;
745 }
746
747
748 /***********************************************************************
749  * CreateToolbarEx [COMCTL32.@]
750  *
751  * Creates a toolbar window.
752  *
753  * PARAMS
754  *     hwnd
755  *     style
756  *     wID
757  *     nBitmaps
758  *     hBMInst
759  *     wBMID
760  *     lpButtons
761  *     iNumButtons
762  *     dxButton
763  *     dyButton
764  *     dxBitmap
765  *     dyBitmap
766  *     uStructSize
767  *
768  * RETURNS
769  *     Success: handle to the tool bar control
770  *     Failure: 0
771  */
772
773 HWND WINAPI
774 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
775                  HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
776                  INT iNumButtons, INT dxButton, INT dyButton,
777                  INT dxBitmap, INT dyBitmap, UINT uStructSize)
778 {
779     HWND hwndTB;
780
781     hwndTB =
782         CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
783                         hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
784     if(hwndTB) {
785         TBADDBITMAP tbab;
786
787         SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
788
789        /* set bitmap and button size */
790        /*If CreateToolbarEx receives 0, windows sets default values*/
791        if (dxBitmap < 0)
792            dxBitmap = 16;
793        if (dyBitmap < 0)
794            dyBitmap = 16;
795        if (dxBitmap == 0 || dyBitmap == 0)
796            dxBitmap = dyBitmap = 16;
797        SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
798
799        if (dxButton < 0)
800            dxButton = dxBitmap;
801        if (dyButton < 0)
802            dyButton = dyBitmap;
803        /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
804        if (dxButton != 0 && dyButton != 0)
805             SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
806
807
808         /* add bitmaps */
809         if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
810         {
811             tbab.hInst = hBMInst;
812             tbab.nID   = wBMID;
813
814             SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
815         }
816         /* add buttons */
817         if(iNumButtons > 0)
818         SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
819     }
820
821     return hwndTB;
822 }
823
824
825 /***********************************************************************
826  * CreateMappedBitmap [COMCTL32.8]
827  *
828  * Loads a bitmap resource using a colour map.
829  *
830  * PARAMS
831  *     hInstance  [I] Handle to the module containing the bitmap.
832  *     idBitmap   [I] The bitmap resource ID.
833  *     wFlags     [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
834  *     lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
835  *     iNumMaps   [I] Number of COLORMAP's pointed to by lpColorMap.
836  *
837  * RETURNS
838  *     Success: handle to the new bitmap
839  *     Failure: 0
840  */
841
842 HBITMAP WINAPI
843 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
844                     LPCOLORMAP lpColorMap, INT iNumMaps)
845 {
846     HGLOBAL hglb;
847     HRSRC hRsrc;
848     const BITMAPINFOHEADER *lpBitmap;
849     LPBITMAPINFOHEADER lpBitmapInfo;
850     UINT nSize, nColorTableSize, iColor;
851     RGBQUAD *pColorTable;
852     INT i, iMaps, nWidth, nHeight;
853     HDC hdcScreen;
854     HBITMAP hbm;
855     LPCOLORMAP sysColorMap;
856     COLORREF cRef;
857     COLORMAP internalColorMap[4] =
858         {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
859
860     /* initialize pointer to colortable and default color table */
861     if (lpColorMap) {
862         iMaps = iNumMaps;
863         sysColorMap = lpColorMap;
864     }
865     else {
866         internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
867         internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
868         internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
869         internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
870         iMaps = 4;
871         sysColorMap = internalColorMap;
872     }
873
874     hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
875     if (hRsrc == 0)
876         return 0;
877     hglb = LoadResource (hInstance, hRsrc);
878     if (hglb == 0)
879         return 0;
880     lpBitmap = LockResource (hglb);
881     if (lpBitmap == NULL)
882         return 0;
883
884     if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
885         nColorTableSize = lpBitmap->biClrUsed;
886     else if (lpBitmap->biBitCount <= 8) 
887         nColorTableSize = (1 << lpBitmap->biBitCount);
888     else
889         nColorTableSize = 0;
890     nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
891     lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
892     if (lpBitmapInfo == NULL)
893         return 0;
894     RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
895
896     pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
897
898     for (iColor = 0; iColor < nColorTableSize; iColor++) {
899         for (i = 0; i < iMaps; i++) {
900             cRef = RGB(pColorTable[iColor].rgbRed,
901                        pColorTable[iColor].rgbGreen,
902                        pColorTable[iColor].rgbBlue);
903             if ( cRef  == sysColorMap[i].from) {
904 #if 0
905                 if (wFlags & CBS_MASKED) {
906                     if (sysColorMap[i].to != COLOR_BTNTEXT)
907                         pColorTable[iColor] = RGB(255, 255, 255);
908                 }
909                 else
910 #endif
911                     pColorTable[iColor].rgbBlue  = GetBValue(sysColorMap[i].to);
912                     pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
913                     pColorTable[iColor].rgbRed   = GetRValue(sysColorMap[i].to);
914                 break;
915             }
916         }
917     }
918     nWidth  = lpBitmapInfo->biWidth;
919     nHeight = lpBitmapInfo->biHeight;
920     hdcScreen = GetDC (NULL);
921     hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
922     if (hbm) {
923         HDC hdcDst = CreateCompatibleDC (hdcScreen);
924         HBITMAP hbmOld = SelectObject (hdcDst, hbm);
925         const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
926         StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
927                          lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
928                          SRCCOPY);
929         SelectObject (hdcDst, hbmOld);
930         DeleteDC (hdcDst);
931     }
932     ReleaseDC (NULL, hdcScreen);
933     GlobalFree (lpBitmapInfo);
934     FreeResource (hglb);
935
936     return hbm;
937 }
938
939
940 /***********************************************************************
941  * CreateToolbar [COMCTL32.7]
942  *
943  * Creates a toolbar control.
944  *
945  * PARAMS
946  *     hwnd
947  *     style
948  *     wID
949  *     nBitmaps
950  *     hBMInst
951  *     wBMID
952  *     lpButtons
953  *     iNumButtons
954  *
955  * RETURNS
956  *     Success: handle to the tool bar control
957  *     Failure: 0
958  *
959  * NOTES
960  *     Do not use this functions anymore. Use CreateToolbarEx instead.
961  */
962
963 HWND WINAPI
964 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
965                HINSTANCE hBMInst, UINT wBMID,
966                LPCTBBUTTON lpButtons,INT iNumButtons)
967 {
968     return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
969                             hBMInst, wBMID, lpButtons,
970                             iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
971 }
972
973
974 /***********************************************************************
975  * DllGetVersion [COMCTL32.@]
976  *
977  * Retrieves version information of the 'COMCTL32.DLL'
978  *
979  * PARAMS
980  *     pdvi [O] pointer to version information structure.
981  *
982  * RETURNS
983  *     Success: S_OK
984  *     Failure: E_INVALIDARG
985  *
986  * NOTES
987  *     Returns version of a comctl32.dll from IE4.01 SP1.
988  */
989
990 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
991 {
992     if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
993         WARN("wrong DLLVERSIONINFO size from app\n");
994         return E_INVALIDARG;
995     }
996
997     pdvi->dwMajorVersion = COMCTL32_VERSION;
998     pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
999     pdvi->dwBuildNumber = 2919;
1000     pdvi->dwPlatformID = 6304;
1001
1002     TRACE("%u.%u.%u.%u\n",
1003            pdvi->dwMajorVersion, pdvi->dwMinorVersion,
1004            pdvi->dwBuildNumber, pdvi->dwPlatformID);
1005
1006     return S_OK;
1007 }
1008
1009 /***********************************************************************
1010  *              DllInstall (COMCTL32.@)
1011  *
1012  * Installs the ComCtl32 DLL.
1013  *
1014  * RETURNS
1015  *     Success: S_OK
1016  *     Failure: A HRESULT error
1017  */
1018 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
1019 {
1020     TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
1021     if (!create_manifest( bInstall )) return HRESULT_FROM_WIN32(GetLastError());
1022     return S_OK;
1023 }
1024
1025 /***********************************************************************
1026  * _TrackMouseEvent [COMCTL32.@]
1027  *
1028  * Requests notification of mouse events
1029  *
1030  * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1031  * to the hwnd specified in the ptme structure.  After the event message
1032  * is posted to the hwnd, the entry in the queue is removed.
1033  *
1034  * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1035  * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1036  * immediately and the TME_LEAVE flag being ignored.
1037  *
1038  * PARAMS
1039  *     ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1040  *
1041  * RETURNS
1042  *     Success: non-zero
1043  *     Failure: zero
1044  *
1045  * IMPLEMENTATION moved to USER32.TrackMouseEvent
1046  *
1047  */
1048
1049 BOOL WINAPI
1050 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1051 {
1052     return TrackMouseEvent (ptme);
1053 }
1054
1055 /*************************************************************************
1056  * GetMUILanguage [COMCTL32.@]
1057  *
1058  * Returns the user interface language in use by the current process.
1059  *
1060  * RETURNS
1061  *      Language ID in use by the current process.
1062  */
1063 LANGID WINAPI GetMUILanguage (VOID)
1064 {
1065     return COMCTL32_uiLang;
1066 }
1067
1068
1069 /*************************************************************************
1070  * InitMUILanguage [COMCTL32.@]
1071  *
1072  * Sets the user interface language to be used by the current process.
1073  *
1074  * RETURNS
1075  *      Nothing.
1076  */
1077 VOID WINAPI InitMUILanguage (LANGID uiLang)
1078 {
1079    COMCTL32_uiLang = uiLang;
1080 }
1081
1082
1083 /***********************************************************************
1084  * SetWindowSubclass [COMCTL32.410]
1085  *
1086  * Starts a window subclass
1087  *
1088  * PARAMS
1089  *     hWnd [in] handle to window subclass.
1090  *     pfnSubclass [in] Pointer to new window procedure.
1091  *     uIDSubclass [in] Unique identifier of sublass together with pfnSubclass.
1092  *     dwRef [in] Reference data to pass to window procedure.
1093  *
1094  * RETURNS
1095  *     Success: non-zero
1096  *     Failure: zero
1097  *
1098  * BUGS
1099  *     If an application manually subclasses a window after subclassing it with
1100  *     this API and then with this API again, then none of the previous 
1101  *     subclasses get called or the original window procedure.
1102  */
1103
1104 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1105                         UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1106 {
1107    LPSUBCLASS_INFO stack;
1108    LPSUBCLASSPROCS proc;
1109
1110    TRACE ("(%p, %p, %lx, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1111
1112    /* Since the window procedure that we set here has two additional arguments,
1113     * we can't simply set it as the new window procedure of the window. So we
1114     * set our own window procedure and then calculate the other two arguments
1115     * from there. */
1116
1117    /* See if we have been called for this window */
1118    stack = GetPropW (hWnd, COMCTL32_wSubclass);
1119    if (!stack) {
1120       /* allocate stack */
1121       stack = Alloc (sizeof(SUBCLASS_INFO));
1122       if (!stack) {
1123          ERR ("Failed to allocate our Subclassing stack\n");
1124          return FALSE;
1125       }
1126       SetPropW (hWnd, COMCTL32_wSubclass, stack);
1127
1128       /* set window procedure to our own and save the current one */
1129       if (IsWindowUnicode (hWnd))
1130          stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1131                                                    (DWORD_PTR)COMCTL32_SubclassProc);
1132       else
1133          stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1134                                                    (DWORD_PTR)COMCTL32_SubclassProc);
1135    }
1136    else {
1137       /* Check to see if we have called this function with the same uIDSubClass
1138        * and pfnSubclass */
1139       proc = stack->SubclassProcs;
1140       while (proc) {
1141          if ((proc->id == uIDSubclass) &&
1142             (proc->subproc == pfnSubclass)) {
1143             proc->ref = dwRef;
1144             return TRUE;
1145          }
1146          proc = proc->next;
1147       }
1148    }
1149    
1150    proc = Alloc(sizeof(SUBCLASSPROCS));
1151    if (!proc) {
1152       ERR ("Failed to allocate subclass entry in stack\n");
1153       if (IsWindowUnicode (hWnd))
1154          SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1155       else
1156          SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1157       Free (stack);
1158       RemovePropW( hWnd, COMCTL32_wSubclass );
1159       return FALSE;
1160    }
1161    
1162    proc->subproc = pfnSubclass;
1163    proc->ref = dwRef;
1164    proc->id = uIDSubclass;
1165    proc->next = stack->SubclassProcs;
1166    stack->SubclassProcs = proc;
1167
1168    return TRUE;
1169 }
1170
1171
1172 /***********************************************************************
1173  * GetWindowSubclass [COMCTL32.411]
1174  *
1175  * Gets the Reference data from a subclass.
1176  *
1177  * PARAMS
1178  *     hWnd [in] Handle to window which were subclassing
1179  *     pfnSubclass [in] Pointer to the subclass procedure
1180  *     uID [in] Unique indentifier of the subclassing procedure
1181  *     pdwRef [out] Pointer to the reference data
1182  *
1183  * RETURNS
1184  *     Success: Non-zero
1185  *     Failure: 0
1186  */
1187
1188 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1189                               UINT_PTR uID, DWORD_PTR *pdwRef)
1190 {
1191    const SUBCLASS_INFO *stack;
1192    const SUBCLASSPROCS *proc;
1193
1194    TRACE ("(%p, %p, %lx, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1195
1196    /* See if we have been called for this window */
1197    stack = GetPropW (hWnd, COMCTL32_wSubclass);
1198    if (!stack)
1199       return FALSE;
1200
1201    proc = stack->SubclassProcs;
1202    while (proc) {
1203       if ((proc->id == uID) &&
1204          (proc->subproc == pfnSubclass)) {
1205          *pdwRef = proc->ref;
1206          return TRUE;
1207       }
1208       proc = proc->next;
1209    }
1210
1211    return FALSE;
1212 }
1213
1214
1215 /***********************************************************************
1216  * RemoveWindowSubclass [COMCTL32.412]
1217  *
1218  * Removes a window subclass.
1219  *
1220  * PARAMS
1221  *     hWnd [in] Handle to the window were subclassing
1222  *     pfnSubclass [in] Pointer to the subclass procedure
1223  *     uID [in] Unique identifier of this subclass
1224  *
1225  * RETURNS
1226  *     Success: non-zero
1227  *     Failure: zero
1228  */
1229
1230 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1231 {
1232    LPSUBCLASS_INFO stack;
1233    LPSUBCLASSPROCS prevproc = NULL;
1234    LPSUBCLASSPROCS proc;
1235    BOOL ret = FALSE;
1236
1237    TRACE ("(%p, %p, %lx)\n", hWnd, pfnSubclass, uID);
1238
1239    /* Find the Subclass to remove */
1240    stack = GetPropW (hWnd, COMCTL32_wSubclass);
1241    if (!stack)
1242       return FALSE;
1243
1244    proc = stack->SubclassProcs;
1245    while (proc) {
1246       if ((proc->id == uID) &&
1247          (proc->subproc == pfnSubclass)) {
1248          
1249          if (!prevproc)
1250             stack->SubclassProcs = proc->next;
1251          else
1252             prevproc->next = proc->next;
1253           
1254          if (stack->stackpos == proc)
1255             stack->stackpos = stack->stackpos->next;
1256             
1257          Free (proc);
1258          ret = TRUE;
1259          break;
1260       }
1261       prevproc = proc;
1262       proc = proc->next;
1263    }
1264    
1265    if (!stack->SubclassProcs && !stack->running) {
1266       TRACE("Last Subclass removed, cleaning up\n");
1267       /* clean up our heap and reset the original window procedure */
1268       if (IsWindowUnicode (hWnd))
1269          SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1270       else
1271          SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1272       Free (stack);
1273       RemovePropW( hWnd, COMCTL32_wSubclass );
1274    }
1275    
1276    return ret;
1277 }
1278
1279 /***********************************************************************
1280  * COMCTL32_SubclassProc (internal)
1281  *
1282  * Window procedure for all subclassed windows. 
1283  * Saves the current subclassing stack position to support nested messages
1284  */
1285 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1286 {
1287    LPSUBCLASS_INFO stack;
1288    LPSUBCLASSPROCS proc;
1289    LRESULT ret;
1290     
1291    TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1292
1293    stack = GetPropW (hWnd, COMCTL32_wSubclass);
1294    if (!stack) {
1295       ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1296       return 0;
1297    }
1298     
1299    /* Save our old stackpos to properly handle nested messages */
1300    proc = stack->stackpos;
1301    stack->stackpos = stack->SubclassProcs;
1302    stack->running++;
1303    ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1304    stack->running--;
1305    stack->stackpos = proc;
1306     
1307    if (!stack->SubclassProcs && !stack->running) {
1308       TRACE("Last Subclass removed, cleaning up\n");
1309       /* clean up our heap and reset the original window procedure */
1310       if (IsWindowUnicode (hWnd))
1311          SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1312       else
1313          SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1314       Free (stack);
1315       RemovePropW( hWnd, COMCTL32_wSubclass );
1316    }
1317    return ret;
1318 }
1319
1320 /***********************************************************************
1321  * DefSubclassProc [COMCTL32.413]
1322  *
1323  * Calls the next window procedure (ie. the one before this subclass)
1324  *
1325  * PARAMS
1326  *     hWnd [in] The window that we're subclassing
1327  *     uMsg [in] Message
1328  *     wParam [in] WPARAM
1329  *     lParam [in] LPARAM
1330  *
1331  * RETURNS
1332  *     Success: non-zero
1333  *     Failure: zero
1334  */
1335
1336 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1337 {
1338    LPSUBCLASS_INFO stack;
1339    LRESULT ret;
1340    
1341    TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1342
1343    /* retrieve our little stack from the Properties */
1344    stack = GetPropW (hWnd, COMCTL32_wSubclass);
1345    if (!stack) {
1346       ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1347       return 0;
1348    }
1349
1350    /* If we are at the end of stack then we have to call the original
1351     * window procedure */
1352    if (!stack->stackpos) {
1353       if (IsWindowUnicode (hWnd))
1354          ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1355       else
1356          ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1357    } else {
1358       const SUBCLASSPROCS *proc = stack->stackpos;
1359       stack->stackpos = stack->stackpos->next; 
1360       /* call the Subclass procedure from the stack */
1361       ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1362             proc->id, proc->ref);
1363    }
1364
1365    return ret;
1366 }
1367
1368
1369 /***********************************************************************
1370  * COMCTL32_CreateToolTip [NOT AN API]
1371  *
1372  * Creates a tooltip for the control specified in hwnd and does all
1373  * necessary setup and notifications.
1374  *
1375  * PARAMS
1376  *     hwndOwner [I] Handle to the window that will own the tool tip.
1377  *
1378  * RETURNS
1379  *     Success: Handle of tool tip window.
1380  *     Failure: NULL
1381  */
1382
1383 HWND
1384 COMCTL32_CreateToolTip(HWND hwndOwner)
1385 {
1386     HWND hwndToolTip;
1387
1388     hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1389                                   CW_USEDEFAULT, CW_USEDEFAULT,
1390                                   CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1391                                   0, 0, 0);
1392
1393     /* Send NM_TOOLTIPSCREATED notification */
1394     if (hwndToolTip)
1395     {
1396         NMTOOLTIPSCREATED nmttc;
1397         /* true owner can be different if hwndOwner is a child window */
1398         HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1399         nmttc.hdr.hwndFrom = hwndTrueOwner;
1400         nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1401         nmttc.hdr.code = NM_TOOLTIPSCREATED;
1402         nmttc.hwndToolTips = hwndToolTip;
1403
1404         SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1405                      GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
1406     }
1407
1408     return hwndToolTip;
1409 }
1410
1411
1412 /***********************************************************************
1413  * COMCTL32_RefreshSysColors [NOT AN API]
1414  *
1415  * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1416  * refresh the color values in the color structure
1417  *
1418  * PARAMS
1419  *     none
1420  *
1421  * RETURNS
1422  *     none
1423  */
1424
1425 VOID
1426 COMCTL32_RefreshSysColors(void)
1427 {
1428     comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1429     comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1430     comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1431     comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1432     comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1433     comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1434     comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1435     comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1436     comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1437     comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1438     comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1439     comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1440     comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1441     comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1442     comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1443     comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1444     comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1445 }
1446
1447 /***********************************************************************
1448  * COMCTL32_DrawInsertMark [NOT AN API]
1449  *
1450  * Draws an insertion mark (which looks similar to an 'I').
1451  *
1452  * PARAMS
1453  *     hDC           [I] Device context to draw onto.
1454  *     lpRect        [I] Co-ordinates of insertion mark.
1455  *     clrInsertMark [I] Colour of the insertion mark.
1456  *     bHorizontal   [I] True if insert mark should be drawn horizontally,
1457  *                       vertical otherwise.
1458  *
1459  * RETURNS
1460  *     none
1461  *
1462  * NOTES
1463  *     Draws up to but not including the bottom co-ordinate when drawing
1464  *     vertically or the right co-ordinate when horizontal.
1465  */
1466 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1467 {
1468     HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1469     HPEN hOldPen;
1470     static const DWORD adwPolyPoints[] = {4,4,4};
1471     LONG lCentre = (bHorizontal ? 
1472         lpRect->top + (lpRect->bottom - lpRect->top)/2 : 
1473         lpRect->left + (lpRect->right - lpRect->left)/2);
1474     LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1475     LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1476     const POINT aptInsertMark[] =
1477     {
1478         /* top (V) or left (H) arrow */
1479         {lCentre    , l1 + 2},
1480         {lCentre - 2, l1    },
1481         {lCentre + 3, l1    },
1482         {lCentre + 1, l1 + 2},
1483         /* middle line */
1484         {lCentre    , l2 - 2},
1485         {lCentre    , l1 - 1},
1486         {lCentre + 1, l1 - 1},
1487         {lCentre + 1, l2 - 2},
1488         /* bottom (V) or right (H) arrow */
1489         {lCentre    , l2 - 3},
1490         {lCentre - 2, l2 - 1},
1491         {lCentre + 3, l2 - 1},
1492         {lCentre + 1, l2 - 3},
1493     };
1494     hOldPen = SelectObject(hDC, hPen);
1495     PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0]));
1496     SelectObject(hDC, hOldPen);
1497     DeleteObject(hPen);
1498 }
1499
1500 /***********************************************************************
1501  * COMCTL32_EnsureBitmapSize [internal]
1502  *
1503  * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1504  * the height is at least cyMinHeight. If the bitmap already has these
1505  * dimensions nothing changes.
1506  *
1507  * PARAMS
1508  *     hBitmap       [I/O] Bitmap to modify. The handle may change
1509  *     cxMinWidth    [I]   If the width of the bitmap is smaller, then it will
1510  *                         be enlarged to this value
1511  *     cyMinHeight   [I]   If the height of the bitmap is smaller, then it will
1512  *                         be enlarged to this value
1513  *     cyBackground  [I]   The color with which the new area will be filled
1514  *
1515  * RETURNS
1516  *     none
1517  */
1518 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1519 {
1520     int cxNew, cyNew;
1521     BITMAP bmp;
1522     HBITMAP hNewBitmap;
1523     HBITMAP hNewDCBitmap, hOldDCBitmap;
1524     HBRUSH hNewDCBrush;
1525     HDC hdcNew, hdcOld;
1526
1527     if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1528         return;
1529     cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1530     cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1531     if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1532         return;
1533
1534     hdcNew = CreateCompatibleDC(NULL);
1535     hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1536     hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1537     hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1538
1539     hdcOld = CreateCompatibleDC(NULL);
1540     hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1541
1542     BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1543     if (bmp.bmWidth < cxMinWidth)
1544         PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1545     if (bmp.bmHeight < cyMinHeight)
1546         PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1547     if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1548         PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1549
1550     SelectObject(hdcNew, hNewDCBitmap);
1551     DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1552     DeleteDC(hdcNew);
1553     SelectObject(hdcOld, hOldDCBitmap);
1554     DeleteDC(hdcOld);
1555
1556     DeleteObject(*pBitmap);    
1557     *pBitmap = hNewBitmap;
1558     return;
1559 }
1560
1561 void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
1562 {
1563     HDC hdc = GetDC(NULL);
1564     HFONT hOldFont;
1565
1566     hOldFont = SelectObject(hdc, hFont);
1567     GetTextMetricsW(hdc, ptm);
1568     SelectObject(hdc, hOldFont);
1569     ReleaseDC(NULL, hdc);
1570 }
1571
1572 #ifndef OCM__BASE      /* avoid including olectl.h */
1573 #define OCM__BASE (WM_USER+0x1c00)
1574 #endif
1575
1576 /***********************************************************************
1577  * COMCTL32_IsReflectedMessage [internal]
1578  *
1579  * Some parents reflect notify messages - for some messages sent by the child,
1580  * they send it back with the message code increased by OCM__BASE (0x2000).
1581  * This allows better subclassing of controls. We don't need to handle such
1582  * messages but we don't want to print ERRs for them, so this helper function
1583  * identifies them.
1584  *
1585  * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1586  * colision with defined CCM_ codes.
1587  */
1588 BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
1589 {
1590     switch (uMsg)
1591     {
1592         case OCM__BASE + WM_COMMAND:
1593         case OCM__BASE + WM_CTLCOLORBTN:
1594         case OCM__BASE + WM_CTLCOLOREDIT:
1595         case OCM__BASE + WM_CTLCOLORDLG:
1596         case OCM__BASE + WM_CTLCOLORLISTBOX:
1597         case OCM__BASE + WM_CTLCOLORMSGBOX:
1598         case OCM__BASE + WM_CTLCOLORSCROLLBAR:
1599         case OCM__BASE + WM_CTLCOLORSTATIC:
1600         case OCM__BASE + WM_DRAWITEM:
1601         case OCM__BASE + WM_MEASUREITEM:
1602         case OCM__BASE + WM_DELETEITEM:
1603         case OCM__BASE + WM_VKEYTOITEM:
1604         case OCM__BASE + WM_CHARTOITEM:
1605         case OCM__BASE + WM_COMPAREITEM:
1606         case OCM__BASE + WM_HSCROLL:
1607         case OCM__BASE + WM_VSCROLL:
1608         case OCM__BASE + WM_PARENTNOTIFY:
1609         case OCM__BASE + WM_NOTIFY:
1610             return TRUE;
1611         default:
1612             return FALSE;
1613     }
1614 }
1615
1616 /***********************************************************************
1617  * MirrorIcon [COMCTL32.414]
1618  *
1619  * Mirrors an icon so that it will appear correctly on a mirrored DC.
1620  *
1621  * PARAMS
1622  *     phicon1 [I/O] Icon.
1623  *     phicon2 [I/O] Icon.
1624  *
1625  * RETURNS
1626  *     Success: TRUE.
1627  *     Failure: FALSE.
1628  */
1629 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1630 {
1631     FIXME("(%p, %p): stub\n", phicon1, phicon2);
1632     return FALSE;
1633 }
1634
1635 static inline int IsDelimiter(WCHAR c)
1636 {
1637     switch(c)
1638     {
1639         case '/':
1640         case '\\':
1641         case '.':
1642         case ' ':
1643             return TRUE;
1644     }
1645     return FALSE;
1646 }
1647
1648 static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1649 {
1650     if (code == WB_ISDELIMITER)
1651         return IsDelimiter(lpch[ichCurrent]);
1652     else
1653     {
1654         int dir = (code == WB_LEFT) ? -1 : 1;
1655         for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1656             if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1657     }
1658     return ichCurrent;
1659 }
1660
1661 /***********************************************************************
1662  * SetPathWordBreakProc [COMCTL32.384]
1663  *
1664  * Sets the word break procedure for an edit control to one that understands
1665  * paths so that the user can jump over directories.
1666  *
1667  * PARAMS
1668  *     hwnd [I] Handle to edit control.
1669  *     bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1670  *
1671  * RETURNS
1672  *     Result from EM_SETWORDBREAKPROC message.
1673  */
1674 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1675 {
1676     return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1677         (LPARAM)(bSet ? PathWordBreakProc : NULL));
1678 }
1679
1680 /***********************************************************************
1681  * DrawShadowText [COMCTL32.@]
1682  *
1683  * Draw text with shadow.
1684  */
1685 int WINAPI DrawShadowText(HDC hdc, LPCWSTR pszText, UINT cch, RECT *rect, DWORD dwFlags,
1686                           COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset)
1687 {
1688     FIXME("(%p, %s, %d, %p, %d, 0x%08x, 0x%08x, %d, %d): stub\n", hdc, debugstr_w(pszText), cch, rect, dwFlags,
1689                                                                   crText, crShadow, ixOffset, iyOffset);
1690     return DrawTextW(hdc, pszText, cch, rect, DT_LEFT);
1691 }
1692
1693 /***********************************************************************
1694  * TaskDialogIndirect [COMCTL32.@]
1695  */
1696 HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *pTaskConfig, int *pnButton,
1697                                   int *pnRadioButton, BOOL *pfVerificationFlagChecked)
1698 {
1699     FIXME("%p, %p, %p, %p\n", pTaskConfig, pnButton, pnRadioButton, pfVerificationFlagChecked);
1700
1701     if (pnButton) *pnButton = IDYES;
1702     if (pnRadioButton) *pnRadioButton = pTaskConfig->nDefaultButton;
1703     if (pfVerificationFlagChecked) *pfVerificationFlagChecked = TRUE;
1704     return S_OK;
1705 }