include: Use the hard-float calling convention for Windows APIs on ARM
[wine.git] / dlls / comctl32 / commctrl.c
blobd3ba314c4785c52c5def47fd40ff8db16e9aaecb
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"
73 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
76 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
78 static LPWSTR COMCTL32_wSubclass = NULL;
79 HMODULE COMCTL32_hModule = 0;
80 static LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
81 HBRUSH COMCTL32_hPattern55AABrush = NULL;
82 COMCTL32_SysColor comctl32_color;
84 static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
86 static const WORD wPattern55AA[] =
88 0x5555, 0xaaaa, 0x5555, 0xaaaa,
89 0x5555, 0xaaaa, 0x5555, 0xaaaa
92 static const WCHAR strCC32SubclassInfo[] = {
93 'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
97 /***********************************************************************
98 * DllMain [Internal]
100 * Initializes the internal 'COMCTL32.DLL'.
102 * PARAMS
103 * hinstDLL [I] handle to the 'dlls' instance
104 * fdwReason [I]
105 * lpvReserved [I] reserved, must be NULL
107 * RETURNS
108 * Success: TRUE
109 * Failure: FALSE
112 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
114 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
116 switch (fdwReason) {
117 case DLL_PROCESS_ATTACH:
118 DisableThreadLibraryCalls(hinstDLL);
120 COMCTL32_hModule = hinstDLL;
122 /* add global subclassing atom (used by 'tooltip' and 'updown') */
123 COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
124 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
126 /* create local pattern brush */
127 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
128 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
130 /* Get all the colors at DLL load */
131 COMCTL32_RefreshSysColors();
133 /* like comctl32 5.82+ register all the common control classes */
134 ANIMATE_Register ();
135 COMBOEX_Register ();
136 DATETIME_Register ();
137 FLATSB_Register ();
138 HEADER_Register ();
139 HOTKEY_Register ();
140 IPADDRESS_Register ();
141 LISTVIEW_Register ();
142 MONTHCAL_Register ();
143 NATIVEFONT_Register ();
144 PAGER_Register ();
145 PROGRESS_Register ();
146 REBAR_Register ();
147 STATUS_Register ();
148 SYSLINK_Register ();
149 TAB_Register ();
150 TOOLBAR_Register ();
151 TOOLTIPS_Register ();
152 TRACKBAR_Register ();
153 TREEVIEW_Register ();
154 UPDOWN_Register ();
156 /* subclass user32 controls */
157 THEMING_Initialize ();
158 break;
160 case DLL_PROCESS_DETACH:
161 if (lpvReserved) break;
162 /* clean up subclassing */
163 THEMING_Uninitialize();
165 /* unregister all common control classes */
166 ANIMATE_Unregister ();
167 COMBOEX_Unregister ();
168 DATETIME_Unregister ();
169 FLATSB_Unregister ();
170 HEADER_Unregister ();
171 HOTKEY_Unregister ();
172 IPADDRESS_Unregister ();
173 LISTVIEW_Unregister ();
174 MONTHCAL_Unregister ();
175 NATIVEFONT_Unregister ();
176 PAGER_Unregister ();
177 PROGRESS_Unregister ();
178 REBAR_Unregister ();
179 STATUS_Unregister ();
180 SYSLINK_Unregister ();
181 TAB_Unregister ();
182 TOOLBAR_Unregister ();
183 TOOLTIPS_Unregister ();
184 TRACKBAR_Unregister ();
185 TREEVIEW_Unregister ();
186 UPDOWN_Unregister ();
188 /* delete local pattern brush */
189 DeleteObject (COMCTL32_hPattern55AABrush);
190 DeleteObject (COMCTL32_hPattern55AABitmap);
192 /* delete global subclassing atom */
193 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
194 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
195 break;
198 return TRUE;
202 /***********************************************************************
203 * MenuHelp [COMCTL32.2]
205 * Handles the setting of status bar help messages when the user
206 * selects menu items.
208 * PARAMS
209 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
210 * wParam [I] wParam of the message uMsg
211 * lParam [I] lParam of the message uMsg
212 * hMainMenu [I] handle to the application's main menu
213 * hInst [I] handle to the module that contains string resources
214 * hwndStatus [I] handle to the status bar window
215 * lpwIDs [I] pointer to an array of integers (see NOTES)
217 * RETURNS
218 * No return value
220 * NOTES
221 * The official documentation is incomplete!
222 * This is the correct documentation:
224 * uMsg:
225 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
226 * WM_MENUSELECT messages.
228 * lpwIDs:
229 * (will be written ...)
232 VOID WINAPI
233 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
234 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
236 UINT uMenuID = 0;
238 if (!IsWindow (hwndStatus))
239 return;
241 switch (uMsg) {
242 case WM_MENUSELECT:
243 TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
244 wParam, lParam);
246 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
247 /* menu was closed */
248 TRACE("menu was closed!\n");
249 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
251 else {
252 /* menu item was selected */
253 if (HIWORD(wParam) & MF_POPUP)
254 uMenuID = *(lpwIDs+1);
255 else
256 uMenuID = (UINT)LOWORD(wParam);
257 TRACE("uMenuID = %u\n", uMenuID);
259 if (uMenuID) {
260 WCHAR szText[256];
262 if (!LoadStringW (hInst, uMenuID, szText, sizeof(szText)/sizeof(szText[0])))
263 szText[0] = '\0';
265 SendMessageW (hwndStatus, SB_SETTEXTW,
266 255 | SBT_NOBORDERS, (LPARAM)szText);
267 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
270 break;
272 case WM_COMMAND :
273 TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
274 wParam, lParam);
275 /* WM_COMMAND is not invalid since it is documented
276 * in the windows api reference. So don't output
277 * any FIXME for WM_COMMAND
279 WARN("We don't care about the WM_COMMAND\n");
280 break;
282 default:
283 FIXME("Invalid Message 0x%x!\n", uMsg);
284 break;
289 /***********************************************************************
290 * ShowHideMenuCtl [COMCTL32.3]
292 * Shows or hides controls and updates the corresponding menu item.
294 * PARAMS
295 * hwnd [I] handle to the client window.
296 * uFlags [I] menu command id.
297 * lpInfo [I] pointer to an array of integers. (See NOTES.)
299 * RETURNS
300 * Success: TRUE
301 * Failure: FALSE
303 * NOTES
304 * The official documentation is incomplete!
305 * This is the correct documentation:
307 * hwnd
308 * Handle to the window that contains the menu and controls.
310 * uFlags
311 * Identifier of the menu item to receive or lose a check mark.
313 * lpInfo
314 * The array of integers contains pairs of values. BOTH values of
315 * the first pair must be the handles to the application's main menu.
316 * Each subsequent pair consists of a menu id and control id.
319 BOOL WINAPI
320 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
322 LPINT lpMenuId;
324 TRACE("%p, %lx, %p\n", hwnd, uFlags, lpInfo);
326 if (lpInfo == NULL)
327 return FALSE;
329 if (!(lpInfo[0]) || !(lpInfo[1]))
330 return FALSE;
332 /* search for control */
333 lpMenuId = &lpInfo[2];
334 while (*lpMenuId != uFlags)
335 lpMenuId += 2;
337 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
338 /* uncheck menu item */
339 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
341 /* hide control */
342 lpMenuId++;
343 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
344 SWP_HIDEWINDOW);
346 else {
347 /* check menu item */
348 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
350 /* show control */
351 lpMenuId++;
352 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
353 SWP_SHOWWINDOW);
356 return TRUE;
360 /***********************************************************************
361 * GetEffectiveClientRect [COMCTL32.4]
363 * Calculates the coordinates of a rectangle in the client area.
365 * PARAMS
366 * hwnd [I] handle to the client window.
367 * lpRect [O] pointer to the rectangle of the client window
368 * lpInfo [I] pointer to an array of integers (see NOTES)
370 * RETURNS
371 * No return value.
373 * NOTES
374 * The official documentation is incomplete!
375 * This is the correct documentation:
377 * lpInfo
378 * (will be written ...)
381 VOID WINAPI
382 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
384 RECT rcCtrl;
385 const INT *lpRun;
386 HWND hwndCtrl;
388 TRACE("(%p %p %p)\n",
389 hwnd, lpRect, lpInfo);
391 GetClientRect (hwnd, lpRect);
392 lpRun = lpInfo;
394 do {
395 lpRun += 2;
396 if (*lpRun == 0)
397 return;
398 lpRun++;
399 hwndCtrl = GetDlgItem (hwnd, *lpRun);
400 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
401 TRACE("control id 0x%x\n", *lpRun);
402 GetWindowRect (hwndCtrl, &rcCtrl);
403 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
404 SubtractRect (lpRect, lpRect, &rcCtrl);
406 lpRun++;
407 } while (*lpRun);
411 /***********************************************************************
412 * DrawStatusTextW [COMCTL32.@]
414 * Draws text with borders, like in a status bar.
416 * PARAMS
417 * hdc [I] handle to the window's display context
418 * lprc [I] pointer to a rectangle
419 * text [I] pointer to the text
420 * style [I] drawing style
422 * RETURNS
423 * No return value.
425 * NOTES
426 * The style variable can have one of the following values:
427 * (will be written ...)
430 void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
432 RECT r = *lprc;
433 UINT border = BDR_SUNKENOUTER;
435 if (style & SBT_POPOUT)
436 border = BDR_RAISEDOUTER;
437 else if (style & SBT_NOBORDERS)
438 border = 0;
440 DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
442 /* now draw text */
443 if (text) {
444 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
445 UINT align = DT_LEFT;
446 int strCnt = 0;
448 if (style & SBT_RTLREADING)
449 FIXME("Unsupported RTL style!\n");
450 r.left += 3;
451 do {
452 if (*text == '\t') {
453 if (strCnt) {
454 DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
455 strCnt = 0;
457 if (align==DT_RIGHT) {
458 break;
460 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
461 } else {
462 strCnt++;
464 } while(*text++);
466 if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
467 SetBkMode(hdc, oldbkmode);
472 /***********************************************************************
473 * DrawStatusText [COMCTL32.@]
474 * DrawStatusTextA [COMCTL32.5]
476 * Draws text with borders, like in a status bar.
478 * PARAMS
479 * hdc [I] handle to the window's display context
480 * lprc [I] pointer to a rectangle
481 * text [I] pointer to the text
482 * style [I] drawing style
484 * RETURNS
485 * No return value.
488 void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
490 INT len;
491 LPWSTR textW = NULL;
493 if ( text ) {
494 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
495 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
496 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
499 DrawStatusTextW( hdc, lprc, textW, style );
500 Free( textW );
504 /***********************************************************************
505 * CreateStatusWindow [COMCTL32.@]
506 * CreateStatusWindowA [COMCTL32.6]
508 * Creates a status bar
510 * PARAMS
511 * style [I] window style
512 * text [I] pointer to the window text
513 * parent [I] handle to the parent window
514 * wid [I] control id of the status bar
516 * RETURNS
517 * Success: handle to the status window
518 * Failure: 0
521 HWND WINAPI
522 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
524 return CreateWindowA(STATUSCLASSNAMEA, text, style,
525 CW_USEDEFAULT, CW_USEDEFAULT,
526 CW_USEDEFAULT, CW_USEDEFAULT,
527 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
531 /***********************************************************************
532 * CreateStatusWindowW [COMCTL32.@]
534 * Creates a status bar control
536 * PARAMS
537 * style [I] window style
538 * text [I] pointer to the window text
539 * parent [I] handle to the parent window
540 * wid [I] control id of the status bar
542 * RETURNS
543 * Success: handle to the status window
544 * Failure: 0
547 HWND WINAPI
548 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
550 return CreateWindowW(STATUSCLASSNAMEW, text, style,
551 CW_USEDEFAULT, CW_USEDEFAULT,
552 CW_USEDEFAULT, CW_USEDEFAULT,
553 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
557 /***********************************************************************
558 * CreateUpDownControl [COMCTL32.16]
560 * Creates an up-down control
562 * PARAMS
563 * style [I] window styles
564 * x [I] horizontal position of the control
565 * y [I] vertical position of the control
566 * cx [I] with of the control
567 * cy [I] height of the control
568 * parent [I] handle to the parent window
569 * id [I] the control's identifier
570 * inst [I] handle to the application's module instance
571 * buddy [I] handle to the buddy window, can be NULL
572 * maxVal [I] upper limit of the control
573 * minVal [I] lower limit of the control
574 * curVal [I] current value of the control
576 * RETURNS
577 * Success: handle to the updown control
578 * Failure: 0
581 HWND WINAPI
582 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
583 HWND parent, INT id, HINSTANCE inst,
584 HWND buddy, INT maxVal, INT minVal, INT curVal)
586 HWND hUD =
587 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
588 parent, (HMENU)(DWORD_PTR)id, inst, 0);
589 if (hUD) {
590 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
591 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
592 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
595 return hUD;
599 /***********************************************************************
600 * InitCommonControls [COMCTL32.17]
602 * Registers the common controls.
604 * PARAMS
605 * No parameters.
607 * RETURNS
608 * No return values.
610 * NOTES
611 * This function is just a dummy - all the controls are registered at
612 * the DLL initialization time. See InitCommonContolsEx for details.
615 VOID WINAPI
616 InitCommonControls (void)
621 /***********************************************************************
622 * InitCommonControlsEx [COMCTL32.@]
624 * Registers the common controls.
626 * PARAMS
627 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
629 * RETURNS
630 * Success: TRUE
631 * Failure: FALSE
633 * NOTES
634 * Probably all versions of comctl32 initializes the Win95 controls in DllMain
635 * during DLL initialization. Starting from comctl32 v5.82 all the controls
636 * are initialized there. We follow this behaviour and this function is just
637 * a dummy.
639 * Note: when writing programs under Windows, if you don't call any function
640 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
641 * was the only comctl32 function you were calling and you remove it you may
642 * have a false impression that InitCommonControlsEx actually did something.
645 BOOL WINAPI
646 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
648 if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
649 return FALSE;
651 TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
652 return TRUE;
656 /***********************************************************************
657 * CreateToolbarEx [COMCTL32.@]
659 * Creates a toolbar window.
661 * PARAMS
662 * hwnd
663 * style
664 * wID
665 * nBitmaps
666 * hBMInst
667 * wBMID
668 * lpButtons
669 * iNumButtons
670 * dxButton
671 * dyButton
672 * dxBitmap
673 * dyBitmap
674 * uStructSize
676 * RETURNS
677 * Success: handle to the tool bar control
678 * Failure: 0
681 HWND WINAPI
682 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
683 HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
684 INT iNumButtons, INT dxButton, INT dyButton,
685 INT dxBitmap, INT dyBitmap, UINT uStructSize)
687 HWND hwndTB;
689 hwndTB =
690 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
691 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
692 if(hwndTB) {
693 TBADDBITMAP tbab;
695 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
697 /* set bitmap and button size */
698 /*If CreateToolbarEx receives 0, windows sets default values*/
699 if (dxBitmap < 0)
700 dxBitmap = 16;
701 if (dyBitmap < 0)
702 dyBitmap = 16;
703 if (dxBitmap == 0 || dyBitmap == 0)
704 dxBitmap = dyBitmap = 16;
705 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
707 if (dxButton < 0)
708 dxButton = dxBitmap;
709 if (dyButton < 0)
710 dyButton = dyBitmap;
711 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
712 if (dxButton != 0 && dyButton != 0)
713 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
716 /* add bitmaps */
717 if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
719 tbab.hInst = hBMInst;
720 tbab.nID = wBMID;
722 SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
724 /* add buttons */
725 if(iNumButtons > 0)
726 SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
729 return hwndTB;
733 /***********************************************************************
734 * CreateMappedBitmap [COMCTL32.8]
736 * Loads a bitmap resource using a colour map.
738 * PARAMS
739 * hInstance [I] Handle to the module containing the bitmap.
740 * idBitmap [I] The bitmap resource ID.
741 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
742 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
743 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
745 * RETURNS
746 * Success: handle to the new bitmap
747 * Failure: 0
750 HBITMAP WINAPI
751 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
752 LPCOLORMAP lpColorMap, INT iNumMaps)
754 HGLOBAL hglb;
755 HRSRC hRsrc;
756 const BITMAPINFOHEADER *lpBitmap;
757 LPBITMAPINFOHEADER lpBitmapInfo;
758 UINT nSize, nColorTableSize, iColor;
759 RGBQUAD *pColorTable;
760 INT i, iMaps, nWidth, nHeight;
761 HDC hdcScreen;
762 HBITMAP hbm;
763 LPCOLORMAP sysColorMap;
764 COLORREF cRef;
765 COLORMAP internalColorMap[4] =
766 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
768 /* initialize pointer to colortable and default color table */
769 if (lpColorMap) {
770 iMaps = iNumMaps;
771 sysColorMap = lpColorMap;
773 else {
774 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
775 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
776 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
777 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
778 iMaps = 4;
779 sysColorMap = internalColorMap;
782 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
783 if (hRsrc == 0)
784 return 0;
785 hglb = LoadResource (hInstance, hRsrc);
786 if (hglb == 0)
787 return 0;
788 lpBitmap = LockResource (hglb);
789 if (lpBitmap == NULL)
790 return 0;
792 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
793 nColorTableSize = lpBitmap->biClrUsed;
794 else if (lpBitmap->biBitCount <= 8)
795 nColorTableSize = (1 << lpBitmap->biBitCount);
796 else
797 nColorTableSize = 0;
798 nSize = lpBitmap->biSize;
799 if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
800 nSize += 3 * sizeof(DWORD);
801 nSize += nColorTableSize * sizeof(RGBQUAD);
802 lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
803 if (lpBitmapInfo == NULL)
804 return 0;
805 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
807 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
809 for (iColor = 0; iColor < nColorTableSize; iColor++) {
810 for (i = 0; i < iMaps; i++) {
811 cRef = RGB(pColorTable[iColor].rgbRed,
812 pColorTable[iColor].rgbGreen,
813 pColorTable[iColor].rgbBlue);
814 if ( cRef == sysColorMap[i].from) {
815 #if 0
816 if (wFlags & CBS_MASKED) {
817 if (sysColorMap[i].to != COLOR_BTNTEXT)
818 pColorTable[iColor] = RGB(255, 255, 255);
820 else
821 #endif
822 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
823 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
824 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
825 break;
829 nWidth = lpBitmapInfo->biWidth;
830 nHeight = lpBitmapInfo->biHeight;
831 hdcScreen = GetDC (NULL);
832 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
833 if (hbm) {
834 HDC hdcDst = CreateCompatibleDC (hdcScreen);
835 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
836 const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
837 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
838 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
839 SRCCOPY);
840 SelectObject (hdcDst, hbmOld);
841 DeleteDC (hdcDst);
843 ReleaseDC (NULL, hdcScreen);
844 GlobalFree (lpBitmapInfo);
845 FreeResource (hglb);
847 return hbm;
851 /***********************************************************************
852 * CreateToolbar [COMCTL32.7]
854 * Creates a toolbar control.
856 * PARAMS
857 * hwnd
858 * style
859 * wID
860 * nBitmaps
861 * hBMInst
862 * wBMID
863 * lpButtons
864 * iNumButtons
866 * RETURNS
867 * Success: handle to the tool bar control
868 * Failure: 0
870 * NOTES
871 * Do not use this function anymore. Use CreateToolbarEx instead.
874 HWND WINAPI
875 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
876 HINSTANCE hBMInst, UINT wBMID,
877 LPCTBBUTTON lpButtons,INT iNumButtons)
879 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
880 hBMInst, wBMID, lpButtons,
881 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
885 /***********************************************************************
886 * DllGetVersion [COMCTL32.@]
888 * Retrieves version information of the 'COMCTL32.DLL'
890 * PARAMS
891 * pdvi [O] pointer to version information structure.
893 * RETURNS
894 * Success: S_OK
895 * Failure: E_INVALIDARG
897 * NOTES
898 * Returns version of a comctl32.dll from IE4.01 SP1.
901 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
903 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
904 WARN("wrong DLLVERSIONINFO size from app\n");
905 return E_INVALIDARG;
908 pdvi->dwMajorVersion = COMCTL32_VERSION;
909 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
910 pdvi->dwBuildNumber = 2919;
911 pdvi->dwPlatformID = 6304;
913 TRACE("%u.%u.%u.%u\n",
914 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
915 pdvi->dwBuildNumber, pdvi->dwPlatformID);
917 return S_OK;
920 /***********************************************************************
921 * DllInstall (COMCTL32.@)
923 * Installs the ComCtl32 DLL.
925 * RETURNS
926 * Success: S_OK
927 * Failure: A HRESULT error
929 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
931 TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
932 return S_OK;
935 /***********************************************************************
936 * _TrackMouseEvent [COMCTL32.@]
938 * Requests notification of mouse events
940 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
941 * to the hwnd specified in the ptme structure. After the event message
942 * is posted to the hwnd, the entry in the queue is removed.
944 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
945 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
946 * immediately and the TME_LEAVE flag being ignored.
948 * PARAMS
949 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
951 * RETURNS
952 * Success: non-zero
953 * Failure: zero
955 * IMPLEMENTATION moved to USER32.TrackMouseEvent
959 BOOL WINAPI
960 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
962 return TrackMouseEvent (ptme);
965 /*************************************************************************
966 * GetMUILanguage [COMCTL32.@]
968 * Returns the user interface language in use by the current process.
970 * RETURNS
971 * Language ID in use by the current process.
973 LANGID WINAPI GetMUILanguage (VOID)
975 return COMCTL32_uiLang;
979 /*************************************************************************
980 * InitMUILanguage [COMCTL32.@]
982 * Sets the user interface language to be used by the current process.
984 * RETURNS
985 * Nothing.
987 VOID WINAPI InitMUILanguage (LANGID uiLang)
989 COMCTL32_uiLang = uiLang;
993 /***********************************************************************
994 * SetWindowSubclass [COMCTL32.410]
996 * Starts a window subclass
998 * PARAMS
999 * hWnd [in] handle to window subclass.
1000 * pfnSubclass [in] Pointer to new window procedure.
1001 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1002 * dwRef [in] Reference data to pass to window procedure.
1004 * RETURNS
1005 * Success: non-zero
1006 * Failure: zero
1008 * BUGS
1009 * If an application manually subclasses a window after subclassing it with
1010 * this API and then with this API again, then none of the previous
1011 * subclasses get called or the original window procedure.
1014 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1015 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1017 LPSUBCLASS_INFO stack;
1018 LPSUBCLASSPROCS proc;
1020 TRACE ("(%p, %p, %lx, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1022 /* Since the window procedure that we set here has two additional arguments,
1023 * we can't simply set it as the new window procedure of the window. So we
1024 * set our own window procedure and then calculate the other two arguments
1025 * from there. */
1027 /* See if we have been called for this window */
1028 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1029 if (!stack) {
1030 /* allocate stack */
1031 stack = Alloc (sizeof(SUBCLASS_INFO));
1032 if (!stack) {
1033 ERR ("Failed to allocate our Subclassing stack\n");
1034 return FALSE;
1036 SetPropW (hWnd, COMCTL32_wSubclass, stack);
1038 /* set window procedure to our own and save the current one */
1039 if (IsWindowUnicode (hWnd))
1040 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1041 (DWORD_PTR)COMCTL32_SubclassProc);
1042 else
1043 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1044 (DWORD_PTR)COMCTL32_SubclassProc);
1046 else {
1047 /* Check to see if we have called this function with the same uIDSubClass
1048 * and pfnSubclass */
1049 proc = stack->SubclassProcs;
1050 while (proc) {
1051 if ((proc->id == uIDSubclass) &&
1052 (proc->subproc == pfnSubclass)) {
1053 proc->ref = dwRef;
1054 return TRUE;
1056 proc = proc->next;
1060 proc = Alloc(sizeof(SUBCLASSPROCS));
1061 if (!proc) {
1062 ERR ("Failed to allocate subclass entry in stack\n");
1063 if (IsWindowUnicode (hWnd))
1064 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1065 else
1066 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1067 Free (stack);
1068 RemovePropW( hWnd, COMCTL32_wSubclass );
1069 return FALSE;
1072 proc->subproc = pfnSubclass;
1073 proc->ref = dwRef;
1074 proc->id = uIDSubclass;
1075 proc->next = stack->SubclassProcs;
1076 stack->SubclassProcs = proc;
1078 return TRUE;
1082 /***********************************************************************
1083 * GetWindowSubclass [COMCTL32.411]
1085 * Gets the Reference data from a subclass.
1087 * PARAMS
1088 * hWnd [in] Handle to the window which we are subclassing
1089 * pfnSubclass [in] Pointer to the subclass procedure
1090 * uID [in] Unique identifier of the subclassing procedure
1091 * pdwRef [out] Pointer to the reference data
1093 * RETURNS
1094 * Success: Non-zero
1095 * Failure: 0
1098 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1099 UINT_PTR uID, DWORD_PTR *pdwRef)
1101 const SUBCLASS_INFO *stack;
1102 const SUBCLASSPROCS *proc;
1104 TRACE ("(%p, %p, %lx, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1106 /* See if we have been called for this window */
1107 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1108 if (!stack)
1109 return FALSE;
1111 proc = stack->SubclassProcs;
1112 while (proc) {
1113 if ((proc->id == uID) &&
1114 (proc->subproc == pfnSubclass)) {
1115 *pdwRef = proc->ref;
1116 return TRUE;
1118 proc = proc->next;
1121 return FALSE;
1125 /***********************************************************************
1126 * RemoveWindowSubclass [COMCTL32.412]
1128 * Removes a window subclass.
1130 * PARAMS
1131 * hWnd [in] Handle to the window which we are subclassing
1132 * pfnSubclass [in] Pointer to the subclass procedure
1133 * uID [in] Unique identifier of this subclass
1135 * RETURNS
1136 * Success: non-zero
1137 * Failure: zero
1140 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1142 LPSUBCLASS_INFO stack;
1143 LPSUBCLASSPROCS prevproc = NULL;
1144 LPSUBCLASSPROCS proc;
1145 BOOL ret = FALSE;
1147 TRACE ("(%p, %p, %lx)\n", hWnd, pfnSubclass, uID);
1149 /* Find the Subclass to remove */
1150 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1151 if (!stack)
1152 return FALSE;
1154 proc = stack->SubclassProcs;
1155 while (proc) {
1156 if ((proc->id == uID) &&
1157 (proc->subproc == pfnSubclass)) {
1159 if (!prevproc)
1160 stack->SubclassProcs = proc->next;
1161 else
1162 prevproc->next = proc->next;
1164 if (stack->stackpos == proc)
1165 stack->stackpos = stack->stackpos->next;
1167 Free (proc);
1168 ret = TRUE;
1169 break;
1171 prevproc = proc;
1172 proc = proc->next;
1175 if (!stack->SubclassProcs && !stack->running) {
1176 TRACE("Last Subclass removed, cleaning up\n");
1177 /* clean up our heap and reset the original window procedure */
1178 if (IsWindowUnicode (hWnd))
1179 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1180 else
1181 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1182 Free (stack);
1183 RemovePropW( hWnd, COMCTL32_wSubclass );
1186 return ret;
1189 /***********************************************************************
1190 * COMCTL32_SubclassProc (internal)
1192 * Window procedure for all subclassed windows.
1193 * Saves the current subclassing stack position to support nested messages
1195 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1197 LPSUBCLASS_INFO stack;
1198 LPSUBCLASSPROCS proc;
1199 LRESULT ret;
1201 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1203 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1204 if (!stack) {
1205 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1206 return 0;
1209 /* Save our old stackpos to properly handle nested messages */
1210 proc = stack->stackpos;
1211 stack->stackpos = stack->SubclassProcs;
1212 stack->running++;
1213 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1214 stack->running--;
1215 stack->stackpos = proc;
1217 if (!stack->SubclassProcs && !stack->running) {
1218 TRACE("Last Subclass removed, cleaning up\n");
1219 /* clean up our heap and reset the original window procedure */
1220 if (IsWindowUnicode (hWnd))
1221 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1222 else
1223 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1224 Free (stack);
1225 RemovePropW( hWnd, COMCTL32_wSubclass );
1227 return ret;
1230 /***********************************************************************
1231 * DefSubclassProc [COMCTL32.413]
1233 * Calls the next window procedure (i.e. the one before this subclass)
1235 * PARAMS
1236 * hWnd [in] The window that we're subclassing
1237 * uMsg [in] Message
1238 * wParam [in] WPARAM
1239 * lParam [in] LPARAM
1241 * RETURNS
1242 * Success: non-zero
1243 * Failure: zero
1246 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1248 LPSUBCLASS_INFO stack;
1249 LRESULT ret;
1251 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1253 /* retrieve our little stack from the Properties */
1254 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1255 if (!stack) {
1256 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1257 return 0;
1260 /* If we are at the end of stack then we have to call the original
1261 * window procedure */
1262 if (!stack->stackpos) {
1263 if (IsWindowUnicode (hWnd))
1264 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1265 else
1266 ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1267 } else {
1268 const SUBCLASSPROCS *proc = stack->stackpos;
1269 stack->stackpos = stack->stackpos->next;
1270 /* call the Subclass procedure from the stack */
1271 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1272 proc->id, proc->ref);
1275 return ret;
1279 /***********************************************************************
1280 * COMCTL32_CreateToolTip [NOT AN API]
1282 * Creates a tooltip for the control specified in hwnd and does all
1283 * necessary setup and notifications.
1285 * PARAMS
1286 * hwndOwner [I] Handle to the window that will own the tool tip.
1288 * RETURNS
1289 * Success: Handle of tool tip window.
1290 * Failure: NULL
1293 HWND
1294 COMCTL32_CreateToolTip(HWND hwndOwner)
1296 HWND hwndToolTip;
1298 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1299 CW_USEDEFAULT, CW_USEDEFAULT,
1300 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1301 0, 0, 0);
1303 /* Send NM_TOOLTIPSCREATED notification */
1304 if (hwndToolTip)
1306 NMTOOLTIPSCREATED nmttc;
1307 /* true owner can be different if hwndOwner is a child window */
1308 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1309 nmttc.hdr.hwndFrom = hwndTrueOwner;
1310 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1311 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1312 nmttc.hwndToolTips = hwndToolTip;
1314 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1315 GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
1318 return hwndToolTip;
1322 /***********************************************************************
1323 * COMCTL32_RefreshSysColors [NOT AN API]
1325 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1326 * refresh the color values in the color structure
1328 * PARAMS
1329 * none
1331 * RETURNS
1332 * none
1335 VOID
1336 COMCTL32_RefreshSysColors(void)
1338 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1339 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1340 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1341 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1342 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1343 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1344 comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1345 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1346 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1347 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1348 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1349 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1350 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1351 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1352 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1353 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1354 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1357 /***********************************************************************
1358 * COMCTL32_DrawInsertMark [NOT AN API]
1360 * Draws an insertion mark (which looks similar to an 'I').
1362 * PARAMS
1363 * hDC [I] Device context to draw onto.
1364 * lpRect [I] Co-ordinates of insertion mark.
1365 * clrInsertMark [I] Colour of the insertion mark.
1366 * bHorizontal [I] True if insert mark should be drawn horizontally,
1367 * vertical otherwise.
1369 * RETURNS
1370 * none
1372 * NOTES
1373 * Draws up to but not including the bottom co-ordinate when drawing
1374 * vertically or the right co-ordinate when horizontal.
1376 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1378 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1379 HPEN hOldPen;
1380 static const DWORD adwPolyPoints[] = {4,4,4};
1381 LONG lCentre = (bHorizontal ?
1382 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1383 lpRect->left + (lpRect->right - lpRect->left)/2);
1384 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1385 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1386 const POINT aptInsertMark[] =
1388 /* top (V) or left (H) arrow */
1389 {lCentre , l1 + 2},
1390 {lCentre - 2, l1 },
1391 {lCentre + 3, l1 },
1392 {lCentre + 1, l1 + 2},
1393 /* middle line */
1394 {lCentre , l2 - 2},
1395 {lCentre , l1 - 1},
1396 {lCentre + 1, l1 - 1},
1397 {lCentre + 1, l2 - 2},
1398 /* bottom (V) or right (H) arrow */
1399 {lCentre , l2 - 3},
1400 {lCentre - 2, l2 - 1},
1401 {lCentre + 3, l2 - 1},
1402 {lCentre + 1, l2 - 3},
1404 hOldPen = SelectObject(hDC, hPen);
1405 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0]));
1406 SelectObject(hDC, hOldPen);
1407 DeleteObject(hPen);
1410 /***********************************************************************
1411 * COMCTL32_EnsureBitmapSize [internal]
1413 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1414 * the height is at least cyMinHeight. If the bitmap already has these
1415 * dimensions nothing changes.
1417 * PARAMS
1418 * hBitmap [I/O] Bitmap to modify. The handle may change
1419 * cxMinWidth [I] If the width of the bitmap is smaller, then it will
1420 * be enlarged to this value
1421 * cyMinHeight [I] If the height of the bitmap is smaller, then it will
1422 * be enlarged to this value
1423 * cyBackground [I] The color with which the new area will be filled
1425 * RETURNS
1426 * none
1428 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1430 int cxNew, cyNew;
1431 BITMAP bmp;
1432 HBITMAP hNewBitmap;
1433 HBITMAP hNewDCBitmap, hOldDCBitmap;
1434 HBRUSH hNewDCBrush;
1435 HDC hdcNew, hdcOld;
1437 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1438 return;
1439 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1440 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1441 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1442 return;
1444 hdcNew = CreateCompatibleDC(NULL);
1445 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1446 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1447 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1449 hdcOld = CreateCompatibleDC(NULL);
1450 hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1452 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1453 if (bmp.bmWidth < cxMinWidth)
1454 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1455 if (bmp.bmHeight < cyMinHeight)
1456 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1457 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1458 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1460 SelectObject(hdcNew, hNewDCBitmap);
1461 DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1462 DeleteDC(hdcNew);
1463 SelectObject(hdcOld, hOldDCBitmap);
1464 DeleteDC(hdcOld);
1466 DeleteObject(*pBitmap);
1467 *pBitmap = hNewBitmap;
1468 return;
1471 void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
1473 HDC hdc = GetDC(NULL);
1474 HFONT hOldFont;
1476 hOldFont = SelectObject(hdc, hFont);
1477 GetTextMetricsW(hdc, ptm);
1478 SelectObject(hdc, hOldFont);
1479 ReleaseDC(NULL, hdc);
1482 #ifndef OCM__BASE /* avoid including olectl.h */
1483 #define OCM__BASE (WM_USER+0x1c00)
1484 #endif
1486 /***********************************************************************
1487 * COMCTL32_IsReflectedMessage [internal]
1489 * Some parents reflect notify messages - for some messages sent by the child,
1490 * they send it back with the message code increased by OCM__BASE (0x2000).
1491 * This allows better subclassing of controls. We don't need to handle such
1492 * messages but we don't want to print ERRs for them, so this helper function
1493 * identifies them.
1495 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1496 * collision with defined CCM_ codes.
1498 BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
1500 switch (uMsg)
1502 case OCM__BASE + WM_COMMAND:
1503 case OCM__BASE + WM_CTLCOLORBTN:
1504 case OCM__BASE + WM_CTLCOLOREDIT:
1505 case OCM__BASE + WM_CTLCOLORDLG:
1506 case OCM__BASE + WM_CTLCOLORLISTBOX:
1507 case OCM__BASE + WM_CTLCOLORMSGBOX:
1508 case OCM__BASE + WM_CTLCOLORSCROLLBAR:
1509 case OCM__BASE + WM_CTLCOLORSTATIC:
1510 case OCM__BASE + WM_DRAWITEM:
1511 case OCM__BASE + WM_MEASUREITEM:
1512 case OCM__BASE + WM_DELETEITEM:
1513 case OCM__BASE + WM_VKEYTOITEM:
1514 case OCM__BASE + WM_CHARTOITEM:
1515 case OCM__BASE + WM_COMPAREITEM:
1516 case OCM__BASE + WM_HSCROLL:
1517 case OCM__BASE + WM_VSCROLL:
1518 case OCM__BASE + WM_PARENTNOTIFY:
1519 case OCM__BASE + WM_NOTIFY:
1520 return TRUE;
1521 default:
1522 return FALSE;
1526 /***********************************************************************
1527 * MirrorIcon [COMCTL32.414]
1529 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1531 * PARAMS
1532 * phicon1 [I/O] Icon.
1533 * phicon2 [I/O] Icon.
1535 * RETURNS
1536 * Success: TRUE.
1537 * Failure: FALSE.
1539 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1541 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1542 return FALSE;
1545 static inline BOOL IsDelimiter(WCHAR c)
1547 switch(c)
1549 case '/':
1550 case '\\':
1551 case '.':
1552 case ' ':
1553 return TRUE;
1555 return FALSE;
1558 static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1560 if (code == WB_ISDELIMITER)
1561 return IsDelimiter(lpch[ichCurrent]);
1562 else
1564 int dir = (code == WB_LEFT) ? -1 : 1;
1565 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1566 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1568 return ichCurrent;
1571 /***********************************************************************
1572 * SetPathWordBreakProc [COMCTL32.384]
1574 * Sets the word break procedure for an edit control to one that understands
1575 * paths so that the user can jump over directories.
1577 * PARAMS
1578 * hwnd [I] Handle to edit control.
1579 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1581 * RETURNS
1582 * Result from EM_SETWORDBREAKPROC message.
1584 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1586 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1587 (LPARAM)(bSet ? PathWordBreakProc : NULL));
1590 /***********************************************************************
1591 * DrawShadowText [COMCTL32.@]
1593 * Draw text with shadow.
1595 int WINAPI DrawShadowText(HDC hdc, LPCWSTR text, UINT length, RECT *rect, DWORD flags,
1596 COLORREF crText, COLORREF crShadow, int offset_x, int offset_y)
1598 int bkmode, ret;
1599 COLORREF clr;
1600 RECT r;
1602 FIXME("(%p, %s, %d, %p, 0x%08x, 0x%08x, 0x%08x, %d, %d): semi-stub\n", hdc, debugstr_w(text),
1603 length, rect, flags, crText, crShadow, offset_x, offset_y);
1605 bkmode = SetBkMode(hdc, TRANSPARENT);
1606 clr = SetTextColor(hdc, crShadow);
1608 /* FIXME: for shadow we need to render normally, blur it, and blend with current background. */
1609 r = *rect;
1610 OffsetRect(&r, 1, 1);
1611 DrawTextW(hdc, text, length, &r, flags);
1613 SetTextColor(hdc, crText);
1615 /* with text color on top of a shadow */
1616 ret = DrawTextW(hdc, text, length, rect, flags);
1618 SetTextColor(hdc, clr);
1619 SetBkMode(hdc, bkmode);
1621 return ret;
1624 /***********************************************************************
1625 * LoadIconWithScaleDown [COMCTL32.@]
1627 HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
1629 TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
1631 *icon = NULL;
1633 if (!name)
1634 return E_INVALIDARG;
1636 *icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
1637 (hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
1638 if (!*icon)
1639 return HRESULT_FROM_WIN32(GetLastError());
1641 return S_OK;
1644 /***********************************************************************
1645 * LoadIconMetric [COMCTL32.@]
1647 HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
1649 int cx, cy;
1651 TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
1653 if (size == LIM_SMALL)
1655 cx = GetSystemMetrics(SM_CXSMICON);
1656 cy = GetSystemMetrics(SM_CYSMICON);
1658 else if (size == LIM_LARGE)
1660 cx = GetSystemMetrics(SM_CXICON);
1661 cy = GetSystemMetrics(SM_CYICON);
1663 else
1665 *icon = NULL;
1666 return E_INVALIDARG;
1669 return LoadIconWithScaleDown(hinst, name, cx, cy, icon);