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