uxtheme: Move themed dialog to uxtheme.
[wine.git] / dlls / comctl32 / commctrl.c
blob1c7718e2400c85c477aba073d848e3b5e57af607
1 /*
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
23 * NOTES
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.
32 * TODO
33 * -- implement GetMUILanguage + InitMUILanguage
34 * -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW
35 * -- FIXMEs + BUGS (search for them)
37 * Control Classes
38 * -- ICC_ANIMATE_CLASS
39 * -- ICC_BAR_CLASSES
40 * -- ICC_COOL_CLASSES
41 * -- ICC_DATE_CLASSES
42 * -- ICC_HOTKEY_CLASS
43 * -- ICC_INTERNET_CLASSES
44 * -- ICC_LINK_CLASS
45 * -- ICC_LISTVIEW_CLASSES
46 * -- ICC_NATIVEFNTCTL_CLASS
47 * -- ICC_PAGESCROLLER_CLASS
48 * -- ICC_PROGRESS_CLASS
49 * -- ICC_STANDARD_CLASSES (not yet implemented)
50 * -- ICC_TAB_CLASSES
51 * -- ICC_TREEVIEW_CLASSES
52 * -- ICC_UPDOWN_CLASS
53 * -- ICC_USEREX_CLASSES
54 * -- ICC_WIN95_CLASSES
57 #include <stdarg.h>
58 #include <string.h>
59 #include <stdlib.h>
61 #define COBJMACROS
62 #define NONAMELESSUNION
64 #include "windef.h"
65 #include "winbase.h"
66 #include "wingdi.h"
67 #include "winuser.h"
68 #include "winnls.h"
69 #include "commctrl.h"
70 #include "winerror.h"
71 #include "winreg.h"
72 #define NO_SHLWAPI_STREAM
73 #include "shlwapi.h"
74 #include "comctl32.h"
75 #include "uxtheme.h"
76 #include "wine/debug.h"
78 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
81 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
83 static LPWSTR COMCTL32_wSubclass = NULL;
84 HMODULE COMCTL32_hModule = 0;
85 static LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
86 HBRUSH COMCTL32_hPattern55AABrush = NULL;
87 COMCTL32_SysColor comctl32_color;
89 static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
91 static const WORD wPattern55AA[] =
93 0x5555, 0xaaaa, 0x5555, 0xaaaa,
94 0x5555, 0xaaaa, 0x5555, 0xaaaa
97 static const WCHAR strCC32SubclassInfo[] = L"CC32SubclassInfo";
99 static void unregister_versioned_classes(void)
101 #define VERSION "6.0.2600.2982!"
102 static const char *classes[] =
104 VERSION WC_BUTTONA,
105 VERSION WC_COMBOBOXA,
106 VERSION "ComboLBox",
107 VERSION WC_EDITA,
108 VERSION WC_LISTBOXA,
109 VERSION WC_STATICA,
111 int i;
113 for (i = 0; i < ARRAY_SIZE(classes); i++)
114 UnregisterClassA(classes[i], NULL);
116 #undef VERSION
119 BOOL WINAPI RegisterClassNameW(const WCHAR *class)
121 static const struct
123 const WCHAR nameW[16];
124 void (*fn_register)(void);
126 classes[] =
128 { L"Button", BUTTON_Register },
129 { L"ComboBox", COMBO_Register },
130 { L"ComboLBox", COMBOLBOX_Register },
131 { L"Edit", EDIT_Register },
132 { L"ListBox", LISTBOX_Register },
133 { L"Static", STATIC_Register },
136 int min = 0, max = ARRAY_SIZE(classes) - 1;
138 while (min <= max)
140 int res, pos = (min + max) / 2;
141 if (!(res = wcsicmp(class, classes[pos].nameW)))
143 classes[pos].fn_register();
144 return TRUE;
146 if (res < 0) max = pos - 1;
147 else min = pos + 1;
150 return FALSE;
153 /***********************************************************************
154 * DllMain [Internal]
156 * Initializes the internal 'COMCTL32.DLL'.
158 * PARAMS
159 * hinstDLL [I] handle to the 'dlls' instance
160 * fdwReason [I]
161 * lpvReserved [I] reserved, must be NULL
163 * RETURNS
164 * Success: TRUE
165 * Failure: FALSE
168 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
170 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
172 switch (fdwReason) {
173 case DLL_PROCESS_ATTACH:
174 DisableThreadLibraryCalls(hinstDLL);
176 COMCTL32_hModule = hinstDLL;
178 /* add global subclassing atom (used by 'tooltip' and 'updown') */
179 COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
180 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
182 /* create local pattern brush */
183 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
184 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
186 /* Get all the colors at DLL load */
187 COMCTL32_RefreshSysColors();
189 /* like comctl32 5.82+ register all the common control classes */
190 ANIMATE_Register ();
191 COMBOEX_Register ();
192 DATETIME_Register ();
193 FLATSB_Register ();
194 HEADER_Register ();
195 HOTKEY_Register ();
196 IPADDRESS_Register ();
197 LISTVIEW_Register ();
198 MONTHCAL_Register ();
199 NATIVEFONT_Register ();
200 PAGER_Register ();
201 PROGRESS_Register ();
202 REBAR_Register ();
203 STATUS_Register ();
204 SYSLINK_Register ();
205 TAB_Register ();
206 TOOLBAR_Register ();
207 TOOLTIPS_Register ();
208 TRACKBAR_Register ();
209 TREEVIEW_Register ();
210 UPDOWN_Register ();
212 /* Call IsThemeActive() so that delay-loaded uxtheme.dll is loaded for hooking user32 */
213 IsThemeActive();
214 break;
216 case DLL_PROCESS_DETACH:
217 if (lpvReserved) break;
219 /* unregister all common control classes */
220 ANIMATE_Unregister ();
221 COMBOEX_Unregister ();
222 DATETIME_Unregister ();
223 FLATSB_Unregister ();
224 HEADER_Unregister ();
225 HOTKEY_Unregister ();
226 IPADDRESS_Unregister ();
227 LISTVIEW_Unregister ();
228 MONTHCAL_Unregister ();
229 NATIVEFONT_Unregister ();
230 PAGER_Unregister ();
231 PROGRESS_Unregister ();
232 REBAR_Unregister ();
233 STATUS_Unregister ();
234 SYSLINK_Unregister ();
235 TAB_Unregister ();
236 TOOLBAR_Unregister ();
237 TOOLTIPS_Unregister ();
238 TRACKBAR_Unregister ();
239 TREEVIEW_Unregister ();
240 UPDOWN_Unregister ();
242 unregister_versioned_classes ();
244 /* delete local pattern brush */
245 DeleteObject (COMCTL32_hPattern55AABrush);
246 DeleteObject (COMCTL32_hPattern55AABitmap);
248 /* delete global subclassing atom */
249 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
250 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
251 break;
254 return TRUE;
258 /***********************************************************************
259 * MenuHelp [COMCTL32.2]
261 * Handles the setting of status bar help messages when the user
262 * selects menu items.
264 * PARAMS
265 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
266 * wParam [I] wParam of the message uMsg
267 * lParam [I] lParam of the message uMsg
268 * hMainMenu [I] handle to the application's main menu
269 * hInst [I] handle to the module that contains string resources
270 * hwndStatus [I] handle to the status bar window
271 * lpwIDs [I] pointer to an array of integers (see NOTES)
273 * RETURNS
274 * No return value
276 * NOTES
277 * The official documentation is incomplete!
278 * This is the correct documentation:
280 * uMsg:
281 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
282 * WM_MENUSELECT messages.
284 * lpwIDs:
285 * (will be written ...)
288 VOID WINAPI
289 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
290 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
292 UINT uMenuID = 0;
294 if (!IsWindow (hwndStatus))
295 return;
297 switch (uMsg) {
298 case WM_MENUSELECT:
299 TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
300 wParam, lParam);
302 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
303 /* menu was closed */
304 TRACE("menu was closed!\n");
305 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
307 else {
308 /* menu item was selected */
309 if (HIWORD(wParam) & MF_POPUP)
310 uMenuID = *(lpwIDs+1);
311 else
312 uMenuID = (UINT)LOWORD(wParam);
313 TRACE("uMenuID = %u\n", uMenuID);
315 if (uMenuID) {
316 WCHAR szText[256];
318 if (!LoadStringW (hInst, uMenuID, szText, ARRAY_SIZE(szText)))
319 szText[0] = '\0';
321 SendMessageW (hwndStatus, SB_SETTEXTW,
322 255 | SBT_NOBORDERS, (LPARAM)szText);
323 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
326 break;
328 case WM_COMMAND :
329 TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
330 wParam, lParam);
331 /* WM_COMMAND is not invalid since it is documented
332 * in the windows api reference. So don't output
333 * any FIXME for WM_COMMAND
335 WARN("We don't care about the WM_COMMAND\n");
336 break;
338 default:
339 FIXME("Invalid Message 0x%x!\n", uMsg);
340 break;
345 /***********************************************************************
346 * ShowHideMenuCtl [COMCTL32.3]
348 * Shows or hides controls and updates the corresponding menu item.
350 * PARAMS
351 * hwnd [I] handle to the client window.
352 * uFlags [I] menu command id.
353 * lpInfo [I] pointer to an array of integers. (See NOTES.)
355 * RETURNS
356 * Success: TRUE
357 * Failure: FALSE
359 * NOTES
360 * The official documentation is incomplete!
361 * This is the correct documentation:
363 * hwnd
364 * Handle to the window that contains the menu and controls.
366 * uFlags
367 * Identifier of the menu item to receive or lose a check mark.
369 * lpInfo
370 * The array of integers contains pairs of values. BOTH values of
371 * the first pair must be the handles to the application's main menu.
372 * Each subsequent pair consists of a menu id and control id.
375 BOOL WINAPI
376 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
378 LPINT lpMenuId;
380 TRACE("%p, %lx, %p\n", hwnd, uFlags, lpInfo);
382 if (lpInfo == NULL)
383 return FALSE;
385 if (!(lpInfo[0]) || !(lpInfo[1]))
386 return FALSE;
388 /* search for control */
389 lpMenuId = &lpInfo[2];
390 while (*lpMenuId != uFlags)
391 lpMenuId += 2;
393 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
394 /* uncheck menu item */
395 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
397 /* hide control */
398 lpMenuId++;
399 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
400 SWP_HIDEWINDOW);
402 else {
403 /* check menu item */
404 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
406 /* show control */
407 lpMenuId++;
408 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
409 SWP_SHOWWINDOW);
412 return TRUE;
416 /***********************************************************************
417 * GetEffectiveClientRect [COMCTL32.4]
419 * Calculates the coordinates of a rectangle in the client area.
421 * PARAMS
422 * hwnd [I] handle to the client window.
423 * lpRect [O] pointer to the rectangle of the client window
424 * lpInfo [I] pointer to an array of integers (see NOTES)
426 * RETURNS
427 * No return value.
429 * NOTES
430 * The official documentation is incomplete!
431 * This is the correct documentation:
433 * lpInfo
434 * (will be written ...)
437 VOID WINAPI
438 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
440 RECT rcCtrl;
441 const INT *lpRun;
442 HWND hwndCtrl;
444 TRACE("(%p %p %p)\n",
445 hwnd, lpRect, lpInfo);
447 GetClientRect (hwnd, lpRect);
448 lpRun = lpInfo;
450 do {
451 lpRun += 2;
452 if (*lpRun == 0)
453 return;
454 lpRun++;
455 hwndCtrl = GetDlgItem (hwnd, *lpRun);
456 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
457 TRACE("control id 0x%x\n", *lpRun);
458 GetWindowRect (hwndCtrl, &rcCtrl);
459 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
460 SubtractRect (lpRect, lpRect, &rcCtrl);
462 lpRun++;
463 } while (*lpRun);
467 /***********************************************************************
468 * DrawStatusTextW [COMCTL32.@]
470 * Draws text with borders, like in a status bar.
472 * PARAMS
473 * hdc [I] handle to the window's display context
474 * lprc [I] pointer to a rectangle
475 * text [I] pointer to the text
476 * style [I] drawing style
478 * RETURNS
479 * No return value.
481 * NOTES
482 * The style variable can have one of the following values:
483 * (will be written ...)
486 void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
488 RECT r = *lprc;
489 UINT border = BDR_SUNKENOUTER;
490 COLORREF oldbkcolor;
492 if (style & SBT_POPOUT)
493 border = BDR_RAISEDOUTER;
494 else if (style & SBT_NOBORDERS)
495 border = 0;
497 oldbkcolor = SetBkColor (hdc, comctl32_color.clrBtnFace);
498 DrawEdge (hdc, &r, border, BF_MIDDLE|BF_RECT|BF_ADJUST);
500 /* now draw text */
501 if (text) {
502 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
503 COLORREF oldtextcolor;
504 UINT align = DT_LEFT;
505 int strCnt = 0;
507 oldtextcolor = SetTextColor (hdc, comctl32_color.clrBtnText);
508 if (style & SBT_RTLREADING)
509 FIXME("Unsupported RTL style!\n");
510 r.left += 3;
511 do {
512 if (*text == '\t') {
513 if (strCnt) {
514 DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
515 strCnt = 0;
517 if (align==DT_RIGHT) {
518 break;
520 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
521 } else {
522 strCnt++;
524 } while(*text++);
526 if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
527 SetBkMode (hdc, oldbkmode);
528 SetTextColor (hdc, oldtextcolor);
531 SetBkColor (hdc, oldbkcolor);
535 /***********************************************************************
536 * DrawStatusText [COMCTL32.@]
537 * DrawStatusTextA [COMCTL32.5]
539 * Draws text with borders, like in a status bar.
541 * PARAMS
542 * hdc [I] handle to the window's display context
543 * lprc [I] pointer to a rectangle
544 * text [I] pointer to the text
545 * style [I] drawing style
547 * RETURNS
548 * No return value.
551 void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
553 INT len;
554 LPWSTR textW = NULL;
556 if ( text ) {
557 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
558 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
559 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
562 DrawStatusTextW( hdc, lprc, textW, style );
563 Free( textW );
567 /***********************************************************************
568 * CreateStatusWindow [COMCTL32.@]
569 * CreateStatusWindowA [COMCTL32.6]
571 * Creates a status bar
573 * PARAMS
574 * style [I] window style
575 * text [I] pointer to the window text
576 * parent [I] handle to the parent window
577 * wid [I] control id of the status bar
579 * RETURNS
580 * Success: handle to the status window
581 * Failure: 0
584 HWND WINAPI
585 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
587 return CreateWindowA(STATUSCLASSNAMEA, text, style,
588 CW_USEDEFAULT, CW_USEDEFAULT,
589 CW_USEDEFAULT, CW_USEDEFAULT,
590 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
594 /***********************************************************************
595 * CreateStatusWindowW [COMCTL32.@]
597 * Creates a status bar control
599 * PARAMS
600 * style [I] window style
601 * text [I] pointer to the window text
602 * parent [I] handle to the parent window
603 * wid [I] control id of the status bar
605 * RETURNS
606 * Success: handle to the status window
607 * Failure: 0
610 HWND WINAPI
611 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
613 return CreateWindowW(STATUSCLASSNAMEW, text, style,
614 CW_USEDEFAULT, CW_USEDEFAULT,
615 CW_USEDEFAULT, CW_USEDEFAULT,
616 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
620 /***********************************************************************
621 * CreateUpDownControl [COMCTL32.16]
623 * Creates an up-down control
625 * PARAMS
626 * style [I] window styles
627 * x [I] horizontal position of the control
628 * y [I] vertical position of the control
629 * cx [I] with of the control
630 * cy [I] height of the control
631 * parent [I] handle to the parent window
632 * id [I] the control's identifier
633 * inst [I] handle to the application's module instance
634 * buddy [I] handle to the buddy window, can be NULL
635 * maxVal [I] upper limit of the control
636 * minVal [I] lower limit of the control
637 * curVal [I] current value of the control
639 * RETURNS
640 * Success: handle to the updown control
641 * Failure: 0
644 HWND WINAPI
645 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
646 HWND parent, INT id, HINSTANCE inst,
647 HWND buddy, INT maxVal, INT minVal, INT curVal)
649 HWND hUD =
650 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
651 parent, (HMENU)(DWORD_PTR)id, inst, 0);
652 if (hUD) {
653 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
654 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
655 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
658 return hUD;
662 /***********************************************************************
663 * InitCommonControls [COMCTL32.17]
665 * Registers the common controls.
667 * PARAMS
668 * No parameters.
670 * RETURNS
671 * No return values.
673 * NOTES
674 * This function is just a dummy - all the controls are registered at
675 * the DLL initialization time. See InitCommonControlsEx for details.
678 VOID WINAPI
679 InitCommonControls (void)
684 /***********************************************************************
685 * InitCommonControlsEx [COMCTL32.@]
687 * Registers the common controls.
689 * PARAMS
690 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
692 * RETURNS
693 * Success: TRUE
694 * Failure: FALSE
696 * NOTES
697 * Probably all versions of comctl32 initializes the Win95 controls in DllMain
698 * during DLL initialization. Starting from comctl32 v5.82 all the controls
699 * are initialized there. We follow this behaviour and this function is just
700 * a dummy.
702 * Note: when writing programs under Windows, if you don't call any function
703 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
704 * was the only comctl32 function you were calling and you remove it you may
705 * have a false impression that InitCommonControlsEx actually did something.
708 BOOL WINAPI
709 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
711 if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
712 return FALSE;
714 TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
715 return TRUE;
719 /***********************************************************************
720 * CreateToolbarEx [COMCTL32.@]
722 * Creates a toolbar window.
724 * PARAMS
725 * hwnd
726 * style
727 * wID
728 * nBitmaps
729 * hBMInst
730 * wBMID
731 * lpButtons
732 * iNumButtons
733 * dxButton
734 * dyButton
735 * dxBitmap
736 * dyBitmap
737 * uStructSize
739 * RETURNS
740 * Success: handle to the tool bar control
741 * Failure: 0
744 HWND WINAPI
745 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
746 HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
747 INT iNumButtons, INT dxButton, INT dyButton,
748 INT dxBitmap, INT dyBitmap, UINT uStructSize)
750 HWND hwndTB;
752 hwndTB =
753 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
754 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
755 if(hwndTB) {
756 TBADDBITMAP tbab;
758 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
760 /* set bitmap and button size */
761 /*If CreateToolbarEx receives 0, windows sets default values*/
762 if (dxBitmap < 0)
763 dxBitmap = 16;
764 if (dyBitmap < 0)
765 dyBitmap = 16;
766 if (dxBitmap == 0 || dyBitmap == 0)
767 dxBitmap = dyBitmap = 16;
768 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
770 if (dxButton < 0)
771 dxButton = dxBitmap;
772 if (dyButton < 0)
773 dyButton = dyBitmap;
774 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
775 if (dxButton != 0 && dyButton != 0)
776 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
779 /* add bitmaps */
780 if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
782 tbab.hInst = hBMInst;
783 tbab.nID = wBMID;
785 SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
787 /* add buttons */
788 if(iNumButtons > 0)
789 SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
792 return hwndTB;
796 /***********************************************************************
797 * CreateMappedBitmap [COMCTL32.8]
799 * Loads a bitmap resource using a colour map.
801 * PARAMS
802 * hInstance [I] Handle to the module containing the bitmap.
803 * idBitmap [I] The bitmap resource ID.
804 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
805 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
806 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
808 * RETURNS
809 * Success: handle to the new bitmap
810 * Failure: 0
813 HBITMAP WINAPI
814 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
815 LPCOLORMAP lpColorMap, INT iNumMaps)
817 HGLOBAL hglb;
818 HRSRC hRsrc;
819 const BITMAPINFOHEADER *lpBitmap;
820 LPBITMAPINFOHEADER lpBitmapInfo;
821 UINT nSize, nColorTableSize, iColor;
822 RGBQUAD *pColorTable;
823 INT i, iMaps, nWidth, nHeight;
824 HDC hdcScreen;
825 HBITMAP hbm;
826 LPCOLORMAP sysColorMap;
827 COLORREF cRef;
828 COLORMAP internalColorMap[4] =
829 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
831 /* initialize pointer to colortable and default color table */
832 if (lpColorMap) {
833 iMaps = iNumMaps;
834 sysColorMap = lpColorMap;
836 else {
837 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
838 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
839 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
840 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
841 iMaps = 4;
842 sysColorMap = internalColorMap;
845 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
846 if (hRsrc == 0)
847 return 0;
848 hglb = LoadResource (hInstance, hRsrc);
849 if (hglb == 0)
850 return 0;
851 lpBitmap = LockResource (hglb);
852 if (lpBitmap == NULL)
853 return 0;
855 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
856 nColorTableSize = lpBitmap->biClrUsed;
857 else if (lpBitmap->biBitCount <= 8)
858 nColorTableSize = (1 << lpBitmap->biBitCount);
859 else
860 nColorTableSize = 0;
861 nSize = lpBitmap->biSize;
862 if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
863 nSize += 3 * sizeof(DWORD);
864 nSize += nColorTableSize * sizeof(RGBQUAD);
865 lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
866 if (lpBitmapInfo == NULL)
867 return 0;
868 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
870 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
872 for (iColor = 0; iColor < nColorTableSize; iColor++) {
873 for (i = 0; i < iMaps; i++) {
874 cRef = RGB(pColorTable[iColor].rgbRed,
875 pColorTable[iColor].rgbGreen,
876 pColorTable[iColor].rgbBlue);
877 if ( cRef == sysColorMap[i].from) {
878 #if 0
879 if (wFlags & CBS_MASKED) {
880 if (sysColorMap[i].to != COLOR_BTNTEXT)
881 pColorTable[iColor] = RGB(255, 255, 255);
883 else
884 #endif
885 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
886 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
887 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
888 break;
892 nWidth = lpBitmapInfo->biWidth;
893 nHeight = lpBitmapInfo->biHeight;
894 hdcScreen = GetDC (NULL);
895 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
896 if (hbm) {
897 HDC hdcDst = CreateCompatibleDC (hdcScreen);
898 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
899 const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
900 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
901 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
902 SRCCOPY);
903 SelectObject (hdcDst, hbmOld);
904 DeleteDC (hdcDst);
906 ReleaseDC (NULL, hdcScreen);
907 GlobalFree (lpBitmapInfo);
908 FreeResource (hglb);
910 return hbm;
914 /***********************************************************************
915 * CreateToolbar [COMCTL32.7]
917 * Creates a toolbar control.
919 * PARAMS
920 * hwnd
921 * style
922 * wID
923 * nBitmaps
924 * hBMInst
925 * wBMID
926 * lpButtons
927 * iNumButtons
929 * RETURNS
930 * Success: handle to the tool bar control
931 * Failure: 0
933 * NOTES
934 * Do not use this function anymore. Use CreateToolbarEx instead.
937 HWND WINAPI
938 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
939 HINSTANCE hBMInst, UINT wBMID,
940 LPCTBBUTTON lpButtons,INT iNumButtons)
942 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
943 hBMInst, wBMID, lpButtons,
944 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
948 /***********************************************************************
949 * DllGetVersion [COMCTL32.@]
951 * Retrieves version information of the 'COMCTL32.DLL'
953 * PARAMS
954 * pdvi [O] pointer to version information structure.
956 * RETURNS
957 * Success: S_OK
958 * Failure: E_INVALIDARG
960 * NOTES
961 * Returns version of a comctl32.dll from IE4.01 SP1.
964 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
966 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
967 WARN("wrong DLLVERSIONINFO size from app\n");
968 return E_INVALIDARG;
971 pdvi->dwMajorVersion = COMCTL32_VERSION;
972 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
973 pdvi->dwBuildNumber = 2919;
974 pdvi->dwPlatformID = 6304;
976 TRACE("%u.%u.%u.%u\n",
977 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
978 pdvi->dwBuildNumber, pdvi->dwPlatformID);
980 return S_OK;
983 /***********************************************************************
984 * DllInstall (COMCTL32.@)
986 * Installs the ComCtl32 DLL.
988 * RETURNS
989 * Success: S_OK
990 * Failure: A HRESULT error
992 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
994 TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
995 return S_OK;
998 /***********************************************************************
999 * _TrackMouseEvent [COMCTL32.@]
1001 * Requests notification of mouse events
1003 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1004 * to the hwnd specified in the ptme structure. After the event message
1005 * is posted to the hwnd, the entry in the queue is removed.
1007 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1008 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1009 * immediately and the TME_LEAVE flag being ignored.
1011 * PARAMS
1012 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1014 * RETURNS
1015 * Success: non-zero
1016 * Failure: zero
1018 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1022 BOOL WINAPI
1023 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1025 return TrackMouseEvent (ptme);
1028 /*************************************************************************
1029 * GetMUILanguage [COMCTL32.@]
1031 * Returns the user interface language in use by the current process.
1033 * RETURNS
1034 * Language ID in use by the current process.
1036 LANGID WINAPI GetMUILanguage (VOID)
1038 return COMCTL32_uiLang;
1042 /*************************************************************************
1043 * InitMUILanguage [COMCTL32.@]
1045 * Sets the user interface language to be used by the current process.
1047 * RETURNS
1048 * Nothing.
1050 VOID WINAPI InitMUILanguage (LANGID uiLang)
1052 COMCTL32_uiLang = uiLang;
1056 /***********************************************************************
1057 * SetWindowSubclass [COMCTL32.410]
1059 * Starts a window subclass
1061 * PARAMS
1062 * hWnd [in] handle to window subclass.
1063 * pfnSubclass [in] Pointer to new window procedure.
1064 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1065 * dwRef [in] Reference data to pass to window procedure.
1067 * RETURNS
1068 * Success: non-zero
1069 * Failure: zero
1071 * BUGS
1072 * If an application manually subclasses a window after subclassing it with
1073 * this API and then with this API again, then none of the previous
1074 * subclasses get called or the original window procedure.
1077 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1078 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1080 LPSUBCLASS_INFO stack;
1081 LPSUBCLASSPROCS proc;
1083 TRACE ("(%p, %p, %lx, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1085 if (!hWnd || !pfnSubclass)
1086 return FALSE;
1088 /* Since the window procedure that we set here has two additional arguments,
1089 * we can't simply set it as the new window procedure of the window. So we
1090 * set our own window procedure and then calculate the other two arguments
1091 * from there. */
1093 /* See if we have been called for this window */
1094 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1095 if (!stack) {
1096 /* allocate stack */
1097 stack = Alloc (sizeof(SUBCLASS_INFO));
1098 if (!stack) {
1099 ERR ("Failed to allocate our Subclassing stack\n");
1100 return FALSE;
1102 SetPropW (hWnd, COMCTL32_wSubclass, stack);
1104 /* set window procedure to our own and save the current one */
1105 if (IsWindowUnicode (hWnd))
1106 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1107 (DWORD_PTR)COMCTL32_SubclassProc);
1108 else
1109 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1110 (DWORD_PTR)COMCTL32_SubclassProc);
1112 else {
1113 /* Check to see if we have called this function with the same uIDSubClass
1114 * and pfnSubclass */
1115 proc = stack->SubclassProcs;
1116 while (proc) {
1117 if ((proc->id == uIDSubclass) &&
1118 (proc->subproc == pfnSubclass)) {
1119 proc->ref = dwRef;
1120 return TRUE;
1122 proc = proc->next;
1126 proc = Alloc(sizeof(SUBCLASSPROCS));
1127 if (!proc) {
1128 ERR ("Failed to allocate subclass entry in stack\n");
1129 if (IsWindowUnicode (hWnd))
1130 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1131 else
1132 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1133 Free (stack);
1134 RemovePropW( hWnd, COMCTL32_wSubclass );
1135 return FALSE;
1138 proc->subproc = pfnSubclass;
1139 proc->ref = dwRef;
1140 proc->id = uIDSubclass;
1141 proc->next = stack->SubclassProcs;
1142 stack->SubclassProcs = proc;
1144 return TRUE;
1148 /***********************************************************************
1149 * GetWindowSubclass [COMCTL32.411]
1151 * Gets the Reference data from a subclass.
1153 * PARAMS
1154 * hWnd [in] Handle to the window which we are subclassing
1155 * pfnSubclass [in] Pointer to the subclass procedure
1156 * uID [in] Unique identifier of the subclassing procedure
1157 * pdwRef [out] Pointer to the reference data
1159 * RETURNS
1160 * Success: Non-zero
1161 * Failure: 0
1164 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1165 UINT_PTR uID, DWORD_PTR *pdwRef)
1167 const SUBCLASS_INFO *stack;
1168 const SUBCLASSPROCS *proc;
1170 TRACE ("(%p, %p, %lx, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1172 /* See if we have been called for this window */
1173 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1174 if (!stack)
1175 return FALSE;
1177 proc = stack->SubclassProcs;
1178 while (proc) {
1179 if ((proc->id == uID) &&
1180 (proc->subproc == pfnSubclass)) {
1181 *pdwRef = proc->ref;
1182 return TRUE;
1184 proc = proc->next;
1187 return FALSE;
1191 /***********************************************************************
1192 * RemoveWindowSubclass [COMCTL32.412]
1194 * Removes a window subclass.
1196 * PARAMS
1197 * hWnd [in] Handle to the window which we are subclassing
1198 * pfnSubclass [in] Pointer to the subclass procedure
1199 * uID [in] Unique identifier of this subclass
1201 * RETURNS
1202 * Success: non-zero
1203 * Failure: zero
1206 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1208 LPSUBCLASS_INFO stack;
1209 LPSUBCLASSPROCS prevproc = NULL;
1210 LPSUBCLASSPROCS proc;
1211 BOOL ret = FALSE;
1213 TRACE ("(%p, %p, %lx)\n", hWnd, pfnSubclass, uID);
1215 /* Find the Subclass to remove */
1216 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1217 if (!stack)
1218 return FALSE;
1220 proc = stack->SubclassProcs;
1221 while (proc) {
1222 if ((proc->id == uID) &&
1223 (proc->subproc == pfnSubclass)) {
1225 if (!prevproc)
1226 stack->SubclassProcs = proc->next;
1227 else
1228 prevproc->next = proc->next;
1230 if (stack->stackpos == proc)
1231 stack->stackpos = stack->stackpos->next;
1233 Free (proc);
1234 ret = TRUE;
1235 break;
1237 prevproc = proc;
1238 proc = proc->next;
1241 if (!stack->SubclassProcs && !stack->running) {
1242 TRACE("Last Subclass removed, cleaning up\n");
1243 /* clean up our heap and reset the original window procedure */
1244 if (IsWindowUnicode (hWnd))
1245 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1246 else
1247 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1248 Free (stack);
1249 RemovePropW( hWnd, COMCTL32_wSubclass );
1252 return ret;
1255 /***********************************************************************
1256 * COMCTL32_SubclassProc (internal)
1258 * Window procedure for all subclassed windows.
1259 * Saves the current subclassing stack position to support nested messages
1261 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1263 LPSUBCLASS_INFO stack;
1264 LPSUBCLASSPROCS proc;
1265 LRESULT ret;
1267 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1269 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1270 if (!stack) {
1271 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1272 return 0;
1275 /* Save our old stackpos to properly handle nested messages */
1276 proc = stack->stackpos;
1277 stack->stackpos = stack->SubclassProcs;
1278 stack->running++;
1279 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1280 stack->running--;
1281 stack->stackpos = proc;
1283 if (!stack->SubclassProcs && !stack->running) {
1284 TRACE("Last Subclass removed, cleaning up\n");
1285 /* clean up our heap and reset the original window procedure */
1286 if (IsWindowUnicode (hWnd))
1287 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1288 else
1289 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1290 Free (stack);
1291 RemovePropW( hWnd, COMCTL32_wSubclass );
1293 return ret;
1296 /***********************************************************************
1297 * DefSubclassProc [COMCTL32.413]
1299 * Calls the next window procedure (i.e. the one before this subclass)
1301 * PARAMS
1302 * hWnd [in] The window that we're subclassing
1303 * uMsg [in] Message
1304 * wParam [in] WPARAM
1305 * lParam [in] LPARAM
1307 * RETURNS
1308 * Success: non-zero
1309 * Failure: zero
1312 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1314 LPSUBCLASS_INFO stack;
1315 LRESULT ret;
1317 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1319 /* retrieve our little stack from the Properties */
1320 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1321 if (!stack) {
1322 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1323 return 0;
1326 /* If we are at the end of stack then we have to call the original
1327 * window procedure */
1328 if (!stack->stackpos) {
1329 if (IsWindowUnicode (hWnd))
1330 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1331 else
1332 ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1333 } else {
1334 const SUBCLASSPROCS *proc = stack->stackpos;
1335 stack->stackpos = stack->stackpos->next;
1336 /* call the Subclass procedure from the stack */
1337 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1338 proc->id, proc->ref);
1341 return ret;
1345 /***********************************************************************
1346 * COMCTL32_CreateToolTip [NOT AN API]
1348 * Creates a tooltip for the control specified in hwnd and does all
1349 * necessary setup and notifications.
1351 * PARAMS
1352 * hwndOwner [I] Handle to the window that will own the tool tip.
1354 * RETURNS
1355 * Success: Handle of tool tip window.
1356 * Failure: NULL
1359 HWND
1360 COMCTL32_CreateToolTip(HWND hwndOwner)
1362 HWND hwndToolTip;
1364 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1365 CW_USEDEFAULT, CW_USEDEFAULT,
1366 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1367 0, 0, 0);
1369 /* Send NM_TOOLTIPSCREATED notification */
1370 if (hwndToolTip)
1372 NMTOOLTIPSCREATED nmttc;
1373 /* true owner can be different if hwndOwner is a child window */
1374 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1375 nmttc.hdr.hwndFrom = hwndTrueOwner;
1376 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1377 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1378 nmttc.hwndToolTips = hwndToolTip;
1380 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1381 GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
1384 return hwndToolTip;
1388 /***********************************************************************
1389 * COMCTL32_RefreshSysColors [NOT AN API]
1391 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1392 * refresh the color values in the color structure
1394 * PARAMS
1395 * none
1397 * RETURNS
1398 * none
1401 VOID
1402 COMCTL32_RefreshSysColors(void)
1404 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1405 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1406 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1407 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1408 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1409 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1410 comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1411 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1412 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1413 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1414 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1415 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1416 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1417 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1418 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1419 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1420 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1423 /***********************************************************************
1424 * COMCTL32_DrawInsertMark [NOT AN API]
1426 * Draws an insertion mark (which looks similar to an 'I').
1428 * PARAMS
1429 * hDC [I] Device context to draw onto.
1430 * lpRect [I] Co-ordinates of insertion mark.
1431 * clrInsertMark [I] Colour of the insertion mark.
1432 * bHorizontal [I] True if insert mark should be drawn horizontally,
1433 * vertical otherwise.
1435 * RETURNS
1436 * none
1438 * NOTES
1439 * Draws up to but not including the bottom co-ordinate when drawing
1440 * vertically or the right co-ordinate when horizontal.
1442 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1444 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1445 HPEN hOldPen;
1446 static const DWORD adwPolyPoints[] = {4,4,4};
1447 LONG lCentre = (bHorizontal ?
1448 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1449 lpRect->left + (lpRect->right - lpRect->left)/2);
1450 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1451 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1452 const POINT aptInsertMark[] =
1454 /* top (V) or left (H) arrow */
1455 {lCentre , l1 + 2},
1456 {lCentre - 2, l1 },
1457 {lCentre + 3, l1 },
1458 {lCentre + 1, l1 + 2},
1459 /* middle line */
1460 {lCentre , l2 - 2},
1461 {lCentre , l1 - 1},
1462 {lCentre + 1, l1 - 1},
1463 {lCentre + 1, l2 - 2},
1464 /* bottom (V) or right (H) arrow */
1465 {lCentre , l2 - 3},
1466 {lCentre - 2, l2 - 1},
1467 {lCentre + 3, l2 - 1},
1468 {lCentre + 1, l2 - 3},
1470 hOldPen = SelectObject(hDC, hPen);
1471 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, ARRAY_SIZE(adwPolyPoints));
1472 SelectObject(hDC, hOldPen);
1473 DeleteObject(hPen);
1476 /***********************************************************************
1477 * COMCTL32_EnsureBitmapSize [internal]
1479 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1480 * the height is at least cyMinHeight. If the bitmap already has these
1481 * dimensions nothing changes.
1483 * PARAMS
1484 * hBitmap [I/O] Bitmap to modify. The handle may change
1485 * cxMinWidth [I] If the width of the bitmap is smaller, then it will
1486 * be enlarged to this value
1487 * cyMinHeight [I] If the height of the bitmap is smaller, then it will
1488 * be enlarged to this value
1489 * cyBackground [I] The color with which the new area will be filled
1491 * RETURNS
1492 * none
1494 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1496 int cxNew, cyNew;
1497 BITMAP bmp;
1498 HBITMAP hNewBitmap;
1499 HBITMAP hNewDCBitmap, hOldDCBitmap;
1500 HBRUSH hNewDCBrush;
1501 HDC hdcNew, hdcOld;
1503 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1504 return;
1505 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1506 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1507 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1508 return;
1510 hdcNew = CreateCompatibleDC(NULL);
1511 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1512 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1513 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1515 hdcOld = CreateCompatibleDC(NULL);
1516 hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1518 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1519 if (bmp.bmWidth < cxMinWidth)
1520 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1521 if (bmp.bmHeight < cyMinHeight)
1522 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1523 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1524 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1526 SelectObject(hdcNew, hNewDCBitmap);
1527 DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1528 DeleteDC(hdcNew);
1529 SelectObject(hdcOld, hOldDCBitmap);
1530 DeleteDC(hdcOld);
1532 DeleteObject(*pBitmap);
1533 *pBitmap = hNewBitmap;
1534 return;
1537 void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
1539 HDC hdc = GetDC(NULL);
1540 HFONT hOldFont;
1542 hOldFont = SelectObject(hdc, hFont);
1543 GetTextMetricsW(hdc, ptm);
1544 SelectObject(hdc, hOldFont);
1545 ReleaseDC(NULL, hdc);
1548 #ifndef OCM__BASE /* avoid including olectl.h */
1549 #define OCM__BASE (WM_USER+0x1c00)
1550 #endif
1552 /***********************************************************************
1553 * COMCTL32_IsReflectedMessage [internal]
1555 * Some parents reflect notify messages - for some messages sent by the child,
1556 * they send it back with the message code increased by OCM__BASE (0x2000).
1557 * This allows better subclassing of controls. We don't need to handle such
1558 * messages but we don't want to print ERRs for them, so this helper function
1559 * identifies them.
1561 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1562 * collision with defined CCM_ codes.
1564 BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
1566 switch (uMsg)
1568 case OCM__BASE + WM_COMMAND:
1569 case OCM__BASE + WM_CTLCOLORBTN:
1570 case OCM__BASE + WM_CTLCOLOREDIT:
1571 case OCM__BASE + WM_CTLCOLORDLG:
1572 case OCM__BASE + WM_CTLCOLORLISTBOX:
1573 case OCM__BASE + WM_CTLCOLORMSGBOX:
1574 case OCM__BASE + WM_CTLCOLORSCROLLBAR:
1575 case OCM__BASE + WM_CTLCOLORSTATIC:
1576 case OCM__BASE + WM_DRAWITEM:
1577 case OCM__BASE + WM_MEASUREITEM:
1578 case OCM__BASE + WM_DELETEITEM:
1579 case OCM__BASE + WM_VKEYTOITEM:
1580 case OCM__BASE + WM_CHARTOITEM:
1581 case OCM__BASE + WM_COMPAREITEM:
1582 case OCM__BASE + WM_HSCROLL:
1583 case OCM__BASE + WM_VSCROLL:
1584 case OCM__BASE + WM_PARENTNOTIFY:
1585 case OCM__BASE + WM_NOTIFY:
1586 return TRUE;
1587 default:
1588 return FALSE;
1592 /***********************************************************************
1593 * MirrorIcon [COMCTL32.414]
1595 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1597 * PARAMS
1598 * phicon1 [I/O] Icon.
1599 * phicon2 [I/O] Icon.
1601 * RETURNS
1602 * Success: TRUE.
1603 * Failure: FALSE.
1605 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1607 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1608 return FALSE;
1611 static inline BOOL IsDelimiter(WCHAR c)
1613 switch(c)
1615 case '/':
1616 case '\\':
1617 case '.':
1618 case ' ':
1619 return TRUE;
1621 return FALSE;
1624 static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1626 if (code == WB_ISDELIMITER)
1627 return IsDelimiter(lpch[ichCurrent]);
1628 else
1630 int dir = (code == WB_LEFT) ? -1 : 1;
1631 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1632 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1634 return ichCurrent;
1637 /***********************************************************************
1638 * SetPathWordBreakProc [COMCTL32.384]
1640 * Sets the word break procedure for an edit control to one that understands
1641 * paths so that the user can jump over directories.
1643 * PARAMS
1644 * hwnd [I] Handle to edit control.
1645 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1647 * RETURNS
1648 * Result from EM_SETWORDBREAKPROC message.
1650 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1652 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1653 (LPARAM)(bSet ? PathWordBreakProc : NULL));
1656 /***********************************************************************
1657 * DrawShadowText [COMCTL32.@]
1659 * Draw text with shadow.
1661 int WINAPI DrawShadowText(HDC hdc, LPCWSTR text, UINT length, RECT *rect, DWORD flags,
1662 COLORREF crText, COLORREF crShadow, int offset_x, int offset_y)
1664 int bkmode, ret;
1665 COLORREF clr;
1666 RECT r;
1668 FIXME("(%p, %s, %d, %p, 0x%08x, 0x%08x, 0x%08x, %d, %d): semi-stub\n", hdc, debugstr_w(text),
1669 length, rect, flags, crText, crShadow, offset_x, offset_y);
1671 bkmode = SetBkMode(hdc, TRANSPARENT);
1672 clr = SetTextColor(hdc, crShadow);
1674 /* FIXME: for shadow we need to render normally, blur it, and blend with current background. */
1675 r = *rect;
1676 OffsetRect(&r, 1, 1);
1677 DrawTextW(hdc, text, length, &r, flags);
1679 SetTextColor(hdc, crText);
1681 /* with text color on top of a shadow */
1682 ret = DrawTextW(hdc, text, length, rect, flags);
1684 SetTextColor(hdc, clr);
1685 SetBkMode(hdc, bkmode);
1687 return ret;
1690 /***********************************************************************
1691 * LoadIconWithScaleDown [COMCTL32.@]
1693 HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
1695 TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
1697 *icon = NULL;
1699 if (!name)
1700 return E_INVALIDARG;
1702 *icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
1703 (hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
1704 if (!*icon)
1705 return HRESULT_FROM_WIN32(GetLastError());
1707 return S_OK;
1710 /***********************************************************************
1711 * LoadIconMetric [COMCTL32.@]
1713 HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
1715 int cx, cy;
1717 TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
1719 if (size == LIM_SMALL)
1721 cx = GetSystemMetrics(SM_CXSMICON);
1722 cy = GetSystemMetrics(SM_CYSMICON);
1724 else if (size == LIM_LARGE)
1726 cx = GetSystemMetrics(SM_CXICON);
1727 cy = GetSystemMetrics(SM_CYICON);
1729 else
1731 *icon = NULL;
1732 return E_INVALIDARG;
1735 return LoadIconWithScaleDown(hinst, name, cx, cy, icon);
1738 static const WCHAR strMRUList[] = L"MRUList";
1740 /**************************************************************************
1741 * Alloc [COMCTL32.71]
1743 * Allocates memory block from the dll's private heap
1745 void * WINAPI Alloc(DWORD size)
1747 return LocalAlloc(LMEM_ZEROINIT, size);
1750 /**************************************************************************
1751 * ReAlloc [COMCTL32.72]
1753 * Changes the size of an allocated memory block or allocates a memory
1754 * block using the dll's private heap.
1757 void * WINAPI ReAlloc(void *src, DWORD size)
1759 if (src)
1760 return LocalReAlloc(src, size, LMEM_ZEROINIT | LMEM_MOVEABLE);
1761 else
1762 return LocalAlloc(LMEM_ZEROINIT, size);
1765 /**************************************************************************
1766 * Free [COMCTL32.73]
1768 * Frees an allocated memory block from the dll's private heap.
1770 BOOL WINAPI Free(void *mem)
1772 return !LocalFree(mem);
1775 /**************************************************************************
1776 * GetSize [COMCTL32.74]
1778 DWORD WINAPI GetSize(void *mem)
1780 return LocalSize(mem);
1783 /**************************************************************************
1784 * MRU-Functions {COMCTL32}
1786 * NOTES
1787 * The MRU-API is a set of functions to manipulate lists of M.R.U. (Most Recently
1788 * Used) items. It is an undocumented API that is used (at least) by the shell
1789 * and explorer to implement their recent documents feature.
1791 * Since these functions are undocumented, they are unsupported by MS and
1792 * may change at any time.
1794 * Internally, the list is implemented as a last in, last out list of items
1795 * persisted into the system registry under a caller chosen key. Each list
1796 * item is given a one character identifier in the Ascii range from 'a' to
1797 * '}'. A list of the identifiers in order from newest to oldest is stored
1798 * under the same key in a value named "MRUList".
1800 * Items are re-ordered by changing the order of the values in the MRUList
1801 * value. When a new item is added, it becomes the new value of the oldest
1802 * identifier, and that identifier is moved to the front of the MRUList value.
1804 * Wine stores MRU-lists in the same registry format as Windows, so when
1805 * switching between the builtin and native comctl32.dll no problems or
1806 * incompatibilities should occur.
1808 * The following undocumented structure is used to create an MRU-list:
1809 *|typedef INT (CALLBACK *MRUStringCmpFn)(LPCTSTR lhs, LPCTSTR rhs);
1810 *|typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
1812 *|typedef struct tagMRUINFO
1814 *| DWORD cbSize;
1815 *| UINT uMax;
1816 *| UINT fFlags;
1817 *| HKEY hKey;
1818 *| LPTSTR lpszSubKey;
1819 *| PROC lpfnCompare;
1820 *|} MRUINFO, *LPMRUINFO;
1822 * MEMBERS
1823 * cbSize [I] The size of the MRUINFO structure. This must be set
1824 * to sizeof(MRUINFO) by the caller.
1825 * uMax [I] The maximum number of items allowed in the list. Because
1826 * of the limited number of identifiers, this should be set to
1827 * a value from 1 to 30 by the caller.
1828 * fFlags [I] If bit 0 is set, the list will be used to store binary
1829 * data, otherwise it is assumed to store strings. If bit 1
1830 * is set, every change made to the list will be reflected in
1831 * the registry immediately, otherwise changes will only be
1832 * written when the list is closed.
1833 * hKey [I] The registry key that the list should be written under.
1834 * This must be supplied by the caller.
1835 * lpszSubKey [I] A caller supplied name of a subkey under hKey to write
1836 * the list to. This may not be blank.
1837 * lpfnCompare [I] A caller supplied comparison function, which may be either
1838 * an MRUStringCmpFn if dwFlags does not have bit 0 set, or a
1839 * MRUBinaryCmpFn otherwise.
1841 * FUNCTIONS
1842 * - Create an MRU-list with CreateMRUList() or CreateMRUListLazy().
1843 * - Add items to an MRU-list with AddMRUString() or AddMRUData().
1844 * - Remove items from an MRU-list with DelMRUString().
1845 * - Find data in an MRU-list with FindMRUString() or FindMRUData().
1846 * - Iterate through an MRU-list with EnumMRUList().
1847 * - Free an MRU-list with FreeMRUList().
1850 typedef INT (CALLBACK *MRUStringCmpFnA)(LPCSTR lhs, LPCSTR rhs);
1851 typedef INT (CALLBACK *MRUStringCmpFnW)(LPCWSTR lhs, LPCWSTR rhs);
1852 typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
1854 struct MRUINFOA
1856 DWORD cbSize;
1857 UINT uMax;
1858 UINT fFlags;
1859 HKEY hKey;
1860 LPSTR lpszSubKey;
1861 union
1863 MRUStringCmpFnA string_cmpfn;
1864 MRUBinaryCmpFn binary_cmpfn;
1865 } u;
1868 struct MRUINFOW
1870 DWORD cbSize;
1871 UINT uMax;
1872 UINT fFlags;
1873 HKEY hKey;
1874 LPWSTR lpszSubKey;
1875 union
1877 MRUStringCmpFnW string_cmpfn;
1878 MRUBinaryCmpFn binary_cmpfn;
1879 } u;
1882 /* MRUINFO.fFlags */
1883 #define MRU_STRING 0 /* list will contain strings */
1884 #define MRU_BINARY 1 /* list will contain binary data */
1885 #define MRU_CACHEWRITE 2 /* only save list order to reg. is FreeMRUList */
1887 /* If list is a string list lpfnCompare has the following prototype
1888 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
1889 * for binary lists the prototype is
1890 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
1891 * where cbData is the no. of bytes to compare.
1892 * Need to check what return value means identical - 0?
1895 typedef struct tagWINEMRUITEM
1897 DWORD size; /* size of data stored */
1898 DWORD itemFlag; /* flags */
1899 BYTE datastart;
1900 } WINEMRUITEM, *LPWINEMRUITEM;
1902 /* itemFlag */
1903 #define WMRUIF_CHANGED 0x0001 /* this dataitem changed */
1905 typedef struct tagWINEMRULIST
1907 struct MRUINFOW extview; /* original create information */
1908 BOOL isUnicode; /* is compare fn Unicode */
1909 DWORD wineFlags; /* internal flags */
1910 DWORD cursize; /* current size of realMRU */
1911 LPWSTR realMRU; /* pointer to string of index names */
1912 LPWINEMRUITEM *array; /* array of pointers to data */
1913 /* in 'a' to 'z' order */
1914 } WINEMRULIST, *LPWINEMRULIST;
1916 /* wineFlags */
1917 #define WMRUF_CHANGED 0x0001 /* MRU list has changed */
1919 /**************************************************************************
1920 * MRU_SaveChanged (internal)
1922 * Local MRU saving code
1924 static void MRU_SaveChanged(WINEMRULIST *mp)
1926 UINT i, err;
1927 HKEY newkey;
1928 WCHAR realname[2];
1929 WINEMRUITEM *witem;
1931 /* or should we do the following instead of RegOpenKeyEx:
1934 /* open the sub key */
1935 if ((err = RegOpenKeyExW(mp->extview.hKey, mp->extview.lpszSubKey, 0, KEY_WRITE, &newkey)))
1937 /* not present - what to do ??? */
1938 ERR("Could not open key, error=%d, attempting to create\n", err);
1939 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
1940 KEY_READ | KEY_WRITE, 0, &newkey, 0)))
1942 ERR("failed to create key /%s/, err=%d\n", debugstr_w(mp->extview.lpszSubKey), err);
1943 return;
1947 if (mp->wineFlags & WMRUF_CHANGED)
1949 mp->wineFlags &= ~WMRUF_CHANGED;
1950 if ((err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (BYTE *)mp->realMRU,
1951 (lstrlenW(mp->realMRU) + 1)*sizeof(WCHAR))))
1953 ERR("error saving MRUList, err=%d\n", err);
1955 TRACE("saving MRUList=/%s/\n", debugstr_w(mp->realMRU));
1958 realname[1] = 0;
1959 for (i = 0; i < mp->cursize; ++i)
1961 witem = mp->array[i];
1962 if (witem->itemFlag & WMRUIF_CHANGED)
1964 witem->itemFlag &= ~WMRUIF_CHANGED;
1965 realname[0] = 'a' + i;
1966 if ((err = RegSetValueExW(newkey, realname, 0, (mp->extview.fFlags & MRU_BINARY) ?
1967 REG_BINARY : REG_SZ, &witem->datastart, witem->size)))
1969 ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err);
1971 TRACE("saving value for name /%s/ size=%d\n", debugstr_w(realname), witem->size);
1974 RegCloseKey(newkey);
1977 /**************************************************************************
1978 * FreeMRUList [COMCTL32.152]
1980 * Frees a most-recently-used items list.
1982 void WINAPI FreeMRUList(HANDLE hMRUList)
1984 WINEMRULIST *mp = hMRUList;
1985 unsigned int i;
1987 TRACE("%p.\n", hMRUList);
1989 if (!hMRUList)
1990 return;
1992 if (mp->wineFlags & WMRUF_CHANGED)
1994 /* need to open key and then save the info */
1995 MRU_SaveChanged(mp);
1998 for (i = 0; i < mp->extview.uMax; ++i)
1999 Free(mp->array[i]);
2001 Free(mp->realMRU);
2002 Free(mp->array);
2003 Free(mp->extview.lpszSubKey);
2004 Free(mp);
2007 /**************************************************************************
2008 * FindMRUData [COMCTL32.169]
2010 * Searches binary list for item that matches data of given length.
2011 * Returns position in list order 0 -> MRU and value corresponding to item's reg.
2012 * name will be stored in it ('a' -> 0).
2015 INT WINAPI FindMRUData(HANDLE hList, const void *data, DWORD cbData, int *pos)
2017 const WINEMRULIST *mp = hList;
2018 INT ret;
2019 UINT i;
2020 LPSTR dataA = NULL;
2022 if (!mp || !mp->extview.u.string_cmpfn)
2023 return -1;
2025 if (!(mp->extview.fFlags & MRU_BINARY) && !mp->isUnicode)
2027 DWORD len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
2028 dataA = Alloc(len);
2029 WideCharToMultiByte(CP_ACP, 0, data, -1, dataA, len, NULL, NULL);
2032 for (i = 0; i < mp->cursize; ++i)
2034 if (mp->extview.fFlags & MRU_BINARY)
2036 if (!mp->extview.u.binary_cmpfn(data, &mp->array[i]->datastart, cbData))
2037 break;
2039 else
2041 if (mp->isUnicode)
2043 if (!mp->extview.u.string_cmpfn(data, (LPWSTR)&mp->array[i]->datastart))
2044 break;
2046 else
2048 DWORD len = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
2049 NULL, 0, NULL, NULL);
2050 LPSTR itemA = Alloc(len);
2051 INT cmp;
2052 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1, itemA, len, NULL, NULL);
2054 cmp = mp->extview.u.string_cmpfn((LPWSTR)dataA, (LPWSTR)itemA);
2055 Free(itemA);
2056 if (!cmp)
2057 break;
2062 Free(dataA);
2063 if (i < mp->cursize)
2064 ret = i;
2065 else
2066 ret = -1;
2067 if (pos && (ret != -1))
2068 *pos = 'a' + i;
2070 TRACE("%p, %p, %d, %p, returning %d.\n", hList, data, cbData, pos, ret);
2072 return ret;
2075 /**************************************************************************
2076 * AddMRUData [COMCTL32.167]
2078 * Add item to MRU binary list. If item already exists in list then it is
2079 * simply moved up to the top of the list and not added again. If list is
2080 * full then the least recently used item is removed to make room.
2083 INT WINAPI AddMRUData(HANDLE hList, const void *data, DWORD cbData)
2085 WINEMRULIST *mp = hList;
2086 WINEMRUITEM *witem;
2087 INT i, replace;
2089 if ((replace = FindMRUData(hList, data, cbData, NULL)) >= 0)
2091 /* Item exists, just move it to the front */
2092 LPWSTR pos = wcschr(mp->realMRU, replace + 'a');
2093 while (pos > mp->realMRU)
2095 pos[0] = pos[-1];
2096 pos--;
2099 else
2101 /* either add a new entry or replace oldest */
2102 if (mp->cursize < mp->extview.uMax)
2104 /* Add in a new item */
2105 replace = mp->cursize;
2106 mp->cursize++;
2108 else
2110 /* get the oldest entry and replace data */
2111 replace = mp->realMRU[mp->cursize - 1] - 'a';
2112 Free(mp->array[replace]);
2115 /* Allocate space for new item and move in the data */
2116 mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM));
2117 witem->itemFlag |= WMRUIF_CHANGED;
2118 witem->size = cbData;
2119 memcpy( &witem->datastart, data, cbData);
2121 /* now rotate MRU list */
2122 for (i = mp->cursize - 1; i >= 1; --i)
2123 mp->realMRU[i] = mp->realMRU[i-1];
2126 /* The new item gets the front spot */
2127 mp->wineFlags |= WMRUF_CHANGED;
2128 mp->realMRU[0] = replace + 'a';
2130 TRACE("(%p, %p, %d) adding data, /%c/ now most current\n", hList, data, cbData, replace+'a');
2132 if (!(mp->extview.fFlags & MRU_CACHEWRITE))
2134 /* save changed stuff right now */
2135 MRU_SaveChanged(mp);
2138 return replace;
2141 /**************************************************************************
2142 * AddMRUStringW [COMCTL32.401]
2144 * Add an item to an MRU string list.
2147 INT WINAPI AddMRUStringW(HANDLE hList, const WCHAR *str)
2149 TRACE("%p, %s.\n", hList, debugstr_w(str));
2151 if (!hList)
2152 return -1;
2154 if (!str || IsBadStringPtrW(str, -1))
2156 SetLastError(ERROR_INVALID_PARAMETER);
2157 return 0;
2160 return AddMRUData(hList, str, (lstrlenW(str) + 1) * sizeof(WCHAR));
2163 /**************************************************************************
2164 * AddMRUStringA [COMCTL32.153]
2166 INT WINAPI AddMRUStringA(HANDLE hList, const char *str)
2168 WCHAR *strW;
2169 DWORD len;
2170 INT ret;
2172 TRACE("%p, %s.\n", hList, debugstr_a(str));
2174 if (!hList)
2175 return -1;
2177 if (IsBadStringPtrA(str, -1))
2179 SetLastError(ERROR_INVALID_PARAMETER);
2180 return 0;
2183 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0) * sizeof(WCHAR);
2184 strW = Alloc(len);
2185 if (!strW)
2186 return -1;
2188 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len/sizeof(WCHAR));
2189 ret = AddMRUData(hList, strW, len);
2190 Free(strW);
2191 return ret;
2194 /**************************************************************************
2195 * DelMRUString [COMCTL32.156]
2197 * Removes item from either string or binary list (despite its name)
2199 * PARAMS
2200 * hList [I] list handle
2201 * nItemPos [I] item position to remove 0 -> MRU
2203 * RETURNS
2204 * TRUE if successful, FALSE if nItemPos is out of range.
2206 BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos)
2208 FIXME("(%p, %d): stub\n", hList, nItemPos);
2209 return TRUE;
2212 /**************************************************************************
2213 * FindMRUStringW [COMCTL32.402]
2215 INT WINAPI FindMRUStringW(HANDLE hList, const WCHAR *str, int *pos)
2217 return FindMRUData(hList, str, (lstrlenW(str) + 1) * sizeof(WCHAR), pos);
2220 /**************************************************************************
2221 * FindMRUStringA [COMCTL32.155]
2223 * Searches string list for item that matches given string.
2225 * RETURNS
2226 * Position in list 0 -> MRU. -1 if item not found.
2228 INT WINAPI FindMRUStringA(HANDLE hList, const char *str, int *pos)
2230 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
2231 WCHAR *strW = Alloc(len * sizeof(*strW));
2232 INT ret;
2234 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
2235 ret = FindMRUData(hList, strW, len * sizeof(WCHAR), pos);
2236 Free(strW);
2237 return ret;
2240 /*************************************************************************
2241 * create_mru_list (internal)
2243 static HANDLE create_mru_list(WINEMRULIST *mp)
2245 UINT i, err;
2246 HKEY newkey;
2247 DWORD datasize, dwdisp;
2248 WCHAR realname[2];
2249 WINEMRUITEM *witem;
2250 DWORD type;
2252 /* get space to save indices that will turn into names
2253 * but in order of most to least recently used
2255 mp->realMRU = Alloc((mp->extview.uMax + 2) * sizeof(WCHAR));
2257 /* get space to save pointers to actual data in order of
2258 * 'a' to 'z' (0 to n).
2260 mp->array = Alloc(mp->extview.uMax * sizeof(LPVOID));
2262 /* open the sub key */
2263 if ((err = RegCreateKeyExW(mp->extview.hKey, mp->extview.lpszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
2264 KEY_READ | KEY_WRITE, 0, &newkey, &dwdisp)))
2266 /* error - what to do ??? */
2267 ERR("(%u %u %x %p %s %p): Could not open key, error=%d\n", mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
2268 mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.u.string_cmpfn, err);
2269 return 0;
2272 /* get values from key 'MRUList' */
2273 if (newkey)
2275 datasize = (mp->extview.uMax + 1) * sizeof(WCHAR);
2276 if (RegQueryValueExW( newkey, strMRUList, 0, &type, (BYTE *)mp->realMRU, &datasize))
2278 /* not present - set size to 1 (will become 0 later) */
2279 datasize = 1;
2280 *mp->realMRU = 0;
2282 else
2283 datasize /= sizeof(WCHAR);
2285 TRACE("MRU list = %s, datasize = %d\n", debugstr_w(mp->realMRU), datasize);
2287 mp->cursize = datasize - 1;
2288 /* datasize now has number of items in the MRUList */
2290 /* get actual values for each entry */
2291 realname[1] = 0;
2292 for (i = 0; i < mp->cursize; ++i)
2294 realname[0] = 'a' + i;
2295 if (RegQueryValueExW(newkey, realname, 0, &type, 0, &datasize))
2297 /* not present - what to do ??? */
2298 ERR("Key %s not found 1\n", debugstr_w(realname));
2300 mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM));
2301 witem->size = datasize;
2302 if (RegQueryValueExW(newkey, realname, 0, &type, &witem->datastart, &datasize))
2304 /* not present - what to do ??? */
2305 ERR("Key %s not found 2\n", debugstr_w(realname));
2308 RegCloseKey( newkey );
2310 else
2311 mp->cursize = 0;
2313 TRACE("(%u %u %x %p %s %p): Current Size = %d\n", mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
2314 mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.u.string_cmpfn, mp->cursize);
2315 return mp;
2318 /**************************************************************************
2319 * CreateMRUListLazyW [COMCTL32.404]
2321 HANDLE WINAPI CreateMRUListLazyW(const struct MRUINFOW *info, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
2323 WINEMRULIST *mp;
2325 /* Native does not check for a NULL. */
2326 if (!info->hKey || IsBadStringPtrW(info->lpszSubKey, -1))
2327 return NULL;
2329 mp = Alloc(sizeof(*mp));
2330 memcpy(&mp->extview, info, sizeof(*info));
2331 mp->extview.lpszSubKey = Alloc((lstrlenW(info->lpszSubKey) + 1) * sizeof(WCHAR));
2332 lstrcpyW(mp->extview.lpszSubKey, info->lpszSubKey);
2333 mp->isUnicode = TRUE;
2335 return create_mru_list(mp);
2338 /**************************************************************************
2339 * CreateMRUListLazyA [COMCTL32.157]
2341 * Creates a most-recently-used list.
2343 HANDLE WINAPI CreateMRUListLazyA(const struct MRUINFOA *info, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
2345 WINEMRULIST *mp;
2346 DWORD len;
2348 /* Native does not check for a NULL lpcml */
2350 if (!info->hKey || IsBadStringPtrA(info->lpszSubKey, -1))
2351 return 0;
2353 mp = Alloc(sizeof(*mp));
2354 memcpy(&mp->extview, info, sizeof(*info));
2355 len = MultiByteToWideChar(CP_ACP, 0, info->lpszSubKey, -1, NULL, 0);
2356 mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR));
2357 MultiByteToWideChar(CP_ACP, 0, info->lpszSubKey, -1, mp->extview.lpszSubKey, len);
2358 mp->isUnicode = FALSE;
2359 return create_mru_list(mp);
2362 /**************************************************************************
2363 * CreateMRUListW [COMCTL32.400]
2365 HANDLE WINAPI CreateMRUListW(const struct MRUINFOW *info)
2367 return CreateMRUListLazyW(info, 0, 0, 0);
2370 /**************************************************************************
2371 * CreateMRUListA [COMCTL32.151]
2373 HANDLE WINAPI CreateMRUListA(const struct MRUINFOA *info)
2375 return CreateMRUListLazyA(info, 0, 0, 0);
2378 /**************************************************************************
2379 * EnumMRUListW [COMCTL32.403]
2381 * Enumerate item in a most-recently-used list
2383 * PARAMS
2384 * hList [I] list handle
2385 * nItemPos [I] item position to enumerate
2386 * lpBuffer [O] buffer to receive item
2387 * nBufferSize [I] size of buffer
2389 * RETURNS
2390 * For binary lists specifies how many bytes were copied to buffer, for
2391 * string lists specifies full length of string. Enumerating past the end
2392 * of list returns -1.
2393 * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
2394 * the list.
2396 INT WINAPI EnumMRUListW(HANDLE hList, INT nItemPos, void *buffer, DWORD nBufferSize)
2398 const WINEMRULIST *mp = hList;
2399 const WINEMRUITEM *witem;
2400 INT desired, datasize;
2402 if (!mp) return -1;
2403 if ((nItemPos < 0) || !buffer) return mp->cursize;
2404 if (nItemPos >= mp->cursize) return -1;
2405 desired = mp->realMRU[nItemPos];
2406 desired -= 'a';
2407 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
2408 witem = mp->array[desired];
2409 datasize = min(witem->size, nBufferSize);
2410 memcpy(buffer, &witem->datastart, datasize);
2411 TRACE("(%p, %d, %p, %d): returning len=%d\n", hList, nItemPos, buffer, nBufferSize, datasize);
2412 return datasize;
2415 /**************************************************************************
2416 * EnumMRUListA [COMCTL32.154]
2418 INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, void *buffer, DWORD nBufferSize)
2420 const WINEMRULIST *mp = hList;
2421 WINEMRUITEM *witem;
2422 INT desired, datasize;
2423 DWORD lenA;
2425 if (!mp) return -1;
2426 if ((nItemPos < 0) || !buffer) return mp->cursize;
2427 if (nItemPos >= mp->cursize) return -1;
2428 desired = mp->realMRU[nItemPos];
2429 desired -= 'a';
2430 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
2431 witem = mp->array[desired];
2432 if (mp->extview.fFlags & MRU_BINARY)
2434 datasize = min(witem->size, nBufferSize);
2435 memcpy(buffer, &witem->datastart, datasize);
2437 else
2439 lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, NULL, 0, NULL, NULL);
2440 datasize = min(lenA, nBufferSize);
2441 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, buffer, datasize, NULL, NULL);
2442 ((char *)buffer)[ datasize - 1 ] = '\0';
2443 datasize = lenA - 1;
2445 TRACE("(%p, %d, %p, %d): returning len=%d\n", hList, nItemPos, buffer, nBufferSize, datasize);
2446 return datasize;
2449 /**************************************************************************
2450 * Str_GetPtrWtoA [internal]
2452 * Converts a unicode string into a multi byte string
2456 INT Str_GetPtrWtoA(const WCHAR *src, char *dst, INT nMaxLen)
2458 INT len;
2460 TRACE("%s, %p, %d.\n", debugstr_w(src), dst, nMaxLen);
2462 if (!dst && src)
2463 return WideCharToMultiByte(CP_ACP, 0, src, -1, 0, 0, NULL, NULL);
2465 if (!nMaxLen)
2466 return 0;
2468 if (!src)
2470 dst[0] = 0;
2471 return 0;
2474 len = WideCharToMultiByte(CP_ACP, 0, src, -1, 0, 0, NULL, NULL);
2475 if (len >= nMaxLen)
2476 len = nMaxLen - 1;
2478 WideCharToMultiByte(CP_ACP, 0, src, -1, dst, len, NULL, NULL);
2479 dst[len] = '\0';
2481 return len;
2484 /**************************************************************************
2485 * Str_GetPtrAtoW [internal]
2487 * Converts a multibyte string into a unicode string
2490 INT Str_GetPtrAtoW(const char *src, WCHAR *dst, INT nMaxLen)
2492 INT len;
2494 TRACE("%s, %p, %d.\n", debugstr_a(src), dst, nMaxLen);
2496 if (!dst && src)
2497 return MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
2499 if (!nMaxLen)
2500 return 0;
2502 if (!src)
2504 *dst = 0;
2505 return 0;
2508 len = MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
2509 if (len >= nMaxLen)
2510 len = nMaxLen - 1;
2512 MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
2513 dst[len] = 0;
2515 return len;
2518 /**************************************************************************
2519 * Str_SetPtrAtoW [internal]
2521 * Converts a multi byte string to a unicode string.
2522 * If the pointer to the destination buffer is NULL a buffer is allocated.
2523 * If the destination buffer is too small to keep the converted multi byte
2524 * string the destination buffer is reallocated. If the source pointer is
2526 BOOL Str_SetPtrAtoW(WCHAR **dst, const char *src)
2528 TRACE("%p, %s.\n", dst, debugstr_a(src));
2530 if (src)
2532 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
2533 LPWSTR ptr = ReAlloc(*dst, len * sizeof(**dst));
2535 if (!ptr)
2536 return FALSE;
2537 MultiByteToWideChar(CP_ACP, 0, src, -1, ptr, len);
2538 *dst = ptr;
2540 else
2542 Free(*dst);
2543 *dst = NULL;
2546 return TRUE;
2549 /**************************************************************************
2550 * Str_SetPtrWtoA [internal]
2552 * Converts a unicode string to a multi byte string.
2553 * If the pointer to the destination buffer is NULL a buffer is allocated.
2554 * If the destination buffer is too small to keep the converted wide
2555 * string the destination buffer is reallocated. If the source pointer is
2556 * NULL, the destination buffer is freed.
2558 BOOL Str_SetPtrWtoA(char **dst, const WCHAR *src)
2560 TRACE("%p, %s.\n", dst, debugstr_w(src));
2562 if (src)
2564 INT len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, FALSE);
2565 LPSTR ptr = ReAlloc(*dst, len * sizeof(**dst));
2567 if (!ptr)
2568 return FALSE;
2569 WideCharToMultiByte(CP_ACP, 0, src, -1, ptr, len, NULL, FALSE);
2570 *dst = ptr;
2572 else
2574 Free(*dst);
2575 *dst = NULL;
2578 return TRUE;
2581 /**************************************************************************
2582 * Notification functions
2585 struct NOTIFYDATA
2587 HWND hwndFrom;
2588 HWND hwndTo;
2589 DWORD dwParam3;
2590 DWORD dwParam4;
2591 DWORD dwParam5;
2592 DWORD dwParam6;
2595 /**************************************************************************
2596 * DoNotify [Internal]
2599 static LRESULT DoNotify(const struct NOTIFYDATA *notify, UINT code, NMHDR *hdr)
2601 NMHDR nmhdr;
2602 NMHDR *lpNmh = NULL;
2603 UINT idFrom = 0;
2605 TRACE("%p, %p, %d, %p, %#x.\n", notify->hwndFrom, notify->hwndTo, code, hdr, notify->dwParam5);
2607 if (!notify->hwndTo)
2608 return 0;
2610 if (notify->hwndFrom == (HWND)-1)
2612 lpNmh = hdr;
2613 idFrom = hdr->idFrom;
2615 else
2617 if (notify->hwndFrom)
2618 idFrom = GetDlgCtrlID(notify->hwndFrom);
2620 lpNmh = hdr ? hdr : &nmhdr;
2621 lpNmh->hwndFrom = notify->hwndFrom;
2622 lpNmh->idFrom = idFrom;
2623 lpNmh->code = code;
2626 return SendMessageW(notify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
2629 /**************************************************************************
2630 * SendNotify [COMCTL32.341]
2632 * Sends a WM_NOTIFY message to the specified window.
2635 LRESULT WINAPI SendNotify(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr)
2637 struct NOTIFYDATA notify;
2639 TRACE("%p, %p, %d, %p.\n", hwndTo, hwndFrom, code, hdr);
2641 notify.hwndFrom = hwndFrom;
2642 notify.hwndTo = hwndTo;
2643 notify.dwParam5 = 0;
2644 notify.dwParam6 = 0;
2646 return DoNotify(&notify, code, hdr);
2649 /**************************************************************************
2650 * SendNotifyEx [COMCTL32.342]
2652 * Sends a WM_NOTIFY message to the specified window.
2654 * PARAMS
2655 * hwndFrom [I] Window to receive the message
2656 * hwndTo [I] Window that the message is from
2657 * code [I] Notification code
2658 * hdr [I] The NMHDR and any additional information to send or NULL
2659 * dwParam5 [I] Unknown
2661 * RETURNS
2662 * Success: return value from notification
2663 * Failure: 0
2665 * NOTES
2666 * If hwndFrom is -1 then the identifier of the control sending the
2667 * message is taken from the NMHDR structure.
2668 * If hwndFrom is not -1 then lpHdr can be NULL.
2670 LRESULT WINAPI SendNotifyEx(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr, DWORD dwParam5)
2672 struct NOTIFYDATA notify;
2673 HWND hwndNotify;
2675 TRACE("(%p %p %d %p %#x)\n", hwndFrom, hwndTo, code, hdr, dwParam5);
2677 hwndNotify = hwndTo;
2678 if (!hwndTo)
2680 if (IsWindow(hwndFrom))
2682 hwndNotify = GetParent(hwndFrom);
2683 if (!hwndNotify)
2684 return 0;
2688 notify.hwndFrom = hwndFrom;
2689 notify.hwndTo = hwndNotify;
2690 notify.dwParam5 = dwParam5;
2691 notify.dwParam6 = 0;
2693 return DoNotify(&notify, code, hdr);