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