winex11.drv: Ignore .dwAspect in FORMATETC during XDnD.
[wine.git] / dlls / comctl32 / commctrl.c
blobac53a2cf0fafd062892996cc2530ea859e48d5b9
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
96 static void unregister_versioned_classes(void)
98 #define VERSION "6.0.2600.2982!"
99 static const char *classes[] =
101 VERSION WC_BUTTONA,
102 VERSION WC_COMBOBOXA,
103 VERSION "ComboLBox",
104 VERSION WC_EDITA,
105 VERSION WC_LISTBOXA,
106 VERSION WC_STATICA,
108 int i;
110 for (i = 0; i < ARRAY_SIZE(classes); i++)
111 UnregisterClassA(classes[i], NULL);
113 #undef VERSION
116 BOOL WINAPI RegisterClassNameW(const WCHAR *class)
118 static const struct
120 const WCHAR nameW[16];
121 void (*fn_register)(void);
123 classes[] =
125 { {'B','u','t','t','o','n',0}, BUTTON_Register },
126 { {'C','o','m','b','o','B','o','x',0}, COMBO_Register },
127 { {'C','o','m','b','o','L','B','o','x',0}, COMBOLBOX_Register },
128 { {'E','d','i','t',0}, EDIT_Register },
129 { {'L','i','s','t','B','o','x',0}, LISTBOX_Register },
130 { {'S','t','a','t','i','c',0}, STATIC_Register },
133 int min = 0, max = ARRAY_SIZE(classes) - 1;
135 while (min <= max)
137 int res, pos = (min + max) / 2;
138 if (!(res = wcsicmp(class, classes[pos].nameW)))
140 classes[pos].fn_register();
141 return TRUE;
143 if (res < 0) max = pos - 1;
144 else min = pos + 1;
147 return FALSE;
150 /***********************************************************************
151 * DllMain [Internal]
153 * Initializes the internal 'COMCTL32.DLL'.
155 * PARAMS
156 * hinstDLL [I] handle to the 'dlls' instance
157 * fdwReason [I]
158 * lpvReserved [I] reserved, must be NULL
160 * RETURNS
161 * Success: TRUE
162 * Failure: FALSE
165 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
167 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
169 switch (fdwReason) {
170 case DLL_PROCESS_ATTACH:
171 DisableThreadLibraryCalls(hinstDLL);
173 COMCTL32_hModule = hinstDLL;
175 /* add global subclassing atom (used by 'tooltip' and 'updown') */
176 COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
177 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
179 /* create local pattern brush */
180 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
181 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
183 /* Get all the colors at DLL load */
184 COMCTL32_RefreshSysColors();
186 /* like comctl32 5.82+ register all the common control classes */
187 ANIMATE_Register ();
188 COMBOEX_Register ();
189 DATETIME_Register ();
190 FLATSB_Register ();
191 HEADER_Register ();
192 HOTKEY_Register ();
193 IPADDRESS_Register ();
194 LISTVIEW_Register ();
195 MONTHCAL_Register ();
196 NATIVEFONT_Register ();
197 PAGER_Register ();
198 PROGRESS_Register ();
199 REBAR_Register ();
200 STATUS_Register ();
201 SYSLINK_Register ();
202 TAB_Register ();
203 TOOLBAR_Register ();
204 TOOLTIPS_Register ();
205 TRACKBAR_Register ();
206 TREEVIEW_Register ();
207 UPDOWN_Register ();
209 /* subclass user32 controls */
210 THEMING_Initialize ();
211 break;
213 case DLL_PROCESS_DETACH:
214 if (lpvReserved) break;
215 /* clean up subclassing */
216 THEMING_Uninitialize();
218 /* unregister all common control classes */
219 ANIMATE_Unregister ();
220 COMBOEX_Unregister ();
221 DATETIME_Unregister ();
222 FLATSB_Unregister ();
223 HEADER_Unregister ();
224 HOTKEY_Unregister ();
225 IPADDRESS_Unregister ();
226 LISTVIEW_Unregister ();
227 MONTHCAL_Unregister ();
228 NATIVEFONT_Unregister ();
229 PAGER_Unregister ();
230 PROGRESS_Unregister ();
231 REBAR_Unregister ();
232 STATUS_Unregister ();
233 SYSLINK_Unregister ();
234 TAB_Unregister ();
235 TOOLBAR_Unregister ();
236 TOOLTIPS_Unregister ();
237 TRACKBAR_Unregister ();
238 TREEVIEW_Unregister ();
239 UPDOWN_Unregister ();
241 unregister_versioned_classes ();
243 /* delete local pattern brush */
244 DeleteObject (COMCTL32_hPattern55AABrush);
245 DeleteObject (COMCTL32_hPattern55AABitmap);
247 /* delete global subclassing atom */
248 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
249 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
250 break;
253 return TRUE;
257 /***********************************************************************
258 * MenuHelp [COMCTL32.2]
260 * Handles the setting of status bar help messages when the user
261 * selects menu items.
263 * PARAMS
264 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
265 * wParam [I] wParam of the message uMsg
266 * lParam [I] lParam of the message uMsg
267 * hMainMenu [I] handle to the application's main menu
268 * hInst [I] handle to the module that contains string resources
269 * hwndStatus [I] handle to the status bar window
270 * lpwIDs [I] pointer to an array of integers (see NOTES)
272 * RETURNS
273 * No return value
275 * NOTES
276 * The official documentation is incomplete!
277 * This is the correct documentation:
279 * uMsg:
280 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
281 * WM_MENUSELECT messages.
283 * lpwIDs:
284 * (will be written ...)
287 VOID WINAPI
288 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
289 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
291 UINT uMenuID = 0;
293 if (!IsWindow (hwndStatus))
294 return;
296 switch (uMsg) {
297 case WM_MENUSELECT:
298 TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
299 wParam, lParam);
301 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
302 /* menu was closed */
303 TRACE("menu was closed!\n");
304 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
306 else {
307 /* menu item was selected */
308 if (HIWORD(wParam) & MF_POPUP)
309 uMenuID = *(lpwIDs+1);
310 else
311 uMenuID = (UINT)LOWORD(wParam);
312 TRACE("uMenuID = %u\n", uMenuID);
314 if (uMenuID) {
315 WCHAR szText[256];
317 if (!LoadStringW (hInst, uMenuID, szText, ARRAY_SIZE(szText)))
318 szText[0] = '\0';
320 SendMessageW (hwndStatus, SB_SETTEXTW,
321 255 | SBT_NOBORDERS, (LPARAM)szText);
322 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
325 break;
327 case WM_COMMAND :
328 TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
329 wParam, lParam);
330 /* WM_COMMAND is not invalid since it is documented
331 * in the windows api reference. So don't output
332 * any FIXME for WM_COMMAND
334 WARN("We don't care about the WM_COMMAND\n");
335 break;
337 default:
338 FIXME("Invalid Message 0x%x!\n", uMsg);
339 break;
344 /***********************************************************************
345 * ShowHideMenuCtl [COMCTL32.3]
347 * Shows or hides controls and updates the corresponding menu item.
349 * PARAMS
350 * hwnd [I] handle to the client window.
351 * uFlags [I] menu command id.
352 * lpInfo [I] pointer to an array of integers. (See NOTES.)
354 * RETURNS
355 * Success: TRUE
356 * Failure: FALSE
358 * NOTES
359 * The official documentation is incomplete!
360 * This is the correct documentation:
362 * hwnd
363 * Handle to the window that contains the menu and controls.
365 * uFlags
366 * Identifier of the menu item to receive or lose a check mark.
368 * lpInfo
369 * The array of integers contains pairs of values. BOTH values of
370 * the first pair must be the handles to the application's main menu.
371 * Each subsequent pair consists of a menu id and control id.
374 BOOL WINAPI
375 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
377 LPINT lpMenuId;
379 TRACE("%p, %lx, %p\n", hwnd, uFlags, lpInfo);
381 if (lpInfo == NULL)
382 return FALSE;
384 if (!(lpInfo[0]) || !(lpInfo[1]))
385 return FALSE;
387 /* search for control */
388 lpMenuId = &lpInfo[2];
389 while (*lpMenuId != uFlags)
390 lpMenuId += 2;
392 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
393 /* uncheck menu item */
394 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
396 /* hide control */
397 lpMenuId++;
398 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
399 SWP_HIDEWINDOW);
401 else {
402 /* check menu item */
403 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
405 /* show control */
406 lpMenuId++;
407 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
408 SWP_SHOWWINDOW);
411 return TRUE;
415 /***********************************************************************
416 * GetEffectiveClientRect [COMCTL32.4]
418 * Calculates the coordinates of a rectangle in the client area.
420 * PARAMS
421 * hwnd [I] handle to the client window.
422 * lpRect [O] pointer to the rectangle of the client window
423 * lpInfo [I] pointer to an array of integers (see NOTES)
425 * RETURNS
426 * No return value.
428 * NOTES
429 * The official documentation is incomplete!
430 * This is the correct documentation:
432 * lpInfo
433 * (will be written ...)
436 VOID WINAPI
437 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
439 RECT rcCtrl;
440 const INT *lpRun;
441 HWND hwndCtrl;
443 TRACE("(%p %p %p)\n",
444 hwnd, lpRect, lpInfo);
446 GetClientRect (hwnd, lpRect);
447 lpRun = lpInfo;
449 do {
450 lpRun += 2;
451 if (*lpRun == 0)
452 return;
453 lpRun++;
454 hwndCtrl = GetDlgItem (hwnd, *lpRun);
455 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
456 TRACE("control id 0x%x\n", *lpRun);
457 GetWindowRect (hwndCtrl, &rcCtrl);
458 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
459 SubtractRect (lpRect, lpRect, &rcCtrl);
461 lpRun++;
462 } while (*lpRun);
466 /***********************************************************************
467 * DrawStatusTextW [COMCTL32.@]
469 * Draws text with borders, like in a status bar.
471 * PARAMS
472 * hdc [I] handle to the window's display context
473 * lprc [I] pointer to a rectangle
474 * text [I] pointer to the text
475 * style [I] drawing style
477 * RETURNS
478 * No return value.
480 * NOTES
481 * The style variable can have one of the following values:
482 * (will be written ...)
485 void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
487 RECT r = *lprc;
488 UINT border = BDR_SUNKENOUTER;
489 COLORREF oldbkcolor;
491 if (style & SBT_POPOUT)
492 border = BDR_RAISEDOUTER;
493 else if (style & SBT_NOBORDERS)
494 border = 0;
496 oldbkcolor = SetBkColor (hdc, comctl32_color.clrBtnFace);
497 DrawEdge (hdc, &r, border, BF_MIDDLE|BF_RECT|BF_ADJUST);
499 /* now draw text */
500 if (text) {
501 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
502 COLORREF oldtextcolor;
503 UINT align = DT_LEFT;
504 int strCnt = 0;
506 oldtextcolor = SetTextColor (hdc, comctl32_color.clrBtnText);
507 if (style & SBT_RTLREADING)
508 FIXME("Unsupported RTL style!\n");
509 r.left += 3;
510 do {
511 if (*text == '\t') {
512 if (strCnt) {
513 DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
514 strCnt = 0;
516 if (align==DT_RIGHT) {
517 break;
519 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
520 } else {
521 strCnt++;
523 } while(*text++);
525 if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
526 SetBkMode (hdc, oldbkmode);
527 SetTextColor (hdc, oldtextcolor);
530 SetBkColor (hdc, oldbkcolor);
534 /***********************************************************************
535 * DrawStatusText [COMCTL32.@]
536 * DrawStatusTextA [COMCTL32.5]
538 * Draws text with borders, like in a status bar.
540 * PARAMS
541 * hdc [I] handle to the window's display context
542 * lprc [I] pointer to a rectangle
543 * text [I] pointer to the text
544 * style [I] drawing style
546 * RETURNS
547 * No return value.
550 void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
552 INT len;
553 LPWSTR textW = NULL;
555 if ( text ) {
556 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
557 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
558 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
561 DrawStatusTextW( hdc, lprc, textW, style );
562 Free( textW );
566 /***********************************************************************
567 * CreateStatusWindow [COMCTL32.@]
568 * CreateStatusWindowA [COMCTL32.6]
570 * Creates a status bar
572 * PARAMS
573 * style [I] window style
574 * text [I] pointer to the window text
575 * parent [I] handle to the parent window
576 * wid [I] control id of the status bar
578 * RETURNS
579 * Success: handle to the status window
580 * Failure: 0
583 HWND WINAPI
584 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
586 return CreateWindowA(STATUSCLASSNAMEA, text, style,
587 CW_USEDEFAULT, CW_USEDEFAULT,
588 CW_USEDEFAULT, CW_USEDEFAULT,
589 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
593 /***********************************************************************
594 * CreateStatusWindowW [COMCTL32.@]
596 * Creates a status bar control
598 * PARAMS
599 * style [I] window style
600 * text [I] pointer to the window text
601 * parent [I] handle to the parent window
602 * wid [I] control id of the status bar
604 * RETURNS
605 * Success: handle to the status window
606 * Failure: 0
609 HWND WINAPI
610 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
612 return CreateWindowW(STATUSCLASSNAMEW, text, style,
613 CW_USEDEFAULT, CW_USEDEFAULT,
614 CW_USEDEFAULT, CW_USEDEFAULT,
615 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
619 /***********************************************************************
620 * CreateUpDownControl [COMCTL32.16]
622 * Creates an up-down control
624 * PARAMS
625 * style [I] window styles
626 * x [I] horizontal position of the control
627 * y [I] vertical position of the control
628 * cx [I] with of the control
629 * cy [I] height of the control
630 * parent [I] handle to the parent window
631 * id [I] the control's identifier
632 * inst [I] handle to the application's module instance
633 * buddy [I] handle to the buddy window, can be NULL
634 * maxVal [I] upper limit of the control
635 * minVal [I] lower limit of the control
636 * curVal [I] current value of the control
638 * RETURNS
639 * Success: handle to the updown control
640 * Failure: 0
643 HWND WINAPI
644 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
645 HWND parent, INT id, HINSTANCE inst,
646 HWND buddy, INT maxVal, INT minVal, INT curVal)
648 HWND hUD =
649 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
650 parent, (HMENU)(DWORD_PTR)id, inst, 0);
651 if (hUD) {
652 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
653 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
654 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
657 return hUD;
661 /***********************************************************************
662 * InitCommonControls [COMCTL32.17]
664 * Registers the common controls.
666 * PARAMS
667 * No parameters.
669 * RETURNS
670 * No return values.
672 * NOTES
673 * This function is just a dummy - all the controls are registered at
674 * the DLL initialization time. See InitCommonControlsEx for details.
677 VOID WINAPI
678 InitCommonControls (void)
683 /***********************************************************************
684 * InitCommonControlsEx [COMCTL32.@]
686 * Registers the common controls.
688 * PARAMS
689 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
691 * RETURNS
692 * Success: TRUE
693 * Failure: FALSE
695 * NOTES
696 * Probably all versions of comctl32 initializes the Win95 controls in DllMain
697 * during DLL initialization. Starting from comctl32 v5.82 all the controls
698 * are initialized there. We follow this behaviour and this function is just
699 * a dummy.
701 * Note: when writing programs under Windows, if you don't call any function
702 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
703 * was the only comctl32 function you were calling and you remove it you may
704 * have a false impression that InitCommonControlsEx actually did something.
707 BOOL WINAPI
708 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
710 if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
711 return FALSE;
713 TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
714 return TRUE;
718 /***********************************************************************
719 * CreateToolbarEx [COMCTL32.@]
721 * Creates a toolbar window.
723 * PARAMS
724 * hwnd
725 * style
726 * wID
727 * nBitmaps
728 * hBMInst
729 * wBMID
730 * lpButtons
731 * iNumButtons
732 * dxButton
733 * dyButton
734 * dxBitmap
735 * dyBitmap
736 * uStructSize
738 * RETURNS
739 * Success: handle to the tool bar control
740 * Failure: 0
743 HWND WINAPI
744 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
745 HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
746 INT iNumButtons, INT dxButton, INT dyButton,
747 INT dxBitmap, INT dyBitmap, UINT uStructSize)
749 HWND hwndTB;
751 hwndTB =
752 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
753 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
754 if(hwndTB) {
755 TBADDBITMAP tbab;
757 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
759 /* set bitmap and button size */
760 /*If CreateToolbarEx receives 0, windows sets default values*/
761 if (dxBitmap < 0)
762 dxBitmap = 16;
763 if (dyBitmap < 0)
764 dyBitmap = 16;
765 if (dxBitmap == 0 || dyBitmap == 0)
766 dxBitmap = dyBitmap = 16;
767 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
769 if (dxButton < 0)
770 dxButton = dxBitmap;
771 if (dyButton < 0)
772 dyButton = dyBitmap;
773 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
774 if (dxButton != 0 && dyButton != 0)
775 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
778 /* add bitmaps */
779 if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
781 tbab.hInst = hBMInst;
782 tbab.nID = wBMID;
784 SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
786 /* add buttons */
787 if(iNumButtons > 0)
788 SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
791 return hwndTB;
795 /***********************************************************************
796 * CreateMappedBitmap [COMCTL32.8]
798 * Loads a bitmap resource using a colour map.
800 * PARAMS
801 * hInstance [I] Handle to the module containing the bitmap.
802 * idBitmap [I] The bitmap resource ID.
803 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
804 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
805 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
807 * RETURNS
808 * Success: handle to the new bitmap
809 * Failure: 0
812 HBITMAP WINAPI
813 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
814 LPCOLORMAP lpColorMap, INT iNumMaps)
816 HGLOBAL hglb;
817 HRSRC hRsrc;
818 const BITMAPINFOHEADER *lpBitmap;
819 LPBITMAPINFOHEADER lpBitmapInfo;
820 UINT nSize, nColorTableSize, iColor;
821 RGBQUAD *pColorTable;
822 INT i, iMaps, nWidth, nHeight;
823 HDC hdcScreen;
824 HBITMAP hbm;
825 LPCOLORMAP sysColorMap;
826 COLORREF cRef;
827 COLORMAP internalColorMap[4] =
828 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
830 /* initialize pointer to colortable and default color table */
831 if (lpColorMap) {
832 iMaps = iNumMaps;
833 sysColorMap = lpColorMap;
835 else {
836 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
837 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
838 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
839 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
840 iMaps = 4;
841 sysColorMap = internalColorMap;
844 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
845 if (hRsrc == 0)
846 return 0;
847 hglb = LoadResource (hInstance, hRsrc);
848 if (hglb == 0)
849 return 0;
850 lpBitmap = LockResource (hglb);
851 if (lpBitmap == NULL)
852 return 0;
854 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
855 nColorTableSize = lpBitmap->biClrUsed;
856 else if (lpBitmap->biBitCount <= 8)
857 nColorTableSize = (1 << lpBitmap->biBitCount);
858 else
859 nColorTableSize = 0;
860 nSize = lpBitmap->biSize;
861 if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
862 nSize += 3 * sizeof(DWORD);
863 nSize += nColorTableSize * sizeof(RGBQUAD);
864 lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
865 if (lpBitmapInfo == NULL)
866 return 0;
867 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
869 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
871 for (iColor = 0; iColor < nColorTableSize; iColor++) {
872 for (i = 0; i < iMaps; i++) {
873 cRef = RGB(pColorTable[iColor].rgbRed,
874 pColorTable[iColor].rgbGreen,
875 pColorTable[iColor].rgbBlue);
876 if ( cRef == sysColorMap[i].from) {
877 #if 0
878 if (wFlags & CBS_MASKED) {
879 if (sysColorMap[i].to != COLOR_BTNTEXT)
880 pColorTable[iColor] = RGB(255, 255, 255);
882 else
883 #endif
884 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
885 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
886 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
887 break;
891 nWidth = lpBitmapInfo->biWidth;
892 nHeight = lpBitmapInfo->biHeight;
893 hdcScreen = GetDC (NULL);
894 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
895 if (hbm) {
896 HDC hdcDst = CreateCompatibleDC (hdcScreen);
897 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
898 const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
899 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
900 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
901 SRCCOPY);
902 SelectObject (hdcDst, hbmOld);
903 DeleteDC (hdcDst);
905 ReleaseDC (NULL, hdcScreen);
906 GlobalFree (lpBitmapInfo);
907 FreeResource (hglb);
909 return hbm;
913 /***********************************************************************
914 * CreateToolbar [COMCTL32.7]
916 * Creates a toolbar control.
918 * PARAMS
919 * hwnd
920 * style
921 * wID
922 * nBitmaps
923 * hBMInst
924 * wBMID
925 * lpButtons
926 * iNumButtons
928 * RETURNS
929 * Success: handle to the tool bar control
930 * Failure: 0
932 * NOTES
933 * Do not use this function anymore. Use CreateToolbarEx instead.
936 HWND WINAPI
937 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
938 HINSTANCE hBMInst, UINT wBMID,
939 LPCTBBUTTON lpButtons,INT iNumButtons)
941 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
942 hBMInst, wBMID, lpButtons,
943 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
947 /***********************************************************************
948 * DllGetVersion [COMCTL32.@]
950 * Retrieves version information of the 'COMCTL32.DLL'
952 * PARAMS
953 * pdvi [O] pointer to version information structure.
955 * RETURNS
956 * Success: S_OK
957 * Failure: E_INVALIDARG
959 * NOTES
960 * Returns version of a comctl32.dll from IE4.01 SP1.
963 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
965 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
966 WARN("wrong DLLVERSIONINFO size from app\n");
967 return E_INVALIDARG;
970 pdvi->dwMajorVersion = COMCTL32_VERSION;
971 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
972 pdvi->dwBuildNumber = 2919;
973 pdvi->dwPlatformID = 6304;
975 TRACE("%u.%u.%u.%u\n",
976 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
977 pdvi->dwBuildNumber, pdvi->dwPlatformID);
979 return S_OK;
982 /***********************************************************************
983 * DllInstall (COMCTL32.@)
985 * Installs the ComCtl32 DLL.
987 * RETURNS
988 * Success: S_OK
989 * Failure: A HRESULT error
991 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
993 TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
994 return S_OK;
997 /***********************************************************************
998 * _TrackMouseEvent [COMCTL32.@]
1000 * Requests notification of mouse events
1002 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1003 * to the hwnd specified in the ptme structure. After the event message
1004 * is posted to the hwnd, the entry in the queue is removed.
1006 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1007 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1008 * immediately and the TME_LEAVE flag being ignored.
1010 * PARAMS
1011 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1013 * RETURNS
1014 * Success: non-zero
1015 * Failure: zero
1017 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1021 BOOL WINAPI
1022 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1024 return TrackMouseEvent (ptme);
1027 /*************************************************************************
1028 * GetMUILanguage [COMCTL32.@]
1030 * Returns the user interface language in use by the current process.
1032 * RETURNS
1033 * Language ID in use by the current process.
1035 LANGID WINAPI GetMUILanguage (VOID)
1037 return COMCTL32_uiLang;
1041 /*************************************************************************
1042 * InitMUILanguage [COMCTL32.@]
1044 * Sets the user interface language to be used by the current process.
1046 * RETURNS
1047 * Nothing.
1049 VOID WINAPI InitMUILanguage (LANGID uiLang)
1051 COMCTL32_uiLang = uiLang;
1055 /***********************************************************************
1056 * SetWindowSubclass [COMCTL32.410]
1058 * Starts a window subclass
1060 * PARAMS
1061 * hWnd [in] handle to window subclass.
1062 * pfnSubclass [in] Pointer to new window procedure.
1063 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1064 * dwRef [in] Reference data to pass to window procedure.
1066 * RETURNS
1067 * Success: non-zero
1068 * Failure: zero
1070 * BUGS
1071 * If an application manually subclasses a window after subclassing it with
1072 * this API and then with this API again, then none of the previous
1073 * subclasses get called or the original window procedure.
1076 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1077 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1079 LPSUBCLASS_INFO stack;
1080 LPSUBCLASSPROCS proc;
1082 TRACE ("(%p, %p, %lx, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1084 if (!hWnd || !pfnSubclass)
1085 return FALSE;
1087 /* Since the window procedure that we set here has two additional arguments,
1088 * we can't simply set it as the new window procedure of the window. So we
1089 * set our own window procedure and then calculate the other two arguments
1090 * from there. */
1092 /* See if we have been called for this window */
1093 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1094 if (!stack) {
1095 /* allocate stack */
1096 stack = Alloc (sizeof(SUBCLASS_INFO));
1097 if (!stack) {
1098 ERR ("Failed to allocate our Subclassing stack\n");
1099 return FALSE;
1101 SetPropW (hWnd, COMCTL32_wSubclass, stack);
1103 /* set window procedure to our own and save the current one */
1104 if (IsWindowUnicode (hWnd))
1105 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1106 (DWORD_PTR)COMCTL32_SubclassProc);
1107 else
1108 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1109 (DWORD_PTR)COMCTL32_SubclassProc);
1111 else {
1112 /* Check to see if we have called this function with the same uIDSubClass
1113 * and pfnSubclass */
1114 proc = stack->SubclassProcs;
1115 while (proc) {
1116 if ((proc->id == uIDSubclass) &&
1117 (proc->subproc == pfnSubclass)) {
1118 proc->ref = dwRef;
1119 return TRUE;
1121 proc = proc->next;
1125 proc = Alloc(sizeof(SUBCLASSPROCS));
1126 if (!proc) {
1127 ERR ("Failed to allocate subclass entry in stack\n");
1128 if (IsWindowUnicode (hWnd))
1129 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1130 else
1131 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1132 Free (stack);
1133 RemovePropW( hWnd, COMCTL32_wSubclass );
1134 return FALSE;
1137 proc->subproc = pfnSubclass;
1138 proc->ref = dwRef;
1139 proc->id = uIDSubclass;
1140 proc->next = stack->SubclassProcs;
1141 stack->SubclassProcs = proc;
1143 return TRUE;
1147 /***********************************************************************
1148 * GetWindowSubclass [COMCTL32.411]
1150 * Gets the Reference data from a subclass.
1152 * PARAMS
1153 * hWnd [in] Handle to the window which we are subclassing
1154 * pfnSubclass [in] Pointer to the subclass procedure
1155 * uID [in] Unique identifier of the subclassing procedure
1156 * pdwRef [out] Pointer to the reference data
1158 * RETURNS
1159 * Success: Non-zero
1160 * Failure: 0
1163 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1164 UINT_PTR uID, DWORD_PTR *pdwRef)
1166 const SUBCLASS_INFO *stack;
1167 const SUBCLASSPROCS *proc;
1169 TRACE ("(%p, %p, %lx, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1171 /* See if we have been called for this window */
1172 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1173 if (!stack)
1174 return FALSE;
1176 proc = stack->SubclassProcs;
1177 while (proc) {
1178 if ((proc->id == uID) &&
1179 (proc->subproc == pfnSubclass)) {
1180 *pdwRef = proc->ref;
1181 return TRUE;
1183 proc = proc->next;
1186 return FALSE;
1190 /***********************************************************************
1191 * RemoveWindowSubclass [COMCTL32.412]
1193 * Removes a window subclass.
1195 * PARAMS
1196 * hWnd [in] Handle to the window which we are subclassing
1197 * pfnSubclass [in] Pointer to the subclass procedure
1198 * uID [in] Unique identifier of this subclass
1200 * RETURNS
1201 * Success: non-zero
1202 * Failure: zero
1205 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1207 LPSUBCLASS_INFO stack;
1208 LPSUBCLASSPROCS prevproc = NULL;
1209 LPSUBCLASSPROCS proc;
1210 BOOL ret = FALSE;
1212 TRACE ("(%p, %p, %lx)\n", hWnd, pfnSubclass, uID);
1214 /* Find the Subclass to remove */
1215 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1216 if (!stack)
1217 return FALSE;
1219 proc = stack->SubclassProcs;
1220 while (proc) {
1221 if ((proc->id == uID) &&
1222 (proc->subproc == pfnSubclass)) {
1224 if (!prevproc)
1225 stack->SubclassProcs = proc->next;
1226 else
1227 prevproc->next = proc->next;
1229 if (stack->stackpos == proc)
1230 stack->stackpos = stack->stackpos->next;
1232 Free (proc);
1233 ret = TRUE;
1234 break;
1236 prevproc = proc;
1237 proc = proc->next;
1240 if (!stack->SubclassProcs && !stack->running) {
1241 TRACE("Last Subclass removed, cleaning up\n");
1242 /* clean up our heap and reset the original window procedure */
1243 if (IsWindowUnicode (hWnd))
1244 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1245 else
1246 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1247 Free (stack);
1248 RemovePropW( hWnd, COMCTL32_wSubclass );
1251 return ret;
1254 /***********************************************************************
1255 * COMCTL32_SubclassProc (internal)
1257 * Window procedure for all subclassed windows.
1258 * Saves the current subclassing stack position to support nested messages
1260 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1262 LPSUBCLASS_INFO stack;
1263 LPSUBCLASSPROCS proc;
1264 LRESULT ret;
1266 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1268 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1269 if (!stack) {
1270 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1271 return 0;
1274 /* Save our old stackpos to properly handle nested messages */
1275 proc = stack->stackpos;
1276 stack->stackpos = stack->SubclassProcs;
1277 stack->running++;
1278 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1279 stack->running--;
1280 stack->stackpos = proc;
1282 if (!stack->SubclassProcs && !stack->running) {
1283 TRACE("Last Subclass removed, cleaning up\n");
1284 /* clean up our heap and reset the original window procedure */
1285 if (IsWindowUnicode (hWnd))
1286 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1287 else
1288 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1289 Free (stack);
1290 RemovePropW( hWnd, COMCTL32_wSubclass );
1292 return ret;
1295 /***********************************************************************
1296 * DefSubclassProc [COMCTL32.413]
1298 * Calls the next window procedure (i.e. the one before this subclass)
1300 * PARAMS
1301 * hWnd [in] The window that we're subclassing
1302 * uMsg [in] Message
1303 * wParam [in] WPARAM
1304 * lParam [in] LPARAM
1306 * RETURNS
1307 * Success: non-zero
1308 * Failure: zero
1311 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1313 LPSUBCLASS_INFO stack;
1314 LRESULT ret;
1316 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1318 /* retrieve our little stack from the Properties */
1319 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1320 if (!stack) {
1321 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1322 return 0;
1325 /* If we are at the end of stack then we have to call the original
1326 * window procedure */
1327 if (!stack->stackpos) {
1328 if (IsWindowUnicode (hWnd))
1329 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1330 else
1331 ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1332 } else {
1333 const SUBCLASSPROCS *proc = stack->stackpos;
1334 stack->stackpos = stack->stackpos->next;
1335 /* call the Subclass procedure from the stack */
1336 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1337 proc->id, proc->ref);
1340 return ret;
1344 /***********************************************************************
1345 * COMCTL32_CreateToolTip [NOT AN API]
1347 * Creates a tooltip for the control specified in hwnd and does all
1348 * necessary setup and notifications.
1350 * PARAMS
1351 * hwndOwner [I] Handle to the window that will own the tool tip.
1353 * RETURNS
1354 * Success: Handle of tool tip window.
1355 * Failure: NULL
1358 HWND
1359 COMCTL32_CreateToolTip(HWND hwndOwner)
1361 HWND hwndToolTip;
1363 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1364 CW_USEDEFAULT, CW_USEDEFAULT,
1365 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1366 0, 0, 0);
1368 /* Send NM_TOOLTIPSCREATED notification */
1369 if (hwndToolTip)
1371 NMTOOLTIPSCREATED nmttc;
1372 /* true owner can be different if hwndOwner is a child window */
1373 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1374 nmttc.hdr.hwndFrom = hwndTrueOwner;
1375 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1376 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1377 nmttc.hwndToolTips = hwndToolTip;
1379 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1380 GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
1383 return hwndToolTip;
1387 /***********************************************************************
1388 * COMCTL32_RefreshSysColors [NOT AN API]
1390 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1391 * refresh the color values in the color structure
1393 * PARAMS
1394 * none
1396 * RETURNS
1397 * none
1400 VOID
1401 COMCTL32_RefreshSysColors(void)
1403 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1404 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1405 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1406 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1407 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1408 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1409 comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1410 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1411 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1412 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1413 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1414 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1415 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1416 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1417 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1418 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1419 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1422 /***********************************************************************
1423 * COMCTL32_DrawInsertMark [NOT AN API]
1425 * Draws an insertion mark (which looks similar to an 'I').
1427 * PARAMS
1428 * hDC [I] Device context to draw onto.
1429 * lpRect [I] Co-ordinates of insertion mark.
1430 * clrInsertMark [I] Colour of the insertion mark.
1431 * bHorizontal [I] True if insert mark should be drawn horizontally,
1432 * vertical otherwise.
1434 * RETURNS
1435 * none
1437 * NOTES
1438 * Draws up to but not including the bottom co-ordinate when drawing
1439 * vertically or the right co-ordinate when horizontal.
1441 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1443 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1444 HPEN hOldPen;
1445 static const DWORD adwPolyPoints[] = {4,4,4};
1446 LONG lCentre = (bHorizontal ?
1447 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1448 lpRect->left + (lpRect->right - lpRect->left)/2);
1449 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1450 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1451 const POINT aptInsertMark[] =
1453 /* top (V) or left (H) arrow */
1454 {lCentre , l1 + 2},
1455 {lCentre - 2, l1 },
1456 {lCentre + 3, l1 },
1457 {lCentre + 1, l1 + 2},
1458 /* middle line */
1459 {lCentre , l2 - 2},
1460 {lCentre , l1 - 1},
1461 {lCentre + 1, l1 - 1},
1462 {lCentre + 1, l2 - 2},
1463 /* bottom (V) or right (H) arrow */
1464 {lCentre , l2 - 3},
1465 {lCentre - 2, l2 - 1},
1466 {lCentre + 3, l2 - 1},
1467 {lCentre + 1, l2 - 3},
1469 hOldPen = SelectObject(hDC, hPen);
1470 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, ARRAY_SIZE(adwPolyPoints));
1471 SelectObject(hDC, hOldPen);
1472 DeleteObject(hPen);
1475 /***********************************************************************
1476 * COMCTL32_EnsureBitmapSize [internal]
1478 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1479 * the height is at least cyMinHeight. If the bitmap already has these
1480 * dimensions nothing changes.
1482 * PARAMS
1483 * hBitmap [I/O] Bitmap to modify. The handle may change
1484 * cxMinWidth [I] If the width of the bitmap is smaller, then it will
1485 * be enlarged to this value
1486 * cyMinHeight [I] If the height of the bitmap is smaller, then it will
1487 * be enlarged to this value
1488 * cyBackground [I] The color with which the new area will be filled
1490 * RETURNS
1491 * none
1493 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1495 int cxNew, cyNew;
1496 BITMAP bmp;
1497 HBITMAP hNewBitmap;
1498 HBITMAP hNewDCBitmap, hOldDCBitmap;
1499 HBRUSH hNewDCBrush;
1500 HDC hdcNew, hdcOld;
1502 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1503 return;
1504 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1505 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1506 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1507 return;
1509 hdcNew = CreateCompatibleDC(NULL);
1510 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1511 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1512 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1514 hdcOld = CreateCompatibleDC(NULL);
1515 hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1517 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1518 if (bmp.bmWidth < cxMinWidth)
1519 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1520 if (bmp.bmHeight < cyMinHeight)
1521 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1522 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1523 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1525 SelectObject(hdcNew, hNewDCBitmap);
1526 DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1527 DeleteDC(hdcNew);
1528 SelectObject(hdcOld, hOldDCBitmap);
1529 DeleteDC(hdcOld);
1531 DeleteObject(*pBitmap);
1532 *pBitmap = hNewBitmap;
1533 return;
1536 void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
1538 HDC hdc = GetDC(NULL);
1539 HFONT hOldFont;
1541 hOldFont = SelectObject(hdc, hFont);
1542 GetTextMetricsW(hdc, ptm);
1543 SelectObject(hdc, hOldFont);
1544 ReleaseDC(NULL, hdc);
1547 #ifndef OCM__BASE /* avoid including olectl.h */
1548 #define OCM__BASE (WM_USER+0x1c00)
1549 #endif
1551 /***********************************************************************
1552 * COMCTL32_IsReflectedMessage [internal]
1554 * Some parents reflect notify messages - for some messages sent by the child,
1555 * they send it back with the message code increased by OCM__BASE (0x2000).
1556 * This allows better subclassing of controls. We don't need to handle such
1557 * messages but we don't want to print ERRs for them, so this helper function
1558 * identifies them.
1560 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1561 * collision with defined CCM_ codes.
1563 BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
1565 switch (uMsg)
1567 case OCM__BASE + WM_COMMAND:
1568 case OCM__BASE + WM_CTLCOLORBTN:
1569 case OCM__BASE + WM_CTLCOLOREDIT:
1570 case OCM__BASE + WM_CTLCOLORDLG:
1571 case OCM__BASE + WM_CTLCOLORLISTBOX:
1572 case OCM__BASE + WM_CTLCOLORMSGBOX:
1573 case OCM__BASE + WM_CTLCOLORSCROLLBAR:
1574 case OCM__BASE + WM_CTLCOLORSTATIC:
1575 case OCM__BASE + WM_DRAWITEM:
1576 case OCM__BASE + WM_MEASUREITEM:
1577 case OCM__BASE + WM_DELETEITEM:
1578 case OCM__BASE + WM_VKEYTOITEM:
1579 case OCM__BASE + WM_CHARTOITEM:
1580 case OCM__BASE + WM_COMPAREITEM:
1581 case OCM__BASE + WM_HSCROLL:
1582 case OCM__BASE + WM_VSCROLL:
1583 case OCM__BASE + WM_PARENTNOTIFY:
1584 case OCM__BASE + WM_NOTIFY:
1585 return TRUE;
1586 default:
1587 return FALSE;
1591 /***********************************************************************
1592 * MirrorIcon [COMCTL32.414]
1594 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1596 * PARAMS
1597 * phicon1 [I/O] Icon.
1598 * phicon2 [I/O] Icon.
1600 * RETURNS
1601 * Success: TRUE.
1602 * Failure: FALSE.
1604 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1606 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1607 return FALSE;
1610 static inline BOOL IsDelimiter(WCHAR c)
1612 switch(c)
1614 case '/':
1615 case '\\':
1616 case '.':
1617 case ' ':
1618 return TRUE;
1620 return FALSE;
1623 static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1625 if (code == WB_ISDELIMITER)
1626 return IsDelimiter(lpch[ichCurrent]);
1627 else
1629 int dir = (code == WB_LEFT) ? -1 : 1;
1630 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1631 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1633 return ichCurrent;
1636 /***********************************************************************
1637 * SetPathWordBreakProc [COMCTL32.384]
1639 * Sets the word break procedure for an edit control to one that understands
1640 * paths so that the user can jump over directories.
1642 * PARAMS
1643 * hwnd [I] Handle to edit control.
1644 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1646 * RETURNS
1647 * Result from EM_SETWORDBREAKPROC message.
1649 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1651 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1652 (LPARAM)(bSet ? PathWordBreakProc : NULL));
1655 /***********************************************************************
1656 * DrawShadowText [COMCTL32.@]
1658 * Draw text with shadow.
1660 int WINAPI DrawShadowText(HDC hdc, LPCWSTR text, UINT length, RECT *rect, DWORD flags,
1661 COLORREF crText, COLORREF crShadow, int offset_x, int offset_y)
1663 int bkmode, ret;
1664 COLORREF clr;
1665 RECT r;
1667 FIXME("(%p, %s, %d, %p, 0x%08x, 0x%08x, 0x%08x, %d, %d): semi-stub\n", hdc, debugstr_w(text),
1668 length, rect, flags, crText, crShadow, offset_x, offset_y);
1670 bkmode = SetBkMode(hdc, TRANSPARENT);
1671 clr = SetTextColor(hdc, crShadow);
1673 /* FIXME: for shadow we need to render normally, blur it, and blend with current background. */
1674 r = *rect;
1675 OffsetRect(&r, 1, 1);
1676 DrawTextW(hdc, text, length, &r, flags);
1678 SetTextColor(hdc, crText);
1680 /* with text color on top of a shadow */
1681 ret = DrawTextW(hdc, text, length, rect, flags);
1683 SetTextColor(hdc, clr);
1684 SetBkMode(hdc, bkmode);
1686 return ret;
1689 /***********************************************************************
1690 * LoadIconWithScaleDown [COMCTL32.@]
1692 HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
1694 TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
1696 *icon = NULL;
1698 if (!name)
1699 return E_INVALIDARG;
1701 *icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
1702 (hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
1703 if (!*icon)
1704 return HRESULT_FROM_WIN32(GetLastError());
1706 return S_OK;
1709 /***********************************************************************
1710 * LoadIconMetric [COMCTL32.@]
1712 HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
1714 int cx, cy;
1716 TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
1718 if (size == LIM_SMALL)
1720 cx = GetSystemMetrics(SM_CXSMICON);
1721 cy = GetSystemMetrics(SM_CYSMICON);
1723 else if (size == LIM_LARGE)
1725 cx = GetSystemMetrics(SM_CXICON);
1726 cy = GetSystemMetrics(SM_CYICON);
1728 else
1730 *icon = NULL;
1731 return E_INVALIDARG;
1734 return LoadIconWithScaleDown(hinst, name, cx, cy, icon);