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