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