schedsvc: Fix a typo in a parameter name.
[wine.git] / dlls / comctl32 / commctrl.c
blob45b93bdc8b5a276b31937a108c0b834377b2f45d
1 /*
2 * Common controls functions
4 * Copyright 1997 Dimitrie O. Paun
5 * Copyright 1998,2000 Eric Kohl
6 * Copyright 2014-2015 Michael Müller
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * NOTES
24 * This code was audited for completeness against the documented features
25 * of Comctl32.dll version 6.0 on Oct. 21, 2002, by Christian Neumair.
27 * Unless otherwise noted, we believe this code to be complete, as per
28 * the specification mentioned above.
29 * If you discover missing features, or bugs, please note them below.
31 * TODO
32 * -- implement GetMUILanguage + InitMUILanguage
33 * -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW
34 * -- FIXMEs + BUGS (search for them)
36 * Control Classes
37 * -- ICC_ANIMATE_CLASS
38 * -- ICC_BAR_CLASSES
39 * -- ICC_COOL_CLASSES
40 * -- ICC_DATE_CLASSES
41 * -- ICC_HOTKEY_CLASS
42 * -- ICC_INTERNET_CLASSES
43 * -- ICC_LINK_CLASS
44 * -- ICC_LISTVIEW_CLASSES
45 * -- ICC_NATIVEFNTCTL_CLASS
46 * -- ICC_PAGESCROLLER_CLASS
47 * -- ICC_PROGRESS_CLASS
48 * -- ICC_STANDARD_CLASSES (not yet implemented)
49 * -- ICC_TAB_CLASSES
50 * -- ICC_TREEVIEW_CLASSES
51 * -- ICC_UPDOWN_CLASS
52 * -- ICC_USEREX_CLASSES
53 * -- ICC_WIN95_CLASSES
56 #include <stdarg.h>
57 #include <string.h>
58 #include <stdlib.h>
60 #include "windef.h"
61 #include "winbase.h"
62 #include "wingdi.h"
63 #include "winuser.h"
64 #include "winnls.h"
65 #include "commctrl.h"
66 #include "winerror.h"
67 #include "winreg.h"
68 #define NO_SHLWAPI_STREAM
69 #include "shlwapi.h"
70 #include "comctl32.h"
71 #include "wine/debug.h"
72 #include "wine/unicode.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
77 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
79 static LPWSTR COMCTL32_wSubclass = NULL;
80 HMODULE COMCTL32_hModule = 0;
81 static LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
82 HBRUSH COMCTL32_hPattern55AABrush = NULL;
83 COMCTL32_SysColor comctl32_color;
85 static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
87 static const WORD wPattern55AA[] =
89 0x5555, 0xaaaa, 0x5555, 0xaaaa,
90 0x5555, 0xaaaa, 0x5555, 0xaaaa
93 static const WCHAR strCC32SubclassInfo[] = {
94 'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
97 static void unregister_versioned_classes(void)
99 #define VERSION "6.0.2600.2982!"
100 static const char *classes[] =
102 VERSION WC_BUTTONA,
103 VERSION WC_COMBOBOXA,
104 VERSION "ComboLBox",
105 VERSION WC_EDITA,
106 VERSION WC_LISTBOXA,
107 VERSION WC_STATICA,
109 int i;
111 for (i = 0; i < ARRAY_SIZE(classes); i++)
112 UnregisterClassA(classes[i], NULL);
114 #undef VERSION
117 BOOL WINAPI RegisterClassNameW(const WCHAR *class)
119 static const struct
121 const WCHAR nameW[16];
122 void (*fn_register)(void);
124 classes[] =
126 { {'B','u','t','t','o','n',0}, BUTTON_Register },
127 { {'C','o','m','b','o','B','o','x',0}, COMBO_Register },
128 { {'C','o','m','b','o','L','B','o','x',0}, COMBOLBOX_Register },
129 { {'E','d','i','t',0}, EDIT_Register },
130 { {'L','i','s','t','B','o','x',0}, LISTBOX_Register },
131 { {'S','t','a','t','i','c',0}, STATIC_Register },
134 int min = 0, max = ARRAY_SIZE(classes) - 1;
136 while (min <= max)
138 int res, pos = (min + max) / 2;
139 if (!(res = strcmpiW(class, classes[pos].nameW)))
141 classes[pos].fn_register();
142 return TRUE;
144 if (res < 0) max = pos - 1;
145 else min = pos + 1;
148 return FALSE;
151 /***********************************************************************
152 * DllMain [Internal]
154 * Initializes the internal 'COMCTL32.DLL'.
156 * PARAMS
157 * hinstDLL [I] handle to the 'dlls' instance
158 * fdwReason [I]
159 * lpvReserved [I] reserved, must be NULL
161 * RETURNS
162 * Success: TRUE
163 * Failure: FALSE
166 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
168 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
170 switch (fdwReason) {
171 case DLL_PROCESS_ATTACH:
172 DisableThreadLibraryCalls(hinstDLL);
174 COMCTL32_hModule = hinstDLL;
176 /* add global subclassing atom (used by 'tooltip' and 'updown') */
177 COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
178 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
180 /* create local pattern brush */
181 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
182 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
184 /* Get all the colors at DLL load */
185 COMCTL32_RefreshSysColors();
187 /* like comctl32 5.82+ register all the common control classes */
188 ANIMATE_Register ();
189 COMBOEX_Register ();
190 DATETIME_Register ();
191 FLATSB_Register ();
192 HEADER_Register ();
193 HOTKEY_Register ();
194 IPADDRESS_Register ();
195 LISTVIEW_Register ();
196 MONTHCAL_Register ();
197 NATIVEFONT_Register ();
198 PAGER_Register ();
199 PROGRESS_Register ();
200 REBAR_Register ();
201 STATUS_Register ();
202 SYSLINK_Register ();
203 TAB_Register ();
204 TOOLBAR_Register ();
205 TOOLTIPS_Register ();
206 TRACKBAR_Register ();
207 TREEVIEW_Register ();
208 UPDOWN_Register ();
210 /* subclass user32 controls */
211 THEMING_Initialize ();
212 break;
214 case DLL_PROCESS_DETACH:
215 if (lpvReserved) break;
216 /* clean up subclassing */
217 THEMING_Uninitialize();
219 /* unregister all common control classes */
220 ANIMATE_Unregister ();
221 COMBOEX_Unregister ();
222 DATETIME_Unregister ();
223 FLATSB_Unregister ();
224 HEADER_Unregister ();
225 HOTKEY_Unregister ();
226 IPADDRESS_Unregister ();
227 LISTVIEW_Unregister ();
228 MONTHCAL_Unregister ();
229 NATIVEFONT_Unregister ();
230 PAGER_Unregister ();
231 PROGRESS_Unregister ();
232 REBAR_Unregister ();
233 STATUS_Unregister ();
234 SYSLINK_Unregister ();
235 TAB_Unregister ();
236 TOOLBAR_Unregister ();
237 TOOLTIPS_Unregister ();
238 TRACKBAR_Unregister ();
239 TREEVIEW_Unregister ();
240 UPDOWN_Unregister ();
242 unregister_versioned_classes ();
244 /* delete local pattern brush */
245 DeleteObject (COMCTL32_hPattern55AABrush);
246 DeleteObject (COMCTL32_hPattern55AABitmap);
248 /* delete global subclassing atom */
249 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
250 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
251 break;
254 return TRUE;
258 /***********************************************************************
259 * MenuHelp [COMCTL32.2]
261 * Handles the setting of status bar help messages when the user
262 * selects menu items.
264 * PARAMS
265 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
266 * wParam [I] wParam of the message uMsg
267 * lParam [I] lParam of the message uMsg
268 * hMainMenu [I] handle to the application's main menu
269 * hInst [I] handle to the module that contains string resources
270 * hwndStatus [I] handle to the status bar window
271 * lpwIDs [I] pointer to an array of integers (see NOTES)
273 * RETURNS
274 * No return value
276 * NOTES
277 * The official documentation is incomplete!
278 * This is the correct documentation:
280 * uMsg:
281 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
282 * WM_MENUSELECT messages.
284 * lpwIDs:
285 * (will be written ...)
288 VOID WINAPI
289 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
290 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
292 UINT uMenuID = 0;
294 if (!IsWindow (hwndStatus))
295 return;
297 switch (uMsg) {
298 case WM_MENUSELECT:
299 TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
300 wParam, lParam);
302 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
303 /* menu was closed */
304 TRACE("menu was closed!\n");
305 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
307 else {
308 /* menu item was selected */
309 if (HIWORD(wParam) & MF_POPUP)
310 uMenuID = *(lpwIDs+1);
311 else
312 uMenuID = (UINT)LOWORD(wParam);
313 TRACE("uMenuID = %u\n", uMenuID);
315 if (uMenuID) {
316 WCHAR szText[256];
318 if (!LoadStringW (hInst, uMenuID, szText, ARRAY_SIZE(szText)))
319 szText[0] = '\0';
321 SendMessageW (hwndStatus, SB_SETTEXTW,
322 255 | SBT_NOBORDERS, (LPARAM)szText);
323 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
326 break;
328 case WM_COMMAND :
329 TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
330 wParam, lParam);
331 /* WM_COMMAND is not invalid since it is documented
332 * in the windows api reference. So don't output
333 * any FIXME for WM_COMMAND
335 WARN("We don't care about the WM_COMMAND\n");
336 break;
338 default:
339 FIXME("Invalid Message 0x%x!\n", uMsg);
340 break;
345 /***********************************************************************
346 * ShowHideMenuCtl [COMCTL32.3]
348 * Shows or hides controls and updates the corresponding menu item.
350 * PARAMS
351 * hwnd [I] handle to the client window.
352 * uFlags [I] menu command id.
353 * lpInfo [I] pointer to an array of integers. (See NOTES.)
355 * RETURNS
356 * Success: TRUE
357 * Failure: FALSE
359 * NOTES
360 * The official documentation is incomplete!
361 * This is the correct documentation:
363 * hwnd
364 * Handle to the window that contains the menu and controls.
366 * uFlags
367 * Identifier of the menu item to receive or lose a check mark.
369 * lpInfo
370 * The array of integers contains pairs of values. BOTH values of
371 * the first pair must be the handles to the application's main menu.
372 * Each subsequent pair consists of a menu id and control id.
375 BOOL WINAPI
376 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
378 LPINT lpMenuId;
380 TRACE("%p, %lx, %p\n", hwnd, uFlags, lpInfo);
382 if (lpInfo == NULL)
383 return FALSE;
385 if (!(lpInfo[0]) || !(lpInfo[1]))
386 return FALSE;
388 /* search for control */
389 lpMenuId = &lpInfo[2];
390 while (*lpMenuId != uFlags)
391 lpMenuId += 2;
393 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
394 /* uncheck menu item */
395 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
397 /* hide control */
398 lpMenuId++;
399 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
400 SWP_HIDEWINDOW);
402 else {
403 /* check menu item */
404 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
406 /* show control */
407 lpMenuId++;
408 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
409 SWP_SHOWWINDOW);
412 return TRUE;
416 /***********************************************************************
417 * GetEffectiveClientRect [COMCTL32.4]
419 * Calculates the coordinates of a rectangle in the client area.
421 * PARAMS
422 * hwnd [I] handle to the client window.
423 * lpRect [O] pointer to the rectangle of the client window
424 * lpInfo [I] pointer to an array of integers (see NOTES)
426 * RETURNS
427 * No return value.
429 * NOTES
430 * The official documentation is incomplete!
431 * This is the correct documentation:
433 * lpInfo
434 * (will be written ...)
437 VOID WINAPI
438 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
440 RECT rcCtrl;
441 const INT *lpRun;
442 HWND hwndCtrl;
444 TRACE("(%p %p %p)\n",
445 hwnd, lpRect, lpInfo);
447 GetClientRect (hwnd, lpRect);
448 lpRun = lpInfo;
450 do {
451 lpRun += 2;
452 if (*lpRun == 0)
453 return;
454 lpRun++;
455 hwndCtrl = GetDlgItem (hwnd, *lpRun);
456 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
457 TRACE("control id 0x%x\n", *lpRun);
458 GetWindowRect (hwndCtrl, &rcCtrl);
459 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
460 SubtractRect (lpRect, lpRect, &rcCtrl);
462 lpRun++;
463 } while (*lpRun);
467 /***********************************************************************
468 * DrawStatusTextW [COMCTL32.@]
470 * Draws text with borders, like in a status bar.
472 * PARAMS
473 * hdc [I] handle to the window's display context
474 * lprc [I] pointer to a rectangle
475 * text [I] pointer to the text
476 * style [I] drawing style
478 * RETURNS
479 * No return value.
481 * NOTES
482 * The style variable can have one of the following values:
483 * (will be written ...)
486 void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
488 RECT r = *lprc;
489 UINT border = BDR_SUNKENOUTER;
490 COLORREF oldbkcolor;
492 if (style & SBT_POPOUT)
493 border = BDR_RAISEDOUTER;
494 else if (style & SBT_NOBORDERS)
495 border = 0;
497 oldbkcolor = SetBkColor (hdc, comctl32_color.clrBtnFace);
498 DrawEdge (hdc, &r, border, BF_MIDDLE|BF_RECT|BF_ADJUST);
500 /* now draw text */
501 if (text) {
502 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
503 COLORREF oldtextcolor;
504 UINT align = DT_LEFT;
505 int strCnt = 0;
507 oldtextcolor = SetTextColor (hdc, comctl32_color.clrBtnText);
508 if (style & SBT_RTLREADING)
509 FIXME("Unsupported RTL style!\n");
510 r.left += 3;
511 do {
512 if (*text == '\t') {
513 if (strCnt) {
514 DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
515 strCnt = 0;
517 if (align==DT_RIGHT) {
518 break;
520 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
521 } else {
522 strCnt++;
524 } while(*text++);
526 if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
527 SetBkMode (hdc, oldbkmode);
528 SetTextColor (hdc, oldtextcolor);
531 SetBkColor (hdc, oldbkcolor);
535 /***********************************************************************
536 * DrawStatusText [COMCTL32.@]
537 * DrawStatusTextA [COMCTL32.5]
539 * Draws text with borders, like in a status bar.
541 * PARAMS
542 * hdc [I] handle to the window's display context
543 * lprc [I] pointer to a rectangle
544 * text [I] pointer to the text
545 * style [I] drawing style
547 * RETURNS
548 * No return value.
551 void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
553 INT len;
554 LPWSTR textW = NULL;
556 if ( text ) {
557 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
558 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
559 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
562 DrawStatusTextW( hdc, lprc, textW, style );
563 Free( textW );
567 /***********************************************************************
568 * CreateStatusWindow [COMCTL32.@]
569 * CreateStatusWindowA [COMCTL32.6]
571 * Creates a status bar
573 * PARAMS
574 * style [I] window style
575 * text [I] pointer to the window text
576 * parent [I] handle to the parent window
577 * wid [I] control id of the status bar
579 * RETURNS
580 * Success: handle to the status window
581 * Failure: 0
584 HWND WINAPI
585 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
587 return CreateWindowA(STATUSCLASSNAMEA, text, style,
588 CW_USEDEFAULT, CW_USEDEFAULT,
589 CW_USEDEFAULT, CW_USEDEFAULT,
590 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
594 /***********************************************************************
595 * CreateStatusWindowW [COMCTL32.@]
597 * Creates a status bar control
599 * PARAMS
600 * style [I] window style
601 * text [I] pointer to the window text
602 * parent [I] handle to the parent window
603 * wid [I] control id of the status bar
605 * RETURNS
606 * Success: handle to the status window
607 * Failure: 0
610 HWND WINAPI
611 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
613 return CreateWindowW(STATUSCLASSNAMEW, text, style,
614 CW_USEDEFAULT, CW_USEDEFAULT,
615 CW_USEDEFAULT, CW_USEDEFAULT,
616 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
620 /***********************************************************************
621 * CreateUpDownControl [COMCTL32.16]
623 * Creates an up-down control
625 * PARAMS
626 * style [I] window styles
627 * x [I] horizontal position of the control
628 * y [I] vertical position of the control
629 * cx [I] with of the control
630 * cy [I] height of the control
631 * parent [I] handle to the parent window
632 * id [I] the control's identifier
633 * inst [I] handle to the application's module instance
634 * buddy [I] handle to the buddy window, can be NULL
635 * maxVal [I] upper limit of the control
636 * minVal [I] lower limit of the control
637 * curVal [I] current value of the control
639 * RETURNS
640 * Success: handle to the updown control
641 * Failure: 0
644 HWND WINAPI
645 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
646 HWND parent, INT id, HINSTANCE inst,
647 HWND buddy, INT maxVal, INT minVal, INT curVal)
649 HWND hUD =
650 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
651 parent, (HMENU)(DWORD_PTR)id, inst, 0);
652 if (hUD) {
653 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
654 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
655 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
658 return hUD;
662 /***********************************************************************
663 * InitCommonControls [COMCTL32.17]
665 * Registers the common controls.
667 * PARAMS
668 * No parameters.
670 * RETURNS
671 * No return values.
673 * NOTES
674 * This function is just a dummy - all the controls are registered at
675 * the DLL initialization time. See InitCommonContolsEx for details.
678 VOID WINAPI
679 InitCommonControls (void)
684 /***********************************************************************
685 * InitCommonControlsEx [COMCTL32.@]
687 * Registers the common controls.
689 * PARAMS
690 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
692 * RETURNS
693 * Success: TRUE
694 * Failure: FALSE
696 * NOTES
697 * Probably all versions of comctl32 initializes the Win95 controls in DllMain
698 * during DLL initialization. Starting from comctl32 v5.82 all the controls
699 * are initialized there. We follow this behaviour and this function is just
700 * a dummy.
702 * Note: when writing programs under Windows, if you don't call any function
703 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
704 * was the only comctl32 function you were calling and you remove it you may
705 * have a false impression that InitCommonControlsEx actually did something.
708 BOOL WINAPI
709 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
711 if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
712 return FALSE;
714 TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
715 return TRUE;
719 /***********************************************************************
720 * CreateToolbarEx [COMCTL32.@]
722 * Creates a toolbar window.
724 * PARAMS
725 * hwnd
726 * style
727 * wID
728 * nBitmaps
729 * hBMInst
730 * wBMID
731 * lpButtons
732 * iNumButtons
733 * dxButton
734 * dyButton
735 * dxBitmap
736 * dyBitmap
737 * uStructSize
739 * RETURNS
740 * Success: handle to the tool bar control
741 * Failure: 0
744 HWND WINAPI
745 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
746 HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
747 INT iNumButtons, INT dxButton, INT dyButton,
748 INT dxBitmap, INT dyBitmap, UINT uStructSize)
750 HWND hwndTB;
752 hwndTB =
753 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
754 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
755 if(hwndTB) {
756 TBADDBITMAP tbab;
758 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
760 /* set bitmap and button size */
761 /*If CreateToolbarEx receives 0, windows sets default values*/
762 if (dxBitmap < 0)
763 dxBitmap = 16;
764 if (dyBitmap < 0)
765 dyBitmap = 16;
766 if (dxBitmap == 0 || dyBitmap == 0)
767 dxBitmap = dyBitmap = 16;
768 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
770 if (dxButton < 0)
771 dxButton = dxBitmap;
772 if (dyButton < 0)
773 dyButton = dyBitmap;
774 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
775 if (dxButton != 0 && dyButton != 0)
776 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
779 /* add bitmaps */
780 if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
782 tbab.hInst = hBMInst;
783 tbab.nID = wBMID;
785 SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
787 /* add buttons */
788 if(iNumButtons > 0)
789 SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
792 return hwndTB;
796 /***********************************************************************
797 * CreateMappedBitmap [COMCTL32.8]
799 * Loads a bitmap resource using a colour map.
801 * PARAMS
802 * hInstance [I] Handle to the module containing the bitmap.
803 * idBitmap [I] The bitmap resource ID.
804 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
805 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
806 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
808 * RETURNS
809 * Success: handle to the new bitmap
810 * Failure: 0
813 HBITMAP WINAPI
814 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
815 LPCOLORMAP lpColorMap, INT iNumMaps)
817 HGLOBAL hglb;
818 HRSRC hRsrc;
819 const BITMAPINFOHEADER *lpBitmap;
820 LPBITMAPINFOHEADER lpBitmapInfo;
821 UINT nSize, nColorTableSize, iColor;
822 RGBQUAD *pColorTable;
823 INT i, iMaps, nWidth, nHeight;
824 HDC hdcScreen;
825 HBITMAP hbm;
826 LPCOLORMAP sysColorMap;
827 COLORREF cRef;
828 COLORMAP internalColorMap[4] =
829 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
831 /* initialize pointer to colortable and default color table */
832 if (lpColorMap) {
833 iMaps = iNumMaps;
834 sysColorMap = lpColorMap;
836 else {
837 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
838 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
839 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
840 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
841 iMaps = 4;
842 sysColorMap = internalColorMap;
845 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
846 if (hRsrc == 0)
847 return 0;
848 hglb = LoadResource (hInstance, hRsrc);
849 if (hglb == 0)
850 return 0;
851 lpBitmap = LockResource (hglb);
852 if (lpBitmap == NULL)
853 return 0;
855 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
856 nColorTableSize = lpBitmap->biClrUsed;
857 else if (lpBitmap->biBitCount <= 8)
858 nColorTableSize = (1 << lpBitmap->biBitCount);
859 else
860 nColorTableSize = 0;
861 nSize = lpBitmap->biSize;
862 if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
863 nSize += 3 * sizeof(DWORD);
864 nSize += nColorTableSize * sizeof(RGBQUAD);
865 lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
866 if (lpBitmapInfo == NULL)
867 return 0;
868 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
870 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
872 for (iColor = 0; iColor < nColorTableSize; iColor++) {
873 for (i = 0; i < iMaps; i++) {
874 cRef = RGB(pColorTable[iColor].rgbRed,
875 pColorTable[iColor].rgbGreen,
876 pColorTable[iColor].rgbBlue);
877 if ( cRef == sysColorMap[i].from) {
878 #if 0
879 if (wFlags & CBS_MASKED) {
880 if (sysColorMap[i].to != COLOR_BTNTEXT)
881 pColorTable[iColor] = RGB(255, 255, 255);
883 else
884 #endif
885 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
886 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
887 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
888 break;
892 nWidth = lpBitmapInfo->biWidth;
893 nHeight = lpBitmapInfo->biHeight;
894 hdcScreen = GetDC (NULL);
895 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
896 if (hbm) {
897 HDC hdcDst = CreateCompatibleDC (hdcScreen);
898 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
899 const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
900 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
901 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
902 SRCCOPY);
903 SelectObject (hdcDst, hbmOld);
904 DeleteDC (hdcDst);
906 ReleaseDC (NULL, hdcScreen);
907 GlobalFree (lpBitmapInfo);
908 FreeResource (hglb);
910 return hbm;
914 /***********************************************************************
915 * CreateToolbar [COMCTL32.7]
917 * Creates a toolbar control.
919 * PARAMS
920 * hwnd
921 * style
922 * wID
923 * nBitmaps
924 * hBMInst
925 * wBMID
926 * lpButtons
927 * iNumButtons
929 * RETURNS
930 * Success: handle to the tool bar control
931 * Failure: 0
933 * NOTES
934 * Do not use this function anymore. Use CreateToolbarEx instead.
937 HWND WINAPI
938 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
939 HINSTANCE hBMInst, UINT wBMID,
940 LPCTBBUTTON lpButtons,INT iNumButtons)
942 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
943 hBMInst, wBMID, lpButtons,
944 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
948 /***********************************************************************
949 * DllGetVersion [COMCTL32.@]
951 * Retrieves version information of the 'COMCTL32.DLL'
953 * PARAMS
954 * pdvi [O] pointer to version information structure.
956 * RETURNS
957 * Success: S_OK
958 * Failure: E_INVALIDARG
960 * NOTES
961 * Returns version of a comctl32.dll from IE4.01 SP1.
964 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
966 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
967 WARN("wrong DLLVERSIONINFO size from app\n");
968 return E_INVALIDARG;
971 pdvi->dwMajorVersion = COMCTL32_VERSION;
972 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
973 pdvi->dwBuildNumber = 2919;
974 pdvi->dwPlatformID = 6304;
976 TRACE("%u.%u.%u.%u\n",
977 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
978 pdvi->dwBuildNumber, pdvi->dwPlatformID);
980 return S_OK;
983 /***********************************************************************
984 * DllInstall (COMCTL32.@)
986 * Installs the ComCtl32 DLL.
988 * RETURNS
989 * Success: S_OK
990 * Failure: A HRESULT error
992 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
994 TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
995 return S_OK;
998 /***********************************************************************
999 * _TrackMouseEvent [COMCTL32.@]
1001 * Requests notification of mouse events
1003 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1004 * to the hwnd specified in the ptme structure. After the event message
1005 * is posted to the hwnd, the entry in the queue is removed.
1007 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1008 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1009 * immediately and the TME_LEAVE flag being ignored.
1011 * PARAMS
1012 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1014 * RETURNS
1015 * Success: non-zero
1016 * Failure: zero
1018 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1022 BOOL WINAPI
1023 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1025 return TrackMouseEvent (ptme);
1028 /*************************************************************************
1029 * GetMUILanguage [COMCTL32.@]
1031 * Returns the user interface language in use by the current process.
1033 * RETURNS
1034 * Language ID in use by the current process.
1036 LANGID WINAPI GetMUILanguage (VOID)
1038 return COMCTL32_uiLang;
1042 /*************************************************************************
1043 * InitMUILanguage [COMCTL32.@]
1045 * Sets the user interface language to be used by the current process.
1047 * RETURNS
1048 * Nothing.
1050 VOID WINAPI InitMUILanguage (LANGID uiLang)
1052 COMCTL32_uiLang = uiLang;
1056 /***********************************************************************
1057 * SetWindowSubclass [COMCTL32.410]
1059 * Starts a window subclass
1061 * PARAMS
1062 * hWnd [in] handle to window subclass.
1063 * pfnSubclass [in] Pointer to new window procedure.
1064 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1065 * dwRef [in] Reference data to pass to window procedure.
1067 * RETURNS
1068 * Success: non-zero
1069 * Failure: zero
1071 * BUGS
1072 * If an application manually subclasses a window after subclassing it with
1073 * this API and then with this API again, then none of the previous
1074 * subclasses get called or the original window procedure.
1077 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1078 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1080 LPSUBCLASS_INFO stack;
1081 LPSUBCLASSPROCS proc;
1083 TRACE ("(%p, %p, %lx, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1085 /* Since the window procedure that we set here has two additional arguments,
1086 * we can't simply set it as the new window procedure of the window. So we
1087 * set our own window procedure and then calculate the other two arguments
1088 * from there. */
1090 /* See if we have been called for this window */
1091 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1092 if (!stack) {
1093 /* allocate stack */
1094 stack = Alloc (sizeof(SUBCLASS_INFO));
1095 if (!stack) {
1096 ERR ("Failed to allocate our Subclassing stack\n");
1097 return FALSE;
1099 SetPropW (hWnd, COMCTL32_wSubclass, stack);
1101 /* set window procedure to our own and save the current one */
1102 if (IsWindowUnicode (hWnd))
1103 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1104 (DWORD_PTR)COMCTL32_SubclassProc);
1105 else
1106 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1107 (DWORD_PTR)COMCTL32_SubclassProc);
1109 else {
1110 /* Check to see if we have called this function with the same uIDSubClass
1111 * and pfnSubclass */
1112 proc = stack->SubclassProcs;
1113 while (proc) {
1114 if ((proc->id == uIDSubclass) &&
1115 (proc->subproc == pfnSubclass)) {
1116 proc->ref = dwRef;
1117 return TRUE;
1119 proc = proc->next;
1123 proc = Alloc(sizeof(SUBCLASSPROCS));
1124 if (!proc) {
1125 ERR ("Failed to allocate subclass entry in stack\n");
1126 if (IsWindowUnicode (hWnd))
1127 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1128 else
1129 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1130 Free (stack);
1131 RemovePropW( hWnd, COMCTL32_wSubclass );
1132 return FALSE;
1135 proc->subproc = pfnSubclass;
1136 proc->ref = dwRef;
1137 proc->id = uIDSubclass;
1138 proc->next = stack->SubclassProcs;
1139 stack->SubclassProcs = proc;
1141 return TRUE;
1145 /***********************************************************************
1146 * GetWindowSubclass [COMCTL32.411]
1148 * Gets the Reference data from a subclass.
1150 * PARAMS
1151 * hWnd [in] Handle to the window which we are subclassing
1152 * pfnSubclass [in] Pointer to the subclass procedure
1153 * uID [in] Unique identifier of the subclassing procedure
1154 * pdwRef [out] Pointer to the reference data
1156 * RETURNS
1157 * Success: Non-zero
1158 * Failure: 0
1161 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1162 UINT_PTR uID, DWORD_PTR *pdwRef)
1164 const SUBCLASS_INFO *stack;
1165 const SUBCLASSPROCS *proc;
1167 TRACE ("(%p, %p, %lx, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1169 /* See if we have been called for this window */
1170 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1171 if (!stack)
1172 return FALSE;
1174 proc = stack->SubclassProcs;
1175 while (proc) {
1176 if ((proc->id == uID) &&
1177 (proc->subproc == pfnSubclass)) {
1178 *pdwRef = proc->ref;
1179 return TRUE;
1181 proc = proc->next;
1184 return FALSE;
1188 /***********************************************************************
1189 * RemoveWindowSubclass [COMCTL32.412]
1191 * Removes a window subclass.
1193 * PARAMS
1194 * hWnd [in] Handle to the window which we are subclassing
1195 * pfnSubclass [in] Pointer to the subclass procedure
1196 * uID [in] Unique identifier of this subclass
1198 * RETURNS
1199 * Success: non-zero
1200 * Failure: zero
1203 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1205 LPSUBCLASS_INFO stack;
1206 LPSUBCLASSPROCS prevproc = NULL;
1207 LPSUBCLASSPROCS proc;
1208 BOOL ret = FALSE;
1210 TRACE ("(%p, %p, %lx)\n", hWnd, pfnSubclass, uID);
1212 /* Find the Subclass to remove */
1213 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1214 if (!stack)
1215 return FALSE;
1217 proc = stack->SubclassProcs;
1218 while (proc) {
1219 if ((proc->id == uID) &&
1220 (proc->subproc == pfnSubclass)) {
1222 if (!prevproc)
1223 stack->SubclassProcs = proc->next;
1224 else
1225 prevproc->next = proc->next;
1227 if (stack->stackpos == proc)
1228 stack->stackpos = stack->stackpos->next;
1230 Free (proc);
1231 ret = TRUE;
1232 break;
1234 prevproc = proc;
1235 proc = proc->next;
1238 if (!stack->SubclassProcs && !stack->running) {
1239 TRACE("Last Subclass removed, cleaning up\n");
1240 /* clean up our heap and reset the original window procedure */
1241 if (IsWindowUnicode (hWnd))
1242 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1243 else
1244 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1245 Free (stack);
1246 RemovePropW( hWnd, COMCTL32_wSubclass );
1249 return ret;
1252 /***********************************************************************
1253 * COMCTL32_SubclassProc (internal)
1255 * Window procedure for all subclassed windows.
1256 * Saves the current subclassing stack position to support nested messages
1258 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1260 LPSUBCLASS_INFO stack;
1261 LPSUBCLASSPROCS proc;
1262 LRESULT ret;
1264 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1266 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1267 if (!stack) {
1268 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1269 return 0;
1272 /* Save our old stackpos to properly handle nested messages */
1273 proc = stack->stackpos;
1274 stack->stackpos = stack->SubclassProcs;
1275 stack->running++;
1276 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1277 stack->running--;
1278 stack->stackpos = proc;
1280 if (!stack->SubclassProcs && !stack->running) {
1281 TRACE("Last Subclass removed, cleaning up\n");
1282 /* clean up our heap and reset the original window procedure */
1283 if (IsWindowUnicode (hWnd))
1284 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1285 else
1286 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1287 Free (stack);
1288 RemovePropW( hWnd, COMCTL32_wSubclass );
1290 return ret;
1293 /***********************************************************************
1294 * DefSubclassProc [COMCTL32.413]
1296 * Calls the next window procedure (i.e. the one before this subclass)
1298 * PARAMS
1299 * hWnd [in] The window that we're subclassing
1300 * uMsg [in] Message
1301 * wParam [in] WPARAM
1302 * lParam [in] LPARAM
1304 * RETURNS
1305 * Success: non-zero
1306 * Failure: zero
1309 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1311 LPSUBCLASS_INFO stack;
1312 LRESULT ret;
1314 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1316 /* retrieve our little stack from the Properties */
1317 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1318 if (!stack) {
1319 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1320 return 0;
1323 /* If we are at the end of stack then we have to call the original
1324 * window procedure */
1325 if (!stack->stackpos) {
1326 if (IsWindowUnicode (hWnd))
1327 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1328 else
1329 ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1330 } else {
1331 const SUBCLASSPROCS *proc = stack->stackpos;
1332 stack->stackpos = stack->stackpos->next;
1333 /* call the Subclass procedure from the stack */
1334 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1335 proc->id, proc->ref);
1338 return ret;
1342 /***********************************************************************
1343 * COMCTL32_CreateToolTip [NOT AN API]
1345 * Creates a tooltip for the control specified in hwnd and does all
1346 * necessary setup and notifications.
1348 * PARAMS
1349 * hwndOwner [I] Handle to the window that will own the tool tip.
1351 * RETURNS
1352 * Success: Handle of tool tip window.
1353 * Failure: NULL
1356 HWND
1357 COMCTL32_CreateToolTip(HWND hwndOwner)
1359 HWND hwndToolTip;
1361 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1362 CW_USEDEFAULT, CW_USEDEFAULT,
1363 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1364 0, 0, 0);
1366 /* Send NM_TOOLTIPSCREATED notification */
1367 if (hwndToolTip)
1369 NMTOOLTIPSCREATED nmttc;
1370 /* true owner can be different if hwndOwner is a child window */
1371 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1372 nmttc.hdr.hwndFrom = hwndTrueOwner;
1373 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1374 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1375 nmttc.hwndToolTips = hwndToolTip;
1377 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1378 GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
1381 return hwndToolTip;
1385 /***********************************************************************
1386 * COMCTL32_RefreshSysColors [NOT AN API]
1388 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1389 * refresh the color values in the color structure
1391 * PARAMS
1392 * none
1394 * RETURNS
1395 * none
1398 VOID
1399 COMCTL32_RefreshSysColors(void)
1401 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1402 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1403 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1404 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1405 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1406 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1407 comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1408 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1409 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1410 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1411 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1412 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1413 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1414 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1415 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1416 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1417 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1420 /***********************************************************************
1421 * COMCTL32_DrawInsertMark [NOT AN API]
1423 * Draws an insertion mark (which looks similar to an 'I').
1425 * PARAMS
1426 * hDC [I] Device context to draw onto.
1427 * lpRect [I] Co-ordinates of insertion mark.
1428 * clrInsertMark [I] Colour of the insertion mark.
1429 * bHorizontal [I] True if insert mark should be drawn horizontally,
1430 * vertical otherwise.
1432 * RETURNS
1433 * none
1435 * NOTES
1436 * Draws up to but not including the bottom co-ordinate when drawing
1437 * vertically or the right co-ordinate when horizontal.
1439 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1441 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1442 HPEN hOldPen;
1443 static const DWORD adwPolyPoints[] = {4,4,4};
1444 LONG lCentre = (bHorizontal ?
1445 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1446 lpRect->left + (lpRect->right - lpRect->left)/2);
1447 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1448 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1449 const POINT aptInsertMark[] =
1451 /* top (V) or left (H) arrow */
1452 {lCentre , l1 + 2},
1453 {lCentre - 2, l1 },
1454 {lCentre + 3, l1 },
1455 {lCentre + 1, l1 + 2},
1456 /* middle line */
1457 {lCentre , l2 - 2},
1458 {lCentre , l1 - 1},
1459 {lCentre + 1, l1 - 1},
1460 {lCentre + 1, l2 - 2},
1461 /* bottom (V) or right (H) arrow */
1462 {lCentre , l2 - 3},
1463 {lCentre - 2, l2 - 1},
1464 {lCentre + 3, l2 - 1},
1465 {lCentre + 1, l2 - 3},
1467 hOldPen = SelectObject(hDC, hPen);
1468 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, ARRAY_SIZE(adwPolyPoints));
1469 SelectObject(hDC, hOldPen);
1470 DeleteObject(hPen);
1473 /***********************************************************************
1474 * COMCTL32_EnsureBitmapSize [internal]
1476 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1477 * the height is at least cyMinHeight. If the bitmap already has these
1478 * dimensions nothing changes.
1480 * PARAMS
1481 * hBitmap [I/O] Bitmap to modify. The handle may change
1482 * cxMinWidth [I] If the width of the bitmap is smaller, then it will
1483 * be enlarged to this value
1484 * cyMinHeight [I] If the height of the bitmap is smaller, then it will
1485 * be enlarged to this value
1486 * cyBackground [I] The color with which the new area will be filled
1488 * RETURNS
1489 * none
1491 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1493 int cxNew, cyNew;
1494 BITMAP bmp;
1495 HBITMAP hNewBitmap;
1496 HBITMAP hNewDCBitmap, hOldDCBitmap;
1497 HBRUSH hNewDCBrush;
1498 HDC hdcNew, hdcOld;
1500 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1501 return;
1502 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1503 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1504 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1505 return;
1507 hdcNew = CreateCompatibleDC(NULL);
1508 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1509 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1510 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1512 hdcOld = CreateCompatibleDC(NULL);
1513 hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1515 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1516 if (bmp.bmWidth < cxMinWidth)
1517 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1518 if (bmp.bmHeight < cyMinHeight)
1519 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1520 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1521 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1523 SelectObject(hdcNew, hNewDCBitmap);
1524 DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1525 DeleteDC(hdcNew);
1526 SelectObject(hdcOld, hOldDCBitmap);
1527 DeleteDC(hdcOld);
1529 DeleteObject(*pBitmap);
1530 *pBitmap = hNewBitmap;
1531 return;
1534 void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
1536 HDC hdc = GetDC(NULL);
1537 HFONT hOldFont;
1539 hOldFont = SelectObject(hdc, hFont);
1540 GetTextMetricsW(hdc, ptm);
1541 SelectObject(hdc, hOldFont);
1542 ReleaseDC(NULL, hdc);
1545 #ifndef OCM__BASE /* avoid including olectl.h */
1546 #define OCM__BASE (WM_USER+0x1c00)
1547 #endif
1549 /***********************************************************************
1550 * COMCTL32_IsReflectedMessage [internal]
1552 * Some parents reflect notify messages - for some messages sent by the child,
1553 * they send it back with the message code increased by OCM__BASE (0x2000).
1554 * This allows better subclassing of controls. We don't need to handle such
1555 * messages but we don't want to print ERRs for them, so this helper function
1556 * identifies them.
1558 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1559 * collision with defined CCM_ codes.
1561 BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
1563 switch (uMsg)
1565 case OCM__BASE + WM_COMMAND:
1566 case OCM__BASE + WM_CTLCOLORBTN:
1567 case OCM__BASE + WM_CTLCOLOREDIT:
1568 case OCM__BASE + WM_CTLCOLORDLG:
1569 case OCM__BASE + WM_CTLCOLORLISTBOX:
1570 case OCM__BASE + WM_CTLCOLORMSGBOX:
1571 case OCM__BASE + WM_CTLCOLORSCROLLBAR:
1572 case OCM__BASE + WM_CTLCOLORSTATIC:
1573 case OCM__BASE + WM_DRAWITEM:
1574 case OCM__BASE + WM_MEASUREITEM:
1575 case OCM__BASE + WM_DELETEITEM:
1576 case OCM__BASE + WM_VKEYTOITEM:
1577 case OCM__BASE + WM_CHARTOITEM:
1578 case OCM__BASE + WM_COMPAREITEM:
1579 case OCM__BASE + WM_HSCROLL:
1580 case OCM__BASE + WM_VSCROLL:
1581 case OCM__BASE + WM_PARENTNOTIFY:
1582 case OCM__BASE + WM_NOTIFY:
1583 return TRUE;
1584 default:
1585 return FALSE;
1589 /***********************************************************************
1590 * MirrorIcon [COMCTL32.414]
1592 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1594 * PARAMS
1595 * phicon1 [I/O] Icon.
1596 * phicon2 [I/O] Icon.
1598 * RETURNS
1599 * Success: TRUE.
1600 * Failure: FALSE.
1602 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1604 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1605 return FALSE;
1608 static inline BOOL IsDelimiter(WCHAR c)
1610 switch(c)
1612 case '/':
1613 case '\\':
1614 case '.':
1615 case ' ':
1616 return TRUE;
1618 return FALSE;
1621 static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1623 if (code == WB_ISDELIMITER)
1624 return IsDelimiter(lpch[ichCurrent]);
1625 else
1627 int dir = (code == WB_LEFT) ? -1 : 1;
1628 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1629 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1631 return ichCurrent;
1634 /***********************************************************************
1635 * SetPathWordBreakProc [COMCTL32.384]
1637 * Sets the word break procedure for an edit control to one that understands
1638 * paths so that the user can jump over directories.
1640 * PARAMS
1641 * hwnd [I] Handle to edit control.
1642 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1644 * RETURNS
1645 * Result from EM_SETWORDBREAKPROC message.
1647 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1649 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1650 (LPARAM)(bSet ? PathWordBreakProc : NULL));
1653 /***********************************************************************
1654 * DrawShadowText [COMCTL32.@]
1656 * Draw text with shadow.
1658 int WINAPI DrawShadowText(HDC hdc, LPCWSTR text, UINT length, RECT *rect, DWORD flags,
1659 COLORREF crText, COLORREF crShadow, int offset_x, int offset_y)
1661 int bkmode, ret;
1662 COLORREF clr;
1663 RECT r;
1665 FIXME("(%p, %s, %d, %p, 0x%08x, 0x%08x, 0x%08x, %d, %d): semi-stub\n", hdc, debugstr_w(text),
1666 length, rect, flags, crText, crShadow, offset_x, offset_y);
1668 bkmode = SetBkMode(hdc, TRANSPARENT);
1669 clr = SetTextColor(hdc, crShadow);
1671 /* FIXME: for shadow we need to render normally, blur it, and blend with current background. */
1672 r = *rect;
1673 OffsetRect(&r, 1, 1);
1674 DrawTextW(hdc, text, length, &r, flags);
1676 SetTextColor(hdc, crText);
1678 /* with text color on top of a shadow */
1679 ret = DrawTextW(hdc, text, length, rect, flags);
1681 SetTextColor(hdc, clr);
1682 SetBkMode(hdc, bkmode);
1684 return ret;
1687 /***********************************************************************
1688 * LoadIconWithScaleDown [COMCTL32.@]
1690 HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
1692 TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
1694 *icon = NULL;
1696 if (!name)
1697 return E_INVALIDARG;
1699 *icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
1700 (hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
1701 if (!*icon)
1702 return HRESULT_FROM_WIN32(GetLastError());
1704 return S_OK;
1707 /***********************************************************************
1708 * LoadIconMetric [COMCTL32.@]
1710 HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
1712 int cx, cy;
1714 TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
1716 if (size == LIM_SMALL)
1718 cx = GetSystemMetrics(SM_CXSMICON);
1719 cy = GetSystemMetrics(SM_CYSMICON);
1721 else if (size == LIM_LARGE)
1723 cx = GetSystemMetrics(SM_CXICON);
1724 cy = GetSystemMetrics(SM_CYICON);
1726 else
1728 *icon = NULL;
1729 return E_INVALIDARG;
1732 return LoadIconWithScaleDown(hinst, name, cx, cy, icon);