2 * Common controls functions
4 * Copyright 1997 Dimitrie O. Paun
5 * 1998 Juergen Schmied <j.schmied@metronet.de>
6 * Copyright 1998,2000 Eric Kohl
7 * Copyright 2014-2015 Michael Müller
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 * This code was audited for completeness against the documented features
26 * of Comctl32.dll version 6.0 on Oct. 21, 2002, by Christian Neumair.
28 * Unless otherwise noted, we believe this code to be complete, as per
29 * the specification mentioned above.
30 * If you discover missing features, or bugs, please note them below.
33 * -- implement GetMUILanguage + InitMUILanguage
34 * -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW
35 * -- FIXMEs + BUGS (search for them)
38 * -- ICC_ANIMATE_CLASS
43 * -- ICC_INTERNET_CLASSES
45 * -- ICC_LISTVIEW_CLASSES
46 * -- ICC_NATIVEFNTCTL_CLASS
47 * -- ICC_PAGESCROLLER_CLASS
48 * -- ICC_PROGRESS_CLASS
49 * -- ICC_STANDARD_CLASSES (not yet implemented)
51 * -- ICC_TREEVIEW_CLASSES
53 * -- ICC_USEREX_CLASSES
54 * -- ICC_WIN95_CLASSES
62 #define NONAMELESSUNION
72 #define NO_SHLWAPI_STREAM
75 #include "wine/debug.h"
77 WINE_DEFAULT_DEBUG_CHANNEL(commctrl
);
80 static LRESULT WINAPI
COMCTL32_SubclassProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
82 static LPWSTR COMCTL32_wSubclass
= NULL
;
83 HMODULE COMCTL32_hModule
= 0;
84 static LANGID COMCTL32_uiLang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
85 HBRUSH COMCTL32_hPattern55AABrush
= NULL
;
86 COMCTL32_SysColor comctl32_color
;
88 static HBITMAP COMCTL32_hPattern55AABitmap
= NULL
;
90 static const WORD wPattern55AA
[] =
92 0x5555, 0xaaaa, 0x5555, 0xaaaa,
93 0x5555, 0xaaaa, 0x5555, 0xaaaa
96 static const WCHAR strCC32SubclassInfo
[] = {
97 'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
100 static void unregister_versioned_classes(void)
102 #define VERSION "6.0.2600.2982!"
103 static const char *classes
[] =
106 VERSION WC_COMBOBOXA
,
114 for (i
= 0; i
< ARRAY_SIZE(classes
); i
++)
115 UnregisterClassA(classes
[i
], NULL
);
120 BOOL WINAPI
RegisterClassNameW(const WCHAR
*class)
124 const WCHAR nameW
[16];
125 void (*fn_register
)(void);
129 { {'B','u','t','t','o','n',0}, BUTTON_Register
},
130 { {'C','o','m','b','o','B','o','x',0}, COMBO_Register
},
131 { {'C','o','m','b','o','L','B','o','x',0}, COMBOLBOX_Register
},
132 { {'E','d','i','t',0}, EDIT_Register
},
133 { {'L','i','s','t','B','o','x',0}, LISTBOX_Register
},
134 { {'S','t','a','t','i','c',0}, STATIC_Register
},
137 int min
= 0, max
= ARRAY_SIZE(classes
) - 1;
141 int res
, pos
= (min
+ max
) / 2;
142 if (!(res
= wcsicmp(class, classes
[pos
].nameW
)))
144 classes
[pos
].fn_register();
147 if (res
< 0) max
= pos
- 1;
154 /***********************************************************************
157 * Initializes the internal 'COMCTL32.DLL'.
160 * hinstDLL [I] handle to the 'dlls' instance
162 * lpvReserved [I] reserved, must be NULL
169 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
171 TRACE("%p,%x,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
174 case DLL_PROCESS_ATTACH
:
175 DisableThreadLibraryCalls(hinstDLL
);
177 COMCTL32_hModule
= hinstDLL
;
179 /* add global subclassing atom (used by 'tooltip' and 'updown') */
180 COMCTL32_wSubclass
= (LPWSTR
)(DWORD_PTR
)GlobalAddAtomW (strCC32SubclassInfo
);
181 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass
);
183 /* create local pattern brush */
184 COMCTL32_hPattern55AABitmap
= CreateBitmap (8, 8, 1, 1, wPattern55AA
);
185 COMCTL32_hPattern55AABrush
= CreatePatternBrush (COMCTL32_hPattern55AABitmap
);
187 /* Get all the colors at DLL load */
188 COMCTL32_RefreshSysColors();
190 /* like comctl32 5.82+ register all the common control classes */
193 DATETIME_Register ();
197 IPADDRESS_Register ();
198 LISTVIEW_Register ();
199 MONTHCAL_Register ();
200 NATIVEFONT_Register ();
202 PROGRESS_Register ();
208 TOOLTIPS_Register ();
209 TRACKBAR_Register ();
210 TREEVIEW_Register ();
213 /* subclass user32 controls */
214 THEMING_Initialize ();
217 case DLL_PROCESS_DETACH
:
218 if (lpvReserved
) break;
219 /* clean up subclassing */
220 THEMING_Uninitialize();
222 /* unregister all common control classes */
223 ANIMATE_Unregister ();
224 COMBOEX_Unregister ();
225 DATETIME_Unregister ();
226 FLATSB_Unregister ();
227 HEADER_Unregister ();
228 HOTKEY_Unregister ();
229 IPADDRESS_Unregister ();
230 LISTVIEW_Unregister ();
231 MONTHCAL_Unregister ();
232 NATIVEFONT_Unregister ();
234 PROGRESS_Unregister ();
236 STATUS_Unregister ();
237 SYSLINK_Unregister ();
239 TOOLBAR_Unregister ();
240 TOOLTIPS_Unregister ();
241 TRACKBAR_Unregister ();
242 TREEVIEW_Unregister ();
243 UPDOWN_Unregister ();
245 unregister_versioned_classes ();
247 /* delete local pattern brush */
248 DeleteObject (COMCTL32_hPattern55AABrush
);
249 DeleteObject (COMCTL32_hPattern55AABitmap
);
251 /* delete global subclassing atom */
252 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass
));
253 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass
);
261 /***********************************************************************
262 * MenuHelp [COMCTL32.2]
264 * Handles the setting of status bar help messages when the user
265 * selects menu items.
268 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
269 * wParam [I] wParam of the message uMsg
270 * lParam [I] lParam of the message uMsg
271 * hMainMenu [I] handle to the application's main menu
272 * hInst [I] handle to the module that contains string resources
273 * hwndStatus [I] handle to the status bar window
274 * lpwIDs [I] pointer to an array of integers (see NOTES)
280 * The official documentation is incomplete!
281 * This is the correct documentation:
284 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
285 * WM_MENUSELECT messages.
288 * (will be written ...)
292 MenuHelp (UINT uMsg
, WPARAM wParam
, LPARAM lParam
, HMENU hMainMenu
,
293 HINSTANCE hInst
, HWND hwndStatus
, UINT
* lpwIDs
)
297 if (!IsWindow (hwndStatus
))
302 TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
305 if ((HIWORD(wParam
) == 0xFFFF) && (lParam
== 0)) {
306 /* menu was closed */
307 TRACE("menu was closed!\n");
308 SendMessageW (hwndStatus
, SB_SIMPLE
, FALSE
, 0);
311 /* menu item was selected */
312 if (HIWORD(wParam
) & MF_POPUP
)
313 uMenuID
= *(lpwIDs
+1);
315 uMenuID
= (UINT
)LOWORD(wParam
);
316 TRACE("uMenuID = %u\n", uMenuID
);
321 if (!LoadStringW (hInst
, uMenuID
, szText
, ARRAY_SIZE(szText
)))
324 SendMessageW (hwndStatus
, SB_SETTEXTW
,
325 255 | SBT_NOBORDERS
, (LPARAM
)szText
);
326 SendMessageW (hwndStatus
, SB_SIMPLE
, TRUE
, 0);
332 TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
334 /* WM_COMMAND is not invalid since it is documented
335 * in the windows api reference. So don't output
336 * any FIXME for WM_COMMAND
338 WARN("We don't care about the WM_COMMAND\n");
342 FIXME("Invalid Message 0x%x!\n", uMsg
);
348 /***********************************************************************
349 * ShowHideMenuCtl [COMCTL32.3]
351 * Shows or hides controls and updates the corresponding menu item.
354 * hwnd [I] handle to the client window.
355 * uFlags [I] menu command id.
356 * lpInfo [I] pointer to an array of integers. (See NOTES.)
363 * The official documentation is incomplete!
364 * This is the correct documentation:
367 * Handle to the window that contains the menu and controls.
370 * Identifier of the menu item to receive or lose a check mark.
373 * The array of integers contains pairs of values. BOTH values of
374 * the first pair must be the handles to the application's main menu.
375 * Each subsequent pair consists of a menu id and control id.
379 ShowHideMenuCtl (HWND hwnd
, UINT_PTR uFlags
, LPINT lpInfo
)
383 TRACE("%p, %lx, %p\n", hwnd
, uFlags
, lpInfo
);
388 if (!(lpInfo
[0]) || !(lpInfo
[1]))
391 /* search for control */
392 lpMenuId
= &lpInfo
[2];
393 while (*lpMenuId
!= uFlags
)
396 if (GetMenuState ((HMENU
)(DWORD_PTR
)lpInfo
[1], uFlags
, MF_BYCOMMAND
) & MFS_CHECKED
) {
397 /* uncheck menu item */
398 CheckMenuItem ((HMENU
)(DWORD_PTR
)lpInfo
[0], *lpMenuId
, MF_BYCOMMAND
| MF_UNCHECKED
);
402 SetWindowPos (GetDlgItem (hwnd
, *lpMenuId
), 0, 0, 0, 0, 0,
406 /* check menu item */
407 CheckMenuItem ((HMENU
)(DWORD_PTR
)lpInfo
[0], *lpMenuId
, MF_BYCOMMAND
| MF_CHECKED
);
411 SetWindowPos (GetDlgItem (hwnd
, *lpMenuId
), 0, 0, 0, 0, 0,
419 /***********************************************************************
420 * GetEffectiveClientRect [COMCTL32.4]
422 * Calculates the coordinates of a rectangle in the client area.
425 * hwnd [I] handle to the client window.
426 * lpRect [O] pointer to the rectangle of the client window
427 * lpInfo [I] pointer to an array of integers (see NOTES)
433 * The official documentation is incomplete!
434 * This is the correct documentation:
437 * (will be written ...)
441 GetEffectiveClientRect (HWND hwnd
, LPRECT lpRect
, const INT
*lpInfo
)
447 TRACE("(%p %p %p)\n",
448 hwnd
, lpRect
, lpInfo
);
450 GetClientRect (hwnd
, lpRect
);
458 hwndCtrl
= GetDlgItem (hwnd
, *lpRun
);
459 if (GetWindowLongW (hwndCtrl
, GWL_STYLE
) & WS_VISIBLE
) {
460 TRACE("control id 0x%x\n", *lpRun
);
461 GetWindowRect (hwndCtrl
, &rcCtrl
);
462 MapWindowPoints (NULL
, hwnd
, (LPPOINT
)&rcCtrl
, 2);
463 SubtractRect (lpRect
, lpRect
, &rcCtrl
);
470 /***********************************************************************
471 * DrawStatusTextW [COMCTL32.@]
473 * Draws text with borders, like in a status bar.
476 * hdc [I] handle to the window's display context
477 * lprc [I] pointer to a rectangle
478 * text [I] pointer to the text
479 * style [I] drawing style
485 * The style variable can have one of the following values:
486 * (will be written ...)
489 void WINAPI
DrawStatusTextW (HDC hdc
, LPCRECT lprc
, LPCWSTR text
, UINT style
)
492 UINT border
= BDR_SUNKENOUTER
;
495 if (style
& SBT_POPOUT
)
496 border
= BDR_RAISEDOUTER
;
497 else if (style
& SBT_NOBORDERS
)
500 oldbkcolor
= SetBkColor (hdc
, comctl32_color
.clrBtnFace
);
501 DrawEdge (hdc
, &r
, border
, BF_MIDDLE
|BF_RECT
|BF_ADJUST
);
505 int oldbkmode
= SetBkMode (hdc
, TRANSPARENT
);
506 COLORREF oldtextcolor
;
507 UINT align
= DT_LEFT
;
510 oldtextcolor
= SetTextColor (hdc
, comctl32_color
.clrBtnText
);
511 if (style
& SBT_RTLREADING
)
512 FIXME("Unsupported RTL style!\n");
517 DrawTextW (hdc
, text
- strCnt
, strCnt
, &r
, align
|DT_VCENTER
|DT_SINGLELINE
|DT_NOPREFIX
);
520 if (align
==DT_RIGHT
) {
523 align
= (align
==DT_LEFT
? DT_CENTER
: DT_RIGHT
);
529 if (strCnt
) DrawTextW (hdc
, text
- strCnt
, -1, &r
, align
|DT_VCENTER
|DT_SINGLELINE
|DT_NOPREFIX
);
530 SetBkMode (hdc
, oldbkmode
);
531 SetTextColor (hdc
, oldtextcolor
);
534 SetBkColor (hdc
, oldbkcolor
);
538 /***********************************************************************
539 * DrawStatusText [COMCTL32.@]
540 * DrawStatusTextA [COMCTL32.5]
542 * Draws text with borders, like in a status bar.
545 * hdc [I] handle to the window's display context
546 * lprc [I] pointer to a rectangle
547 * text [I] pointer to the text
548 * style [I] drawing style
554 void WINAPI
DrawStatusTextA (HDC hdc
, LPCRECT lprc
, LPCSTR text
, UINT style
)
560 if ( (len
= MultiByteToWideChar( CP_ACP
, 0, text
, -1, NULL
, 0 )) ) {
561 if ( (textW
= Alloc( len
* sizeof(WCHAR
) )) )
562 MultiByteToWideChar( CP_ACP
, 0, text
, -1, textW
, len
);
565 DrawStatusTextW( hdc
, lprc
, textW
, style
);
570 /***********************************************************************
571 * CreateStatusWindow [COMCTL32.@]
572 * CreateStatusWindowA [COMCTL32.6]
574 * Creates a status bar
577 * style [I] window style
578 * text [I] pointer to the window text
579 * parent [I] handle to the parent window
580 * wid [I] control id of the status bar
583 * Success: handle to the status window
588 CreateStatusWindowA (LONG style
, LPCSTR text
, HWND parent
, UINT wid
)
590 return CreateWindowA(STATUSCLASSNAMEA
, text
, style
,
591 CW_USEDEFAULT
, CW_USEDEFAULT
,
592 CW_USEDEFAULT
, CW_USEDEFAULT
,
593 parent
, (HMENU
)(DWORD_PTR
)wid
, 0, 0);
597 /***********************************************************************
598 * CreateStatusWindowW [COMCTL32.@]
600 * Creates a status bar control
603 * style [I] window style
604 * text [I] pointer to the window text
605 * parent [I] handle to the parent window
606 * wid [I] control id of the status bar
609 * Success: handle to the status window
614 CreateStatusWindowW (LONG style
, LPCWSTR text
, HWND parent
, UINT wid
)
616 return CreateWindowW(STATUSCLASSNAMEW
, text
, style
,
617 CW_USEDEFAULT
, CW_USEDEFAULT
,
618 CW_USEDEFAULT
, CW_USEDEFAULT
,
619 parent
, (HMENU
)(DWORD_PTR
)wid
, 0, 0);
623 /***********************************************************************
624 * CreateUpDownControl [COMCTL32.16]
626 * Creates an up-down control
629 * style [I] window styles
630 * x [I] horizontal position of the control
631 * y [I] vertical position of the control
632 * cx [I] with of the control
633 * cy [I] height of the control
634 * parent [I] handle to the parent window
635 * id [I] the control's identifier
636 * inst [I] handle to the application's module instance
637 * buddy [I] handle to the buddy window, can be NULL
638 * maxVal [I] upper limit of the control
639 * minVal [I] lower limit of the control
640 * curVal [I] current value of the control
643 * Success: handle to the updown control
648 CreateUpDownControl (DWORD style
, INT x
, INT y
, INT cx
, INT cy
,
649 HWND parent
, INT id
, HINSTANCE inst
,
650 HWND buddy
, INT maxVal
, INT minVal
, INT curVal
)
653 CreateWindowW (UPDOWN_CLASSW
, 0, style
, x
, y
, cx
, cy
,
654 parent
, (HMENU
)(DWORD_PTR
)id
, inst
, 0);
656 SendMessageW (hUD
, UDM_SETBUDDY
, (WPARAM
)buddy
, 0);
657 SendMessageW (hUD
, UDM_SETRANGE
, 0, MAKELONG(maxVal
, minVal
));
658 SendMessageW (hUD
, UDM_SETPOS
, 0, MAKELONG(curVal
, 0));
665 /***********************************************************************
666 * InitCommonControls [COMCTL32.17]
668 * Registers the common controls.
677 * This function is just a dummy - all the controls are registered at
678 * the DLL initialization time. See InitCommonControlsEx for details.
682 InitCommonControls (void)
687 /***********************************************************************
688 * InitCommonControlsEx [COMCTL32.@]
690 * Registers the common controls.
693 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
700 * Probably all versions of comctl32 initializes the Win95 controls in DllMain
701 * during DLL initialization. Starting from comctl32 v5.82 all the controls
702 * are initialized there. We follow this behaviour and this function is just
705 * Note: when writing programs under Windows, if you don't call any function
706 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
707 * was the only comctl32 function you were calling and you remove it you may
708 * have a false impression that InitCommonControlsEx actually did something.
712 InitCommonControlsEx (const INITCOMMONCONTROLSEX
*lpInitCtrls
)
714 if (!lpInitCtrls
|| lpInitCtrls
->dwSize
!= sizeof(INITCOMMONCONTROLSEX
))
717 TRACE("(0x%08x)\n", lpInitCtrls
->dwICC
);
722 /***********************************************************************
723 * CreateToolbarEx [COMCTL32.@]
725 * Creates a toolbar window.
743 * Success: handle to the tool bar control
748 CreateToolbarEx (HWND hwnd
, DWORD style
, UINT wID
, INT nBitmaps
,
749 HINSTANCE hBMInst
, UINT_PTR wBMID
, LPCTBBUTTON lpButtons
,
750 INT iNumButtons
, INT dxButton
, INT dyButton
,
751 INT dxBitmap
, INT dyBitmap
, UINT uStructSize
)
756 CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
, style
|WS_CHILD
, 0,0,100,30,
757 hwnd
, (HMENU
)(DWORD_PTR
)wID
, COMCTL32_hModule
, NULL
);
761 SendMessageW (hwndTB
, TB_BUTTONSTRUCTSIZE
, uStructSize
, 0);
763 /* set bitmap and button size */
764 /*If CreateToolbarEx receives 0, windows sets default values*/
769 if (dxBitmap
== 0 || dyBitmap
== 0)
770 dxBitmap
= dyBitmap
= 16;
771 SendMessageW(hwndTB
, TB_SETBITMAPSIZE
, 0, MAKELPARAM(dxBitmap
, dyBitmap
));
777 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
778 if (dxButton
!= 0 && dyButton
!= 0)
779 SendMessageW(hwndTB
, TB_SETBITMAPSIZE
, 0, MAKELPARAM(dxButton
, dyButton
));
783 if (nBitmaps
> 0 || hBMInst
== HINST_COMMCTRL
)
785 tbab
.hInst
= hBMInst
;
788 SendMessageW (hwndTB
, TB_ADDBITMAP
, nBitmaps
, (LPARAM
)&tbab
);
792 SendMessageW (hwndTB
, TB_ADDBUTTONSW
, iNumButtons
, (LPARAM
)lpButtons
);
799 /***********************************************************************
800 * CreateMappedBitmap [COMCTL32.8]
802 * Loads a bitmap resource using a colour map.
805 * hInstance [I] Handle to the module containing the bitmap.
806 * idBitmap [I] The bitmap resource ID.
807 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
808 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
809 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
812 * Success: handle to the new bitmap
817 CreateMappedBitmap (HINSTANCE hInstance
, INT_PTR idBitmap
, UINT wFlags
,
818 LPCOLORMAP lpColorMap
, INT iNumMaps
)
822 const BITMAPINFOHEADER
*lpBitmap
;
823 LPBITMAPINFOHEADER lpBitmapInfo
;
824 UINT nSize
, nColorTableSize
, iColor
;
825 RGBQUAD
*pColorTable
;
826 INT i
, iMaps
, nWidth
, nHeight
;
829 LPCOLORMAP sysColorMap
;
831 COLORMAP internalColorMap
[4] =
832 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
834 /* initialize pointer to colortable and default color table */
837 sysColorMap
= lpColorMap
;
840 internalColorMap
[0].to
= GetSysColor (COLOR_BTNTEXT
);
841 internalColorMap
[1].to
= GetSysColor (COLOR_BTNSHADOW
);
842 internalColorMap
[2].to
= GetSysColor (COLOR_BTNFACE
);
843 internalColorMap
[3].to
= GetSysColor (COLOR_BTNHIGHLIGHT
);
845 sysColorMap
= internalColorMap
;
848 hRsrc
= FindResourceW (hInstance
, (LPWSTR
)idBitmap
, (LPWSTR
)RT_BITMAP
);
851 hglb
= LoadResource (hInstance
, hRsrc
);
854 lpBitmap
= LockResource (hglb
);
855 if (lpBitmap
== NULL
)
858 if (lpBitmap
->biSize
>= sizeof(BITMAPINFOHEADER
) && lpBitmap
->biClrUsed
)
859 nColorTableSize
= lpBitmap
->biClrUsed
;
860 else if (lpBitmap
->biBitCount
<= 8)
861 nColorTableSize
= (1 << lpBitmap
->biBitCount
);
864 nSize
= lpBitmap
->biSize
;
865 if (nSize
== sizeof(BITMAPINFOHEADER
) && lpBitmap
->biCompression
== BI_BITFIELDS
)
866 nSize
+= 3 * sizeof(DWORD
);
867 nSize
+= nColorTableSize
* sizeof(RGBQUAD
);
868 lpBitmapInfo
= GlobalAlloc (GMEM_FIXED
, nSize
);
869 if (lpBitmapInfo
== NULL
)
871 RtlMoveMemory (lpBitmapInfo
, lpBitmap
, nSize
);
873 pColorTable
= (RGBQUAD
*)(((LPBYTE
)lpBitmapInfo
) + lpBitmapInfo
->biSize
);
875 for (iColor
= 0; iColor
< nColorTableSize
; iColor
++) {
876 for (i
= 0; i
< iMaps
; i
++) {
877 cRef
= RGB(pColorTable
[iColor
].rgbRed
,
878 pColorTable
[iColor
].rgbGreen
,
879 pColorTable
[iColor
].rgbBlue
);
880 if ( cRef
== sysColorMap
[i
].from
) {
882 if (wFlags
& CBS_MASKED
) {
883 if (sysColorMap
[i
].to
!= COLOR_BTNTEXT
)
884 pColorTable
[iColor
] = RGB(255, 255, 255);
888 pColorTable
[iColor
].rgbBlue
= GetBValue(sysColorMap
[i
].to
);
889 pColorTable
[iColor
].rgbGreen
= GetGValue(sysColorMap
[i
].to
);
890 pColorTable
[iColor
].rgbRed
= GetRValue(sysColorMap
[i
].to
);
895 nWidth
= lpBitmapInfo
->biWidth
;
896 nHeight
= lpBitmapInfo
->biHeight
;
897 hdcScreen
= GetDC (NULL
);
898 hbm
= CreateCompatibleBitmap (hdcScreen
, nWidth
, nHeight
);
900 HDC hdcDst
= CreateCompatibleDC (hdcScreen
);
901 HBITMAP hbmOld
= SelectObject (hdcDst
, hbm
);
902 const BYTE
*lpBits
= (const BYTE
*)lpBitmap
+ nSize
;
903 StretchDIBits (hdcDst
, 0, 0, nWidth
, nHeight
, 0, 0, nWidth
, nHeight
,
904 lpBits
, (LPBITMAPINFO
)lpBitmapInfo
, DIB_RGB_COLORS
,
906 SelectObject (hdcDst
, hbmOld
);
909 ReleaseDC (NULL
, hdcScreen
);
910 GlobalFree (lpBitmapInfo
);
917 /***********************************************************************
918 * CreateToolbar [COMCTL32.7]
920 * Creates a toolbar control.
933 * Success: handle to the tool bar control
937 * Do not use this function anymore. Use CreateToolbarEx instead.
941 CreateToolbar (HWND hwnd
, DWORD style
, UINT wID
, INT nBitmaps
,
942 HINSTANCE hBMInst
, UINT wBMID
,
943 LPCTBBUTTON lpButtons
,INT iNumButtons
)
945 return CreateToolbarEx (hwnd
, style
| CCS_NODIVIDER
, wID
, nBitmaps
,
946 hBMInst
, wBMID
, lpButtons
,
947 iNumButtons
, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON
, dwData
));
951 /***********************************************************************
952 * DllGetVersion [COMCTL32.@]
954 * Retrieves version information of the 'COMCTL32.DLL'
957 * pdvi [O] pointer to version information structure.
961 * Failure: E_INVALIDARG
964 * Returns version of a comctl32.dll from IE4.01 SP1.
967 HRESULT WINAPI
DllGetVersion (DLLVERSIONINFO
*pdvi
)
969 if (pdvi
->cbSize
!= sizeof(DLLVERSIONINFO
)) {
970 WARN("wrong DLLVERSIONINFO size from app\n");
974 pdvi
->dwMajorVersion
= COMCTL32_VERSION
;
975 pdvi
->dwMinorVersion
= COMCTL32_VERSION_MINOR
;
976 pdvi
->dwBuildNumber
= 2919;
977 pdvi
->dwPlatformID
= 6304;
979 TRACE("%u.%u.%u.%u\n",
980 pdvi
->dwMajorVersion
, pdvi
->dwMinorVersion
,
981 pdvi
->dwBuildNumber
, pdvi
->dwPlatformID
);
986 /***********************************************************************
987 * DllInstall (COMCTL32.@)
989 * Installs the ComCtl32 DLL.
993 * Failure: A HRESULT error
995 HRESULT WINAPI
DllInstall(BOOL bInstall
, LPCWSTR cmdline
)
997 TRACE("(%u, %s): stub\n", bInstall
, debugstr_w(cmdline
));
1001 /***********************************************************************
1002 * _TrackMouseEvent [COMCTL32.@]
1004 * Requests notification of mouse events
1006 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1007 * to the hwnd specified in the ptme structure. After the event message
1008 * is posted to the hwnd, the entry in the queue is removed.
1010 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1011 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1012 * immediately and the TME_LEAVE flag being ignored.
1015 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1021 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1026 _TrackMouseEvent (TRACKMOUSEEVENT
*ptme
)
1028 return TrackMouseEvent (ptme
);
1031 /*************************************************************************
1032 * GetMUILanguage [COMCTL32.@]
1034 * Returns the user interface language in use by the current process.
1037 * Language ID in use by the current process.
1039 LANGID WINAPI
GetMUILanguage (VOID
)
1041 return COMCTL32_uiLang
;
1045 /*************************************************************************
1046 * InitMUILanguage [COMCTL32.@]
1048 * Sets the user interface language to be used by the current process.
1053 VOID WINAPI
InitMUILanguage (LANGID uiLang
)
1055 COMCTL32_uiLang
= uiLang
;
1059 /***********************************************************************
1060 * SetWindowSubclass [COMCTL32.410]
1062 * Starts a window subclass
1065 * hWnd [in] handle to window subclass.
1066 * pfnSubclass [in] Pointer to new window procedure.
1067 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1068 * dwRef [in] Reference data to pass to window procedure.
1075 * If an application manually subclasses a window after subclassing it with
1076 * this API and then with this API again, then none of the previous
1077 * subclasses get called or the original window procedure.
1080 BOOL WINAPI
SetWindowSubclass (HWND hWnd
, SUBCLASSPROC pfnSubclass
,
1081 UINT_PTR uIDSubclass
, DWORD_PTR dwRef
)
1083 LPSUBCLASS_INFO stack
;
1084 LPSUBCLASSPROCS proc
;
1086 TRACE ("(%p, %p, %lx, %lx)\n", hWnd
, pfnSubclass
, uIDSubclass
, dwRef
);
1088 if (!hWnd
|| !pfnSubclass
)
1091 /* Since the window procedure that we set here has two additional arguments,
1092 * we can't simply set it as the new window procedure of the window. So we
1093 * set our own window procedure and then calculate the other two arguments
1096 /* See if we have been called for this window */
1097 stack
= GetPropW (hWnd
, COMCTL32_wSubclass
);
1099 /* allocate stack */
1100 stack
= Alloc (sizeof(SUBCLASS_INFO
));
1102 ERR ("Failed to allocate our Subclassing stack\n");
1105 SetPropW (hWnd
, COMCTL32_wSubclass
, stack
);
1107 /* set window procedure to our own and save the current one */
1108 if (IsWindowUnicode (hWnd
))
1109 stack
->origproc
= (WNDPROC
)SetWindowLongPtrW (hWnd
, GWLP_WNDPROC
,
1110 (DWORD_PTR
)COMCTL32_SubclassProc
);
1112 stack
->origproc
= (WNDPROC
)SetWindowLongPtrA (hWnd
, GWLP_WNDPROC
,
1113 (DWORD_PTR
)COMCTL32_SubclassProc
);
1116 /* Check to see if we have called this function with the same uIDSubClass
1117 * and pfnSubclass */
1118 proc
= stack
->SubclassProcs
;
1120 if ((proc
->id
== uIDSubclass
) &&
1121 (proc
->subproc
== pfnSubclass
)) {
1129 proc
= Alloc(sizeof(SUBCLASSPROCS
));
1131 ERR ("Failed to allocate subclass entry in stack\n");
1132 if (IsWindowUnicode (hWnd
))
1133 SetWindowLongPtrW (hWnd
, GWLP_WNDPROC
, (DWORD_PTR
)stack
->origproc
);
1135 SetWindowLongPtrA (hWnd
, GWLP_WNDPROC
, (DWORD_PTR
)stack
->origproc
);
1137 RemovePropW( hWnd
, COMCTL32_wSubclass
);
1141 proc
->subproc
= pfnSubclass
;
1143 proc
->id
= uIDSubclass
;
1144 proc
->next
= stack
->SubclassProcs
;
1145 stack
->SubclassProcs
= proc
;
1151 /***********************************************************************
1152 * GetWindowSubclass [COMCTL32.411]
1154 * Gets the Reference data from a subclass.
1157 * hWnd [in] Handle to the window which we are subclassing
1158 * pfnSubclass [in] Pointer to the subclass procedure
1159 * uID [in] Unique identifier of the subclassing procedure
1160 * pdwRef [out] Pointer to the reference data
1167 BOOL WINAPI
GetWindowSubclass (HWND hWnd
, SUBCLASSPROC pfnSubclass
,
1168 UINT_PTR uID
, DWORD_PTR
*pdwRef
)
1170 const SUBCLASS_INFO
*stack
;
1171 const SUBCLASSPROCS
*proc
;
1173 TRACE ("(%p, %p, %lx, %p)\n", hWnd
, pfnSubclass
, uID
, pdwRef
);
1175 /* See if we have been called for this window */
1176 stack
= GetPropW (hWnd
, COMCTL32_wSubclass
);
1180 proc
= stack
->SubclassProcs
;
1182 if ((proc
->id
== uID
) &&
1183 (proc
->subproc
== pfnSubclass
)) {
1184 *pdwRef
= proc
->ref
;
1194 /***********************************************************************
1195 * RemoveWindowSubclass [COMCTL32.412]
1197 * Removes a window subclass.
1200 * hWnd [in] Handle to the window which we are subclassing
1201 * pfnSubclass [in] Pointer to the subclass procedure
1202 * uID [in] Unique identifier of this subclass
1209 BOOL WINAPI
RemoveWindowSubclass(HWND hWnd
, SUBCLASSPROC pfnSubclass
, UINT_PTR uID
)
1211 LPSUBCLASS_INFO stack
;
1212 LPSUBCLASSPROCS prevproc
= NULL
;
1213 LPSUBCLASSPROCS proc
;
1216 TRACE ("(%p, %p, %lx)\n", hWnd
, pfnSubclass
, uID
);
1218 /* Find the Subclass to remove */
1219 stack
= GetPropW (hWnd
, COMCTL32_wSubclass
);
1223 proc
= stack
->SubclassProcs
;
1225 if ((proc
->id
== uID
) &&
1226 (proc
->subproc
== pfnSubclass
)) {
1229 stack
->SubclassProcs
= proc
->next
;
1231 prevproc
->next
= proc
->next
;
1233 if (stack
->stackpos
== proc
)
1234 stack
->stackpos
= stack
->stackpos
->next
;
1244 if (!stack
->SubclassProcs
&& !stack
->running
) {
1245 TRACE("Last Subclass removed, cleaning up\n");
1246 /* clean up our heap and reset the original window procedure */
1247 if (IsWindowUnicode (hWnd
))
1248 SetWindowLongPtrW (hWnd
, GWLP_WNDPROC
, (DWORD_PTR
)stack
->origproc
);
1250 SetWindowLongPtrA (hWnd
, GWLP_WNDPROC
, (DWORD_PTR
)stack
->origproc
);
1252 RemovePropW( hWnd
, COMCTL32_wSubclass
);
1258 /***********************************************************************
1259 * COMCTL32_SubclassProc (internal)
1261 * Window procedure for all subclassed windows.
1262 * Saves the current subclassing stack position to support nested messages
1264 static LRESULT WINAPI
COMCTL32_SubclassProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1266 LPSUBCLASS_INFO stack
;
1267 LPSUBCLASSPROCS proc
;
1270 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd
, uMsg
, wParam
, lParam
);
1272 stack
= GetPropW (hWnd
, COMCTL32_wSubclass
);
1274 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd
);
1278 /* Save our old stackpos to properly handle nested messages */
1279 proc
= stack
->stackpos
;
1280 stack
->stackpos
= stack
->SubclassProcs
;
1282 ret
= DefSubclassProc(hWnd
, uMsg
, wParam
, lParam
);
1284 stack
->stackpos
= proc
;
1286 if (!stack
->SubclassProcs
&& !stack
->running
) {
1287 TRACE("Last Subclass removed, cleaning up\n");
1288 /* clean up our heap and reset the original window procedure */
1289 if (IsWindowUnicode (hWnd
))
1290 SetWindowLongPtrW (hWnd
, GWLP_WNDPROC
, (DWORD_PTR
)stack
->origproc
);
1292 SetWindowLongPtrA (hWnd
, GWLP_WNDPROC
, (DWORD_PTR
)stack
->origproc
);
1294 RemovePropW( hWnd
, COMCTL32_wSubclass
);
1299 /***********************************************************************
1300 * DefSubclassProc [COMCTL32.413]
1302 * Calls the next window procedure (i.e. the one before this subclass)
1305 * hWnd [in] The window that we're subclassing
1307 * wParam [in] WPARAM
1308 * lParam [in] LPARAM
1315 LRESULT WINAPI
DefSubclassProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1317 LPSUBCLASS_INFO stack
;
1320 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd
, uMsg
, wParam
, lParam
);
1322 /* retrieve our little stack from the Properties */
1323 stack
= GetPropW (hWnd
, COMCTL32_wSubclass
);
1325 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd
);
1329 /* If we are at the end of stack then we have to call the original
1330 * window procedure */
1331 if (!stack
->stackpos
) {
1332 if (IsWindowUnicode (hWnd
))
1333 ret
= CallWindowProcW (stack
->origproc
, hWnd
, uMsg
, wParam
, lParam
);
1335 ret
= CallWindowProcA (stack
->origproc
, hWnd
, uMsg
, wParam
, lParam
);
1337 const SUBCLASSPROCS
*proc
= stack
->stackpos
;
1338 stack
->stackpos
= stack
->stackpos
->next
;
1339 /* call the Subclass procedure from the stack */
1340 ret
= proc
->subproc (hWnd
, uMsg
, wParam
, lParam
,
1341 proc
->id
, proc
->ref
);
1348 /***********************************************************************
1349 * COMCTL32_CreateToolTip [NOT AN API]
1351 * Creates a tooltip for the control specified in hwnd and does all
1352 * necessary setup and notifications.
1355 * hwndOwner [I] Handle to the window that will own the tool tip.
1358 * Success: Handle of tool tip window.
1363 COMCTL32_CreateToolTip(HWND hwndOwner
)
1367 hwndToolTip
= CreateWindowExW(0, TOOLTIPS_CLASSW
, NULL
, WS_POPUP
,
1368 CW_USEDEFAULT
, CW_USEDEFAULT
,
1369 CW_USEDEFAULT
, CW_USEDEFAULT
, hwndOwner
,
1372 /* Send NM_TOOLTIPSCREATED notification */
1375 NMTOOLTIPSCREATED nmttc
;
1376 /* true owner can be different if hwndOwner is a child window */
1377 HWND hwndTrueOwner
= GetWindow(hwndToolTip
, GW_OWNER
);
1378 nmttc
.hdr
.hwndFrom
= hwndTrueOwner
;
1379 nmttc
.hdr
.idFrom
= GetWindowLongPtrW(hwndTrueOwner
, GWLP_ID
);
1380 nmttc
.hdr
.code
= NM_TOOLTIPSCREATED
;
1381 nmttc
.hwndToolTips
= hwndToolTip
;
1383 SendMessageW(GetParent(hwndTrueOwner
), WM_NOTIFY
,
1384 GetWindowLongPtrW(hwndTrueOwner
, GWLP_ID
), (LPARAM
)&nmttc
);
1391 /***********************************************************************
1392 * COMCTL32_RefreshSysColors [NOT AN API]
1394 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1395 * refresh the color values in the color structure
1405 COMCTL32_RefreshSysColors(void)
1407 comctl32_color
.clrBtnHighlight
= GetSysColor (COLOR_BTNHIGHLIGHT
);
1408 comctl32_color
.clrBtnShadow
= GetSysColor (COLOR_BTNSHADOW
);
1409 comctl32_color
.clrBtnText
= GetSysColor (COLOR_BTNTEXT
);
1410 comctl32_color
.clrBtnFace
= GetSysColor (COLOR_BTNFACE
);
1411 comctl32_color
.clrHighlight
= GetSysColor (COLOR_HIGHLIGHT
);
1412 comctl32_color
.clrHighlightText
= GetSysColor (COLOR_HIGHLIGHTTEXT
);
1413 comctl32_color
.clrHotTrackingColor
= GetSysColor (COLOR_HOTLIGHT
);
1414 comctl32_color
.clr3dHilight
= GetSysColor (COLOR_3DHILIGHT
);
1415 comctl32_color
.clr3dShadow
= GetSysColor (COLOR_3DSHADOW
);
1416 comctl32_color
.clr3dDkShadow
= GetSysColor (COLOR_3DDKSHADOW
);
1417 comctl32_color
.clr3dFace
= GetSysColor (COLOR_3DFACE
);
1418 comctl32_color
.clrWindow
= GetSysColor (COLOR_WINDOW
);
1419 comctl32_color
.clrWindowText
= GetSysColor (COLOR_WINDOWTEXT
);
1420 comctl32_color
.clrGrayText
= GetSysColor (COLOR_GRAYTEXT
);
1421 comctl32_color
.clrActiveCaption
= GetSysColor (COLOR_ACTIVECAPTION
);
1422 comctl32_color
.clrInfoBk
= GetSysColor (COLOR_INFOBK
);
1423 comctl32_color
.clrInfoText
= GetSysColor (COLOR_INFOTEXT
);
1426 /***********************************************************************
1427 * COMCTL32_DrawInsertMark [NOT AN API]
1429 * Draws an insertion mark (which looks similar to an 'I').
1432 * hDC [I] Device context to draw onto.
1433 * lpRect [I] Co-ordinates of insertion mark.
1434 * clrInsertMark [I] Colour of the insertion mark.
1435 * bHorizontal [I] True if insert mark should be drawn horizontally,
1436 * vertical otherwise.
1442 * Draws up to but not including the bottom co-ordinate when drawing
1443 * vertically or the right co-ordinate when horizontal.
1445 void COMCTL32_DrawInsertMark(HDC hDC
, const RECT
*lpRect
, COLORREF clrInsertMark
, BOOL bHorizontal
)
1447 HPEN hPen
= CreatePen(PS_SOLID
, 1, clrInsertMark
);
1449 static const DWORD adwPolyPoints
[] = {4,4,4};
1450 LONG lCentre
= (bHorizontal
?
1451 lpRect
->top
+ (lpRect
->bottom
- lpRect
->top
)/2 :
1452 lpRect
->left
+ (lpRect
->right
- lpRect
->left
)/2);
1453 LONG l1
= (bHorizontal
? lpRect
->left
: lpRect
->top
);
1454 LONG l2
= (bHorizontal
? lpRect
->right
: lpRect
->bottom
);
1455 const POINT aptInsertMark
[] =
1457 /* top (V) or left (H) arrow */
1461 {lCentre
+ 1, l1
+ 2},
1465 {lCentre
+ 1, l1
- 1},
1466 {lCentre
+ 1, l2
- 2},
1467 /* bottom (V) or right (H) arrow */
1469 {lCentre
- 2, l2
- 1},
1470 {lCentre
+ 3, l2
- 1},
1471 {lCentre
+ 1, l2
- 3},
1473 hOldPen
= SelectObject(hDC
, hPen
);
1474 PolyPolyline(hDC
, aptInsertMark
, adwPolyPoints
, ARRAY_SIZE(adwPolyPoints
));
1475 SelectObject(hDC
, hOldPen
);
1479 /***********************************************************************
1480 * COMCTL32_EnsureBitmapSize [internal]
1482 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1483 * the height is at least cyMinHeight. If the bitmap already has these
1484 * dimensions nothing changes.
1487 * hBitmap [I/O] Bitmap to modify. The handle may change
1488 * cxMinWidth [I] If the width of the bitmap is smaller, then it will
1489 * be enlarged to this value
1490 * cyMinHeight [I] If the height of the bitmap is smaller, then it will
1491 * be enlarged to this value
1492 * cyBackground [I] The color with which the new area will be filled
1497 void COMCTL32_EnsureBitmapSize(HBITMAP
*pBitmap
, int cxMinWidth
, int cyMinHeight
, COLORREF crBackground
)
1502 HBITMAP hNewDCBitmap
, hOldDCBitmap
;
1506 if (!GetObjectW(*pBitmap
, sizeof(BITMAP
), &bmp
))
1508 cxNew
= (cxMinWidth
> bmp
.bmWidth
? cxMinWidth
: bmp
.bmWidth
);
1509 cyNew
= (cyMinHeight
> bmp
.bmHeight
? cyMinHeight
: bmp
.bmHeight
);
1510 if (cxNew
== bmp
.bmWidth
&& cyNew
== bmp
.bmHeight
)
1513 hdcNew
= CreateCompatibleDC(NULL
);
1514 hNewBitmap
= CreateBitmap(cxNew
, cyNew
, bmp
.bmPlanes
, bmp
.bmBitsPixel
, NULL
);
1515 hNewDCBitmap
= SelectObject(hdcNew
, hNewBitmap
);
1516 hNewDCBrush
= SelectObject(hdcNew
, CreateSolidBrush(crBackground
));
1518 hdcOld
= CreateCompatibleDC(NULL
);
1519 hOldDCBitmap
= SelectObject(hdcOld
, *pBitmap
);
1521 BitBlt(hdcNew
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, hdcOld
, 0, 0, SRCCOPY
);
1522 if (bmp
.bmWidth
< cxMinWidth
)
1523 PatBlt(hdcNew
, bmp
.bmWidth
, 0, cxNew
, bmp
.bmHeight
, PATCOPY
);
1524 if (bmp
.bmHeight
< cyMinHeight
)
1525 PatBlt(hdcNew
, 0, bmp
.bmHeight
, bmp
.bmWidth
, cyNew
, PATCOPY
);
1526 if (bmp
.bmWidth
< cxMinWidth
&& bmp
.bmHeight
< cyMinHeight
)
1527 PatBlt(hdcNew
, bmp
.bmWidth
, bmp
.bmHeight
, cxNew
, cyNew
, PATCOPY
);
1529 SelectObject(hdcNew
, hNewDCBitmap
);
1530 DeleteObject(SelectObject(hdcNew
, hNewDCBrush
));
1532 SelectObject(hdcOld
, hOldDCBitmap
);
1535 DeleteObject(*pBitmap
);
1536 *pBitmap
= hNewBitmap
;
1540 void COMCTL32_GetFontMetrics(HFONT hFont
, TEXTMETRICW
*ptm
)
1542 HDC hdc
= GetDC(NULL
);
1545 hOldFont
= SelectObject(hdc
, hFont
);
1546 GetTextMetricsW(hdc
, ptm
);
1547 SelectObject(hdc
, hOldFont
);
1548 ReleaseDC(NULL
, hdc
);
1551 #ifndef OCM__BASE /* avoid including olectl.h */
1552 #define OCM__BASE (WM_USER+0x1c00)
1555 /***********************************************************************
1556 * COMCTL32_IsReflectedMessage [internal]
1558 * Some parents reflect notify messages - for some messages sent by the child,
1559 * they send it back with the message code increased by OCM__BASE (0x2000).
1560 * This allows better subclassing of controls. We don't need to handle such
1561 * messages but we don't want to print ERRs for them, so this helper function
1564 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1565 * collision with defined CCM_ codes.
1567 BOOL
COMCTL32_IsReflectedMessage(UINT uMsg
)
1571 case OCM__BASE
+ WM_COMMAND
:
1572 case OCM__BASE
+ WM_CTLCOLORBTN
:
1573 case OCM__BASE
+ WM_CTLCOLOREDIT
:
1574 case OCM__BASE
+ WM_CTLCOLORDLG
:
1575 case OCM__BASE
+ WM_CTLCOLORLISTBOX
:
1576 case OCM__BASE
+ WM_CTLCOLORMSGBOX
:
1577 case OCM__BASE
+ WM_CTLCOLORSCROLLBAR
:
1578 case OCM__BASE
+ WM_CTLCOLORSTATIC
:
1579 case OCM__BASE
+ WM_DRAWITEM
:
1580 case OCM__BASE
+ WM_MEASUREITEM
:
1581 case OCM__BASE
+ WM_DELETEITEM
:
1582 case OCM__BASE
+ WM_VKEYTOITEM
:
1583 case OCM__BASE
+ WM_CHARTOITEM
:
1584 case OCM__BASE
+ WM_COMPAREITEM
:
1585 case OCM__BASE
+ WM_HSCROLL
:
1586 case OCM__BASE
+ WM_VSCROLL
:
1587 case OCM__BASE
+ WM_PARENTNOTIFY
:
1588 case OCM__BASE
+ WM_NOTIFY
:
1595 /***********************************************************************
1596 * MirrorIcon [COMCTL32.414]
1598 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1601 * phicon1 [I/O] Icon.
1602 * phicon2 [I/O] Icon.
1608 BOOL WINAPI
MirrorIcon(HICON
*phicon1
, HICON
*phicon2
)
1610 FIXME("(%p, %p): stub\n", phicon1
, phicon2
);
1614 static inline BOOL
IsDelimiter(WCHAR c
)
1627 static int CALLBACK
PathWordBreakProc(LPCWSTR lpch
, int ichCurrent
, int cch
, int code
)
1629 if (code
== WB_ISDELIMITER
)
1630 return IsDelimiter(lpch
[ichCurrent
]);
1633 int dir
= (code
== WB_LEFT
) ? -1 : 1;
1634 for(; 0 <= ichCurrent
&& ichCurrent
< cch
; ichCurrent
+= dir
)
1635 if (IsDelimiter(lpch
[ichCurrent
])) return ichCurrent
;
1640 /***********************************************************************
1641 * SetPathWordBreakProc [COMCTL32.384]
1643 * Sets the word break procedure for an edit control to one that understands
1644 * paths so that the user can jump over directories.
1647 * hwnd [I] Handle to edit control.
1648 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1651 * Result from EM_SETWORDBREAKPROC message.
1653 LRESULT WINAPI
SetPathWordBreakProc(HWND hwnd
, BOOL bSet
)
1655 return SendMessageW(hwnd
, EM_SETWORDBREAKPROC
, 0,
1656 (LPARAM
)(bSet
? PathWordBreakProc
: NULL
));
1659 /***********************************************************************
1660 * DrawShadowText [COMCTL32.@]
1662 * Draw text with shadow.
1664 int WINAPI
DrawShadowText(HDC hdc
, LPCWSTR text
, UINT length
, RECT
*rect
, DWORD flags
,
1665 COLORREF crText
, COLORREF crShadow
, int offset_x
, int offset_y
)
1671 FIXME("(%p, %s, %d, %p, 0x%08x, 0x%08x, 0x%08x, %d, %d): semi-stub\n", hdc
, debugstr_w(text
),
1672 length
, rect
, flags
, crText
, crShadow
, offset_x
, offset_y
);
1674 bkmode
= SetBkMode(hdc
, TRANSPARENT
);
1675 clr
= SetTextColor(hdc
, crShadow
);
1677 /* FIXME: for shadow we need to render normally, blur it, and blend with current background. */
1679 OffsetRect(&r
, 1, 1);
1680 DrawTextW(hdc
, text
, length
, &r
, flags
);
1682 SetTextColor(hdc
, crText
);
1684 /* with text color on top of a shadow */
1685 ret
= DrawTextW(hdc
, text
, length
, rect
, flags
);
1687 SetTextColor(hdc
, clr
);
1688 SetBkMode(hdc
, bkmode
);
1693 /***********************************************************************
1694 * LoadIconWithScaleDown [COMCTL32.@]
1696 HRESULT WINAPI
LoadIconWithScaleDown(HINSTANCE hinst
, const WCHAR
*name
, int cx
, int cy
, HICON
*icon
)
1698 TRACE("(%p, %s, %d, %d, %p)\n", hinst
, debugstr_w(name
), cx
, cy
, icon
);
1703 return E_INVALIDARG
;
1705 *icon
= LoadImageW(hinst
, name
, IMAGE_ICON
, cx
, cy
,
1706 (hinst
|| IS_INTRESOURCE(name
)) ? 0 : LR_LOADFROMFILE
);
1708 return HRESULT_FROM_WIN32(GetLastError());
1713 /***********************************************************************
1714 * LoadIconMetric [COMCTL32.@]
1716 HRESULT WINAPI
LoadIconMetric(HINSTANCE hinst
, const WCHAR
*name
, int size
, HICON
*icon
)
1720 TRACE("(%p, %s, %d, %p)\n", hinst
, debugstr_w(name
), size
, icon
);
1722 if (size
== LIM_SMALL
)
1724 cx
= GetSystemMetrics(SM_CXSMICON
);
1725 cy
= GetSystemMetrics(SM_CYSMICON
);
1727 else if (size
== LIM_LARGE
)
1729 cx
= GetSystemMetrics(SM_CXICON
);
1730 cy
= GetSystemMetrics(SM_CYICON
);
1735 return E_INVALIDARG
;
1738 return LoadIconWithScaleDown(hinst
, name
, cx
, cy
, icon
);
1741 static const WCHAR strMRUList
[] = { 'M','R','U','L','i','s','t',0 };
1743 /**************************************************************************
1744 * Alloc [COMCTL32.71]
1746 * Allocates memory block from the dll's private heap
1748 void * WINAPI
Alloc(DWORD size
)
1750 return LocalAlloc(LMEM_ZEROINIT
, size
);
1753 /**************************************************************************
1754 * ReAlloc [COMCTL32.72]
1756 * Changes the size of an allocated memory block or allocates a memory
1757 * block using the dll's private heap.
1760 void * WINAPI
ReAlloc(void *src
, DWORD size
)
1763 return LocalReAlloc(src
, size
, LMEM_ZEROINIT
| LMEM_MOVEABLE
);
1765 return LocalAlloc(LMEM_ZEROINIT
, size
);
1768 /**************************************************************************
1769 * Free [COMCTL32.73]
1771 * Frees an allocated memory block from the dll's private heap.
1773 BOOL WINAPI
Free(void *mem
)
1775 return !LocalFree(mem
);
1778 /**************************************************************************
1779 * GetSize [COMCTL32.74]
1781 DWORD WINAPI
GetSize(void *mem
)
1783 return LocalSize(mem
);
1786 /**************************************************************************
1787 * MRU-Functions {COMCTL32}
1790 * The MRU-API is a set of functions to manipulate lists of M.R.U. (Most Recently
1791 * Used) items. It is an undocumented API that is used (at least) by the shell
1792 * and explorer to implement their recent documents feature.
1794 * Since these functions are undocumented, they are unsupported by MS and
1795 * may change at any time.
1797 * Internally, the list is implemented as a last in, last out list of items
1798 * persisted into the system registry under a caller chosen key. Each list
1799 * item is given a one character identifier in the Ascii range from 'a' to
1800 * '}'. A list of the identifiers in order from newest to oldest is stored
1801 * under the same key in a value named "MRUList".
1803 * Items are re-ordered by changing the order of the values in the MRUList
1804 * value. When a new item is added, it becomes the new value of the oldest
1805 * identifier, and that identifier is moved to the front of the MRUList value.
1807 * Wine stores MRU-lists in the same registry format as Windows, so when
1808 * switching between the builtin and native comctl32.dll no problems or
1809 * incompatibilities should occur.
1811 * The following undocumented structure is used to create an MRU-list:
1812 *|typedef INT (CALLBACK *MRUStringCmpFn)(LPCTSTR lhs, LPCTSTR rhs);
1813 *|typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
1815 *|typedef struct tagMRUINFO
1821 *| LPTSTR lpszSubKey;
1822 *| PROC lpfnCompare;
1823 *|} MRUINFO, *LPMRUINFO;
1826 * cbSize [I] The size of the MRUINFO structure. This must be set
1827 * to sizeof(MRUINFO) by the caller.
1828 * uMax [I] The maximum number of items allowed in the list. Because
1829 * of the limited number of identifiers, this should be set to
1830 * a value from 1 to 30 by the caller.
1831 * fFlags [I] If bit 0 is set, the list will be used to store binary
1832 * data, otherwise it is assumed to store strings. If bit 1
1833 * is set, every change made to the list will be reflected in
1834 * the registry immediately, otherwise changes will only be
1835 * written when the list is closed.
1836 * hKey [I] The registry key that the list should be written under.
1837 * This must be supplied by the caller.
1838 * lpszSubKey [I] A caller supplied name of a subkey under hKey to write
1839 * the list to. This may not be blank.
1840 * lpfnCompare [I] A caller supplied comparison function, which may be either
1841 * an MRUStringCmpFn if dwFlags does not have bit 0 set, or a
1842 * MRUBinaryCmpFn otherwise.
1845 * - Create an MRU-list with CreateMRUList() or CreateMRUListLazy().
1846 * - Add items to an MRU-list with AddMRUString() or AddMRUData().
1847 * - Remove items from an MRU-list with DelMRUString().
1848 * - Find data in an MRU-list with FindMRUString() or FindMRUData().
1849 * - Iterate through an MRU-list with EnumMRUList().
1850 * - Free an MRU-list with FreeMRUList().
1853 typedef INT (CALLBACK
*MRUStringCmpFnA
)(LPCSTR lhs
, LPCSTR rhs
);
1854 typedef INT (CALLBACK
*MRUStringCmpFnW
)(LPCWSTR lhs
, LPCWSTR rhs
);
1855 typedef INT (CALLBACK
*MRUBinaryCmpFn
)(LPCVOID lhs
, LPCVOID rhs
, DWORD length
);
1866 MRUStringCmpFnA string_cmpfn
;
1867 MRUBinaryCmpFn binary_cmpfn
;
1880 MRUStringCmpFnW string_cmpfn
;
1881 MRUBinaryCmpFn binary_cmpfn
;
1885 /* MRUINFO.fFlags */
1886 #define MRU_STRING 0 /* list will contain strings */
1887 #define MRU_BINARY 1 /* list will contain binary data */
1888 #define MRU_CACHEWRITE 2 /* only save list order to reg. is FreeMRUList */
1890 /* If list is a string list lpfnCompare has the following prototype
1891 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
1892 * for binary lists the prototype is
1893 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
1894 * where cbData is the no. of bytes to compare.
1895 * Need to check what return value means identical - 0?
1898 typedef struct tagWINEMRUITEM
1900 DWORD size
; /* size of data stored */
1901 DWORD itemFlag
; /* flags */
1903 } WINEMRUITEM
, *LPWINEMRUITEM
;
1906 #define WMRUIF_CHANGED 0x0001 /* this dataitem changed */
1908 typedef struct tagWINEMRULIST
1910 struct MRUINFOW extview
; /* original create information */
1911 BOOL isUnicode
; /* is compare fn Unicode */
1912 DWORD wineFlags
; /* internal flags */
1913 DWORD cursize
; /* current size of realMRU */
1914 LPWSTR realMRU
; /* pointer to string of index names */
1915 LPWINEMRUITEM
*array
; /* array of pointers to data */
1916 /* in 'a' to 'z' order */
1917 } WINEMRULIST
, *LPWINEMRULIST
;
1920 #define WMRUF_CHANGED 0x0001 /* MRU list has changed */
1922 /**************************************************************************
1923 * MRU_SaveChanged (internal)
1925 * Local MRU saving code
1927 static void MRU_SaveChanged(WINEMRULIST
*mp
)
1934 /* or should we do the following instead of RegOpenKeyEx:
1937 /* open the sub key */
1938 if ((err
= RegOpenKeyExW(mp
->extview
.hKey
, mp
->extview
.lpszSubKey
, 0, KEY_WRITE
, &newkey
)))
1940 /* not present - what to do ??? */
1941 ERR("Could not open key, error=%d, attempting to create\n", err
);
1942 if ((err
= RegCreateKeyExW( mp
->extview
.hKey
, mp
->extview
.lpszSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1943 KEY_READ
| KEY_WRITE
, 0, &newkey
, 0)))
1945 ERR("failed to create key /%s/, err=%d\n", debugstr_w(mp
->extview
.lpszSubKey
), err
);
1950 if (mp
->wineFlags
& WMRUF_CHANGED
)
1952 mp
->wineFlags
&= ~WMRUF_CHANGED
;
1953 if ((err
= RegSetValueExW(newkey
, strMRUList
, 0, REG_SZ
, (BYTE
*)mp
->realMRU
,
1954 (lstrlenW(mp
->realMRU
) + 1)*sizeof(WCHAR
))))
1956 ERR("error saving MRUList, err=%d\n", err
);
1958 TRACE("saving MRUList=/%s/\n", debugstr_w(mp
->realMRU
));
1962 for (i
= 0; i
< mp
->cursize
; ++i
)
1964 witem
= mp
->array
[i
];
1965 if (witem
->itemFlag
& WMRUIF_CHANGED
)
1967 witem
->itemFlag
&= ~WMRUIF_CHANGED
;
1968 realname
[0] = 'a' + i
;
1969 if ((err
= RegSetValueExW(newkey
, realname
, 0, (mp
->extview
.fFlags
& MRU_BINARY
) ?
1970 REG_BINARY
: REG_SZ
, &witem
->datastart
, witem
->size
)))
1972 ERR("error saving /%s/, err=%d\n", debugstr_w(realname
), err
);
1974 TRACE("saving value for name /%s/ size=%d\n", debugstr_w(realname
), witem
->size
);
1977 RegCloseKey(newkey
);
1980 /**************************************************************************
1981 * FreeMRUList [COMCTL32.152]
1983 * Frees a most-recently-used items list.
1985 void WINAPI
FreeMRUList(HANDLE hMRUList
)
1987 WINEMRULIST
*mp
= hMRUList
;
1990 TRACE("%p.\n", hMRUList
);
1995 if (mp
->wineFlags
& WMRUF_CHANGED
)
1997 /* need to open key and then save the info */
1998 MRU_SaveChanged(mp
);
2001 for (i
= 0; i
< mp
->extview
.uMax
; ++i
)
2006 Free(mp
->extview
.lpszSubKey
);
2010 /**************************************************************************
2011 * FindMRUData [COMCTL32.169]
2013 * Searches binary list for item that matches data of given length.
2014 * Returns position in list order 0 -> MRU and value corresponding to item's reg.
2015 * name will be stored in it ('a' -> 0).
2018 INT WINAPI
FindMRUData(HANDLE hList
, const void *data
, DWORD cbData
, int *pos
)
2020 const WINEMRULIST
*mp
= hList
;
2025 if (!mp
|| !mp
->extview
.u
.string_cmpfn
)
2028 if (!(mp
->extview
.fFlags
& MRU_BINARY
) && !mp
->isUnicode
)
2030 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, data
, -1, NULL
, 0, NULL
, NULL
);
2032 WideCharToMultiByte(CP_ACP
, 0, data
, -1, dataA
, len
, NULL
, NULL
);
2035 for (i
= 0; i
< mp
->cursize
; ++i
)
2037 if (mp
->extview
.fFlags
& MRU_BINARY
)
2039 if (!mp
->extview
.u
.binary_cmpfn(data
, &mp
->array
[i
]->datastart
, cbData
))
2046 if (!mp
->extview
.u
.string_cmpfn(data
, (LPWSTR
)&mp
->array
[i
]->datastart
))
2051 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)&mp
->array
[i
]->datastart
, -1,
2052 NULL
, 0, NULL
, NULL
);
2053 LPSTR itemA
= Alloc(len
);
2055 WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)&mp
->array
[i
]->datastart
, -1, itemA
, len
, NULL
, NULL
);
2057 cmp
= mp
->extview
.u
.string_cmpfn((LPWSTR
)dataA
, (LPWSTR
)itemA
);
2066 if (i
< mp
->cursize
)
2070 if (pos
&& (ret
!= -1))
2073 TRACE("%p, %p, %d, %p, returning %d.\n", hList
, data
, cbData
, pos
, ret
);
2078 /**************************************************************************
2079 * AddMRUData [COMCTL32.167]
2081 * Add item to MRU binary list. If item already exists in list then it is
2082 * simply moved up to the top of the list and not added again. If list is
2083 * full then the least recently used item is removed to make room.
2086 INT WINAPI
AddMRUData(HANDLE hList
, const void *data
, DWORD cbData
)
2088 WINEMRULIST
*mp
= hList
;
2092 if ((replace
= FindMRUData(hList
, data
, cbData
, NULL
)) >= 0)
2094 /* Item exists, just move it to the front */
2095 LPWSTR pos
= wcschr(mp
->realMRU
, replace
+ 'a');
2096 while (pos
> mp
->realMRU
)
2104 /* either add a new entry or replace oldest */
2105 if (mp
->cursize
< mp
->extview
.uMax
)
2107 /* Add in a new item */
2108 replace
= mp
->cursize
;
2113 /* get the oldest entry and replace data */
2114 replace
= mp
->realMRU
[mp
->cursize
- 1] - 'a';
2115 Free(mp
->array
[replace
]);
2118 /* Allocate space for new item and move in the data */
2119 mp
->array
[replace
] = witem
= Alloc(cbData
+ sizeof(WINEMRUITEM
));
2120 witem
->itemFlag
|= WMRUIF_CHANGED
;
2121 witem
->size
= cbData
;
2122 memcpy( &witem
->datastart
, data
, cbData
);
2124 /* now rotate MRU list */
2125 for (i
= mp
->cursize
- 1; i
>= 1; --i
)
2126 mp
->realMRU
[i
] = mp
->realMRU
[i
-1];
2129 /* The new item gets the front spot */
2130 mp
->wineFlags
|= WMRUF_CHANGED
;
2131 mp
->realMRU
[0] = replace
+ 'a';
2133 TRACE("(%p, %p, %d) adding data, /%c/ now most current\n", hList
, data
, cbData
, replace
+'a');
2135 if (!(mp
->extview
.fFlags
& MRU_CACHEWRITE
))
2137 /* save changed stuff right now */
2138 MRU_SaveChanged(mp
);
2144 /**************************************************************************
2145 * AddMRUStringW [COMCTL32.401]
2147 * Add an item to an MRU string list.
2150 INT WINAPI
AddMRUStringW(HANDLE hList
, const WCHAR
*str
)
2152 TRACE("%p, %s.\n", hList
, debugstr_w(str
));
2157 if (!str
|| IsBadStringPtrW(str
, -1))
2159 SetLastError(ERROR_INVALID_PARAMETER
);
2163 return AddMRUData(hList
, str
, (lstrlenW(str
) + 1) * sizeof(WCHAR
));
2166 /**************************************************************************
2167 * AddMRUStringA [COMCTL32.153]
2169 INT WINAPI
AddMRUStringA(HANDLE hList
, const char *str
)
2175 TRACE("%p, %s.\n", hList
, debugstr_a(str
));
2180 if (IsBadStringPtrA(str
, -1))
2182 SetLastError(ERROR_INVALID_PARAMETER
);
2186 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0) * sizeof(WCHAR
);
2191 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
/sizeof(WCHAR
));
2192 ret
= AddMRUData(hList
, strW
, len
);
2197 /**************************************************************************
2198 * DelMRUString [COMCTL32.156]
2200 * Removes item from either string or binary list (despite its name)
2203 * hList [I] list handle
2204 * nItemPos [I] item position to remove 0 -> MRU
2207 * TRUE if successful, FALSE if nItemPos is out of range.
2209 BOOL WINAPI
DelMRUString(HANDLE hList
, INT nItemPos
)
2211 FIXME("(%p, %d): stub\n", hList
, nItemPos
);
2215 /**************************************************************************
2216 * FindMRUStringW [COMCTL32.402]
2218 INT WINAPI
FindMRUStringW(HANDLE hList
, const WCHAR
*str
, int *pos
)
2220 return FindMRUData(hList
, str
, (lstrlenW(str
) + 1) * sizeof(WCHAR
), pos
);
2223 /**************************************************************************
2224 * FindMRUStringA [COMCTL32.155]
2226 * Searches string list for item that matches given string.
2229 * Position in list 0 -> MRU. -1 if item not found.
2231 INT WINAPI
FindMRUStringA(HANDLE hList
, const char *str
, int *pos
)
2233 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
2234 WCHAR
*strW
= Alloc(len
* sizeof(*strW
));
2237 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
);
2238 ret
= FindMRUData(hList
, strW
, len
* sizeof(WCHAR
), pos
);
2243 /*************************************************************************
2244 * create_mru_list (internal)
2246 static HANDLE
create_mru_list(WINEMRULIST
*mp
)
2250 DWORD datasize
, dwdisp
;
2255 /* get space to save indices that will turn into names
2256 * but in order of most to least recently used
2258 mp
->realMRU
= Alloc((mp
->extview
.uMax
+ 2) * sizeof(WCHAR
));
2260 /* get space to save pointers to actual data in order of
2261 * 'a' to 'z' (0 to n).
2263 mp
->array
= Alloc(mp
->extview
.uMax
* sizeof(LPVOID
));
2265 /* open the sub key */
2266 if ((err
= RegCreateKeyExW(mp
->extview
.hKey
, mp
->extview
.lpszSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2267 KEY_READ
| KEY_WRITE
, 0, &newkey
, &dwdisp
)))
2269 /* error - what to do ??? */
2270 ERR("(%u %u %x %p %s %p): Could not open key, error=%d\n", mp
->extview
.cbSize
, mp
->extview
.uMax
, mp
->extview
.fFlags
,
2271 mp
->extview
.hKey
, debugstr_w(mp
->extview
.lpszSubKey
), mp
->extview
.u
.string_cmpfn
, err
);
2275 /* get values from key 'MRUList' */
2278 datasize
= (mp
->extview
.uMax
+ 1) * sizeof(WCHAR
);
2279 if (RegQueryValueExW( newkey
, strMRUList
, 0, &type
, (BYTE
*)mp
->realMRU
, &datasize
))
2281 /* not present - set size to 1 (will become 0 later) */
2286 datasize
/= sizeof(WCHAR
);
2288 TRACE("MRU list = %s, datasize = %d\n", debugstr_w(mp
->realMRU
), datasize
);
2290 mp
->cursize
= datasize
- 1;
2291 /* datasize now has number of items in the MRUList */
2293 /* get actual values for each entry */
2295 for (i
= 0; i
< mp
->cursize
; ++i
)
2297 realname
[0] = 'a' + i
;
2298 if (RegQueryValueExW(newkey
, realname
, 0, &type
, 0, &datasize
))
2300 /* not present - what to do ??? */
2301 ERR("Key %s not found 1\n", debugstr_w(realname
));
2303 mp
->array
[i
] = witem
= Alloc(datasize
+ sizeof(WINEMRUITEM
));
2304 witem
->size
= datasize
;
2305 if (RegQueryValueExW(newkey
, realname
, 0, &type
, &witem
->datastart
, &datasize
))
2307 /* not present - what to do ??? */
2308 ERR("Key %s not found 2\n", debugstr_w(realname
));
2311 RegCloseKey( newkey
);
2316 TRACE("(%u %u %x %p %s %p): Current Size = %d\n", mp
->extview
.cbSize
, mp
->extview
.uMax
, mp
->extview
.fFlags
,
2317 mp
->extview
.hKey
, debugstr_w(mp
->extview
.lpszSubKey
), mp
->extview
.u
.string_cmpfn
, mp
->cursize
);
2321 /**************************************************************************
2322 * CreateMRUListLazyW [COMCTL32.404]
2324 HANDLE WINAPI
CreateMRUListLazyW(const struct MRUINFOW
*info
, DWORD dwParam2
, DWORD dwParam3
, DWORD dwParam4
)
2328 /* Native does not check for a NULL. */
2329 if (!info
->hKey
|| IsBadStringPtrW(info
->lpszSubKey
, -1))
2332 mp
= Alloc(sizeof(*mp
));
2333 memcpy(&mp
->extview
, info
, sizeof(*info
));
2334 mp
->extview
.lpszSubKey
= Alloc((lstrlenW(info
->lpszSubKey
) + 1) * sizeof(WCHAR
));
2335 lstrcpyW(mp
->extview
.lpszSubKey
, info
->lpszSubKey
);
2336 mp
->isUnicode
= TRUE
;
2338 return create_mru_list(mp
);
2341 /**************************************************************************
2342 * CreateMRUListLazyA [COMCTL32.157]
2344 * Creates a most-recently-used list.
2346 HANDLE WINAPI
CreateMRUListLazyA(const struct MRUINFOA
*info
, DWORD dwParam2
, DWORD dwParam3
, DWORD dwParam4
)
2351 /* Native does not check for a NULL lpcml */
2353 if (!info
->hKey
|| IsBadStringPtrA(info
->lpszSubKey
, -1))
2356 mp
= Alloc(sizeof(*mp
));
2357 memcpy(&mp
->extview
, info
, sizeof(*info
));
2358 len
= MultiByteToWideChar(CP_ACP
, 0, info
->lpszSubKey
, -1, NULL
, 0);
2359 mp
->extview
.lpszSubKey
= Alloc(len
* sizeof(WCHAR
));
2360 MultiByteToWideChar(CP_ACP
, 0, info
->lpszSubKey
, -1, mp
->extview
.lpszSubKey
, len
);
2361 mp
->isUnicode
= FALSE
;
2362 return create_mru_list(mp
);
2365 /**************************************************************************
2366 * CreateMRUListW [COMCTL32.400]
2368 HANDLE WINAPI
CreateMRUListW(const struct MRUINFOW
*info
)
2370 return CreateMRUListLazyW(info
, 0, 0, 0);
2373 /**************************************************************************
2374 * CreateMRUListA [COMCTL32.151]
2376 HANDLE WINAPI
CreateMRUListA(const struct MRUINFOA
*info
)
2378 return CreateMRUListLazyA(info
, 0, 0, 0);
2381 /**************************************************************************
2382 * EnumMRUListW [COMCTL32.403]
2384 * Enumerate item in a most-recently-used list
2387 * hList [I] list handle
2388 * nItemPos [I] item position to enumerate
2389 * lpBuffer [O] buffer to receive item
2390 * nBufferSize [I] size of buffer
2393 * For binary lists specifies how many bytes were copied to buffer, for
2394 * string lists specifies full length of string. Enumerating past the end
2395 * of list returns -1.
2396 * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
2399 INT WINAPI
EnumMRUListW(HANDLE hList
, INT nItemPos
, void *buffer
, DWORD nBufferSize
)
2401 const WINEMRULIST
*mp
= hList
;
2402 const WINEMRUITEM
*witem
;
2403 INT desired
, datasize
;
2406 if ((nItemPos
< 0) || !buffer
) return mp
->cursize
;
2407 if (nItemPos
>= mp
->cursize
) return -1;
2408 desired
= mp
->realMRU
[nItemPos
];
2410 TRACE("nItemPos=%d, desired=%d\n", nItemPos
, desired
);
2411 witem
= mp
->array
[desired
];
2412 datasize
= min(witem
->size
, nBufferSize
);
2413 memcpy(buffer
, &witem
->datastart
, datasize
);
2414 TRACE("(%p, %d, %p, %d): returning len=%d\n", hList
, nItemPos
, buffer
, nBufferSize
, datasize
);
2418 /**************************************************************************
2419 * EnumMRUListA [COMCTL32.154]
2421 INT WINAPI
EnumMRUListA(HANDLE hList
, INT nItemPos
, void *buffer
, DWORD nBufferSize
)
2423 const WINEMRULIST
*mp
= hList
;
2425 INT desired
, datasize
;
2429 if ((nItemPos
< 0) || !buffer
) return mp
->cursize
;
2430 if (nItemPos
>= mp
->cursize
) return -1;
2431 desired
= mp
->realMRU
[nItemPos
];
2433 TRACE("nItemPos=%d, desired=%d\n", nItemPos
, desired
);
2434 witem
= mp
->array
[desired
];
2435 if (mp
->extview
.fFlags
& MRU_BINARY
)
2437 datasize
= min(witem
->size
, nBufferSize
);
2438 memcpy(buffer
, &witem
->datastart
, datasize
);
2442 lenA
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)&witem
->datastart
, -1, NULL
, 0, NULL
, NULL
);
2443 datasize
= min(lenA
, nBufferSize
);
2444 WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)&witem
->datastart
, -1, buffer
, datasize
, NULL
, NULL
);
2445 ((char *)buffer
)[ datasize
- 1 ] = '\0';
2446 datasize
= lenA
- 1;
2448 TRACE("(%p, %d, %p, %d): returning len=%d\n", hList
, nItemPos
, buffer
, nBufferSize
, datasize
);
2452 /**************************************************************************
2453 * Str_GetPtrWtoA [internal]
2455 * Converts a unicode string into a multi byte string
2459 INT
Str_GetPtrWtoA(const WCHAR
*src
, char *dst
, INT nMaxLen
)
2463 TRACE("%s, %p, %d.\n", debugstr_w(src
), dst
, nMaxLen
);
2466 return WideCharToMultiByte(CP_ACP
, 0, src
, -1, 0, 0, NULL
, NULL
);
2477 len
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, 0, 0, NULL
, NULL
);
2481 WideCharToMultiByte(CP_ACP
, 0, src
, -1, dst
, len
, NULL
, NULL
);
2487 /**************************************************************************
2488 * Str_GetPtrAtoW [internal]
2490 * Converts a multibyte string into a unicode string
2493 INT
Str_GetPtrAtoW(const char *src
, WCHAR
*dst
, INT nMaxLen
)
2497 TRACE("%s, %p, %d.\n", debugstr_a(src
), dst
, nMaxLen
);
2500 return MultiByteToWideChar(CP_ACP
, 0, src
, -1, 0, 0);
2511 len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, 0, 0);
2515 MultiByteToWideChar(CP_ACP
, 0, src
, -1, dst
, len
);
2521 /**************************************************************************
2522 * Str_SetPtrAtoW [internal]
2524 * Converts a multi byte string to a unicode string.
2525 * If the pointer to the destination buffer is NULL a buffer is allocated.
2526 * If the destination buffer is too small to keep the converted multi byte
2527 * string the destination buffer is reallocated. If the source pointer is
2529 BOOL
Str_SetPtrAtoW(WCHAR
**dst
, const char *src
)
2531 TRACE("%p, %s.\n", dst
, debugstr_a(src
));
2535 INT len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
2536 LPWSTR ptr
= ReAlloc(*dst
, len
* sizeof(**dst
));
2540 MultiByteToWideChar(CP_ACP
, 0, src
, -1, ptr
, len
);
2552 /**************************************************************************
2553 * Str_SetPtrWtoA [internal]
2555 * Converts a unicode string to a multi byte string.
2556 * If the pointer to the destination buffer is NULL a buffer is allocated.
2557 * If the destination buffer is too small to keep the converted wide
2558 * string the destination buffer is reallocated. If the source pointer is
2559 * NULL, the destination buffer is freed.
2561 BOOL
Str_SetPtrWtoA(char **dst
, const WCHAR
*src
)
2563 TRACE("%p, %s.\n", dst
, debugstr_w(src
));
2567 INT len
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, NULL
, 0, NULL
, FALSE
);
2568 LPSTR ptr
= ReAlloc(*dst
, len
* sizeof(**dst
));
2572 WideCharToMultiByte(CP_ACP
, 0, src
, -1, ptr
, len
, NULL
, FALSE
);
2584 /**************************************************************************
2585 * Notification functions
2598 /**************************************************************************
2599 * DoNotify [Internal]
2602 static LRESULT
DoNotify(const struct NOTIFYDATA
*notify
, UINT code
, NMHDR
*hdr
)
2605 NMHDR
*lpNmh
= NULL
;
2608 TRACE("%p, %p, %d, %p, %#x.\n", notify
->hwndFrom
, notify
->hwndTo
, code
, hdr
, notify
->dwParam5
);
2610 if (!notify
->hwndTo
)
2613 if (notify
->hwndFrom
== (HWND
)-1)
2616 idFrom
= hdr
->idFrom
;
2620 if (notify
->hwndFrom
)
2621 idFrom
= GetDlgCtrlID(notify
->hwndFrom
);
2623 lpNmh
= hdr
? hdr
: &nmhdr
;
2624 lpNmh
->hwndFrom
= notify
->hwndFrom
;
2625 lpNmh
->idFrom
= idFrom
;
2629 return SendMessageW(notify
->hwndTo
, WM_NOTIFY
, idFrom
, (LPARAM
)lpNmh
);
2632 /**************************************************************************
2633 * SendNotify [COMCTL32.341]
2635 * Sends a WM_NOTIFY message to the specified window.
2638 LRESULT WINAPI
SendNotify(HWND hwndTo
, HWND hwndFrom
, UINT code
, NMHDR
*hdr
)
2640 struct NOTIFYDATA notify
;
2642 TRACE("%p, %p, %d, %p.\n", hwndTo
, hwndFrom
, code
, hdr
);
2644 notify
.hwndFrom
= hwndFrom
;
2645 notify
.hwndTo
= hwndTo
;
2646 notify
.dwParam5
= 0;
2647 notify
.dwParam6
= 0;
2649 return DoNotify(¬ify
, code
, hdr
);
2652 /**************************************************************************
2653 * SendNotifyEx [COMCTL32.342]
2655 * Sends a WM_NOTIFY message to the specified window.
2658 * hwndFrom [I] Window to receive the message
2659 * hwndTo [I] Window that the message is from
2660 * code [I] Notification code
2661 * hdr [I] The NMHDR and any additional information to send or NULL
2662 * dwParam5 [I] Unknown
2665 * Success: return value from notification
2669 * If hwndFrom is -1 then the identifier of the control sending the
2670 * message is taken from the NMHDR structure.
2671 * If hwndFrom is not -1 then lpHdr can be NULL.
2673 LRESULT WINAPI
SendNotifyEx(HWND hwndTo
, HWND hwndFrom
, UINT code
, NMHDR
*hdr
, DWORD dwParam5
)
2675 struct NOTIFYDATA notify
;
2678 TRACE("(%p %p %d %p %#x)\n", hwndFrom
, hwndTo
, code
, hdr
, dwParam5
);
2680 hwndNotify
= hwndTo
;
2683 if (IsWindow(hwndFrom
))
2685 hwndNotify
= GetParent(hwndFrom
);
2691 notify
.hwndFrom
= hwndFrom
;
2692 notify
.hwndTo
= hwndNotify
;
2693 notify
.dwParam5
= dwParam5
;
2694 notify
.dwParam6
= 0;
2696 return DoNotify(¬ify
, code
, hdr
);