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