wineps.drv: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / comctl32 / commctrl.c
blob4c5900bc37ff6c0ca43b247a1a31753e2c21c931
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, %#lx, %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 ();
211 break;
213 case DLL_PROCESS_DETACH:
214 if (lpvReserved) break;
216 /* unregister all common control classes */
217 ANIMATE_Unregister ();
218 COMBOEX_Unregister ();
219 DATETIME_Unregister ();
220 FLATSB_Unregister ();
221 HEADER_Unregister ();
222 HOTKEY_Unregister ();
223 IPADDRESS_Unregister ();
224 LISTVIEW_Unregister ();
225 MONTHCAL_Unregister ();
226 NATIVEFONT_Unregister ();
227 PAGER_Unregister ();
228 PROGRESS_Unregister ();
229 REBAR_Unregister ();
230 STATUS_Unregister ();
231 SYSLINK_Unregister ();
232 TAB_Unregister ();
233 TOOLBAR_Unregister ();
234 TOOLTIPS_Unregister ();
235 TRACKBAR_Unregister ();
236 TREEVIEW_Unregister ();
237 UPDOWN_Unregister ();
239 unregister_versioned_classes ();
241 /* delete local pattern brush */
242 DeleteObject (COMCTL32_hPattern55AABrush);
243 DeleteObject (COMCTL32_hPattern55AABitmap);
245 /* delete global subclassing atom */
246 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
247 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
248 break;
251 return TRUE;
255 /***********************************************************************
256 * MenuHelp [COMCTL32.2]
258 * Handles the setting of status bar help messages when the user
259 * selects menu items.
261 * PARAMS
262 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
263 * wParam [I] wParam of the message uMsg
264 * lParam [I] lParam of the message uMsg
265 * hMainMenu [I] handle to the application's main menu
266 * hInst [I] handle to the module that contains string resources
267 * hwndStatus [I] handle to the status bar window
268 * lpwIDs [I] pointer to an array of integers (see NOTES)
270 * RETURNS
271 * No return value
273 * NOTES
274 * The official documentation is incomplete!
275 * This is the correct documentation:
277 * uMsg:
278 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
279 * WM_MENUSELECT messages.
281 * lpwIDs:
282 * (will be written ...)
285 VOID WINAPI
286 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
287 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
289 UINT uMenuID = 0;
291 if (!IsWindow (hwndStatus))
292 return;
294 switch (uMsg) {
295 case WM_MENUSELECT:
296 TRACE("WM_MENUSELECT wParam %#Ix, lParam %#Ix\n", wParam, lParam);
298 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
299 /* menu was closed */
300 TRACE("menu was closed!\n");
301 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
303 else {
304 /* menu item was selected */
305 if (HIWORD(wParam) & MF_POPUP)
306 uMenuID = *(lpwIDs+1);
307 else
308 uMenuID = (UINT)LOWORD(wParam);
309 TRACE("uMenuID = %u\n", uMenuID);
311 if (uMenuID) {
312 WCHAR szText[256];
314 if (!LoadStringW (hInst, uMenuID, szText, ARRAY_SIZE(szText)))
315 szText[0] = '\0';
317 SendMessageW (hwndStatus, SB_SETTEXTW,
318 255 | SBT_NOBORDERS, (LPARAM)szText);
319 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
322 break;
324 case WM_COMMAND :
325 TRACE("WM_COMMAND wParam %#Ix, lParam %#Ix\n", wParam, lParam);
326 /* WM_COMMAND is not invalid since it is documented
327 * in the windows api reference. So don't output
328 * any FIXME for WM_COMMAND
330 WARN("We don't care about the WM_COMMAND\n");
331 break;
333 default:
334 FIXME("Invalid Message 0x%x!\n", uMsg);
335 break;
340 /***********************************************************************
341 * ShowHideMenuCtl [COMCTL32.3]
343 * Shows or hides controls and updates the corresponding menu item.
345 * PARAMS
346 * hwnd [I] handle to the client window.
347 * uFlags [I] menu command id.
348 * lpInfo [I] pointer to an array of integers. (See NOTES.)
350 * RETURNS
351 * Success: TRUE
352 * Failure: FALSE
354 * NOTES
355 * The official documentation is incomplete!
356 * This is the correct documentation:
358 * hwnd
359 * Handle to the window that contains the menu and controls.
361 * uFlags
362 * Identifier of the menu item to receive or lose a check mark.
364 * lpInfo
365 * The array of integers contains pairs of values. BOTH values of
366 * the first pair must be the handles to the application's main menu.
367 * Each subsequent pair consists of a menu id and control id.
370 BOOL WINAPI
371 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
373 LPINT lpMenuId;
375 TRACE("%p, %Ix, %p\n", hwnd, uFlags, lpInfo);
377 if (lpInfo == NULL)
378 return FALSE;
380 if (!(lpInfo[0]) || !(lpInfo[1]))
381 return FALSE;
383 /* search for control */
384 lpMenuId = &lpInfo[2];
385 while (*lpMenuId != uFlags)
386 lpMenuId += 2;
388 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
389 /* uncheck menu item */
390 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
392 /* hide control */
393 lpMenuId++;
394 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
395 SWP_HIDEWINDOW);
397 else {
398 /* check menu item */
399 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
401 /* show control */
402 lpMenuId++;
403 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
404 SWP_SHOWWINDOW);
407 return TRUE;
411 /***********************************************************************
412 * GetEffectiveClientRect [COMCTL32.4]
414 * Calculates the coordinates of a rectangle in the client area.
416 * PARAMS
417 * hwnd [I] handle to the client window.
418 * lpRect [O] pointer to the rectangle of the client window
419 * lpInfo [I] pointer to an array of integers (see NOTES)
421 * RETURNS
422 * No return value.
424 * NOTES
425 * The official documentation is incomplete!
426 * This is the correct documentation:
428 * lpInfo
429 * (will be written ...)
432 VOID WINAPI
433 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
435 RECT rcCtrl;
436 const INT *lpRun;
437 HWND hwndCtrl;
439 TRACE("(%p %p %p)\n",
440 hwnd, lpRect, lpInfo);
442 GetClientRect (hwnd, lpRect);
443 lpRun = lpInfo;
445 do {
446 lpRun += 2;
447 if (*lpRun == 0)
448 return;
449 lpRun++;
450 hwndCtrl = GetDlgItem (hwnd, *lpRun);
451 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
452 TRACE("control id 0x%x\n", *lpRun);
453 GetWindowRect (hwndCtrl, &rcCtrl);
454 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
455 SubtractRect (lpRect, lpRect, &rcCtrl);
457 lpRun++;
458 } while (*lpRun);
461 void COMCTL32_DrawStatusText(HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style, BOOL draw_background)
463 RECT r = *lprc;
464 UINT border;
465 COLORREF oldbkcolor;
467 if (draw_background)
469 if (style & SBT_POPOUT)
470 border = BDR_RAISEDOUTER;
471 else if (style & SBT_NOBORDERS)
472 border = 0;
473 else
474 border = BDR_SUNKENOUTER;
476 oldbkcolor = SetBkColor (hdc, comctl32_color.clrBtnFace);
477 DrawEdge (hdc, &r, border, BF_MIDDLE|BF_RECT|BF_ADJUST);
478 SetBkColor (hdc, oldbkcolor);
481 /* now draw text */
482 if (text) {
483 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
484 COLORREF oldtextcolor;
485 UINT align = DT_LEFT;
486 int strCnt = 0;
488 oldtextcolor = SetTextColor (hdc, comctl32_color.clrBtnText);
489 if (style & SBT_RTLREADING)
490 FIXME("Unsupported RTL style!\n");
491 r.left += 3;
492 do {
493 if (*text == '\t') {
494 if (strCnt) {
495 DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
496 strCnt = 0;
498 if (align==DT_RIGHT) {
499 break;
501 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
502 } else {
503 strCnt++;
505 } while(*text++);
507 if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
508 SetBkMode (hdc, oldbkmode);
509 SetTextColor (hdc, oldtextcolor);
513 /***********************************************************************
514 * DrawStatusTextW [COMCTL32.@]
516 * Draws text with borders, like in a status bar.
518 * PARAMS
519 * hdc [I] handle to the window's display context
520 * lprc [I] pointer to a rectangle
521 * text [I] pointer to the text
522 * style [I] drawing style
524 * RETURNS
525 * No return value.
527 * NOTES
528 * The style variable can have one of the following values:
529 * (will be written ...)
532 void WINAPI DrawStatusTextW(HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
534 COMCTL32_DrawStatusText(hdc, lprc, text, style, TRUE);
537 /***********************************************************************
538 * DrawStatusText [COMCTL32.@]
539 * DrawStatusTextA [COMCTL32.5]
541 * Draws text with borders, like in a status bar.
543 * PARAMS
544 * hdc [I] handle to the window's display context
545 * lprc [I] pointer to a rectangle
546 * text [I] pointer to the text
547 * style [I] drawing style
549 * RETURNS
550 * No return value.
553 void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
555 INT len;
556 LPWSTR textW = NULL;
558 if ( text ) {
559 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
560 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
561 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
564 DrawStatusTextW( hdc, lprc, textW, style );
565 Free( textW );
569 /***********************************************************************
570 * CreateStatusWindow [COMCTL32.@]
571 * CreateStatusWindowA [COMCTL32.6]
573 * Creates a status bar
575 * PARAMS
576 * style [I] window style
577 * text [I] pointer to the window text
578 * parent [I] handle to the parent window
579 * wid [I] control id of the status bar
581 * RETURNS
582 * Success: handle to the status window
583 * Failure: 0
586 HWND WINAPI
587 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
589 return CreateWindowA(STATUSCLASSNAMEA, text, style,
590 CW_USEDEFAULT, CW_USEDEFAULT,
591 CW_USEDEFAULT, CW_USEDEFAULT,
592 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
596 /***********************************************************************
597 * CreateStatusWindowW [COMCTL32.@]
599 * Creates a status bar control
601 * PARAMS
602 * style [I] window style
603 * text [I] pointer to the window text
604 * parent [I] handle to the parent window
605 * wid [I] control id of the status bar
607 * RETURNS
608 * Success: handle to the status window
609 * Failure: 0
612 HWND WINAPI
613 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
615 return CreateWindowW(STATUSCLASSNAMEW, text, style,
616 CW_USEDEFAULT, CW_USEDEFAULT,
617 CW_USEDEFAULT, CW_USEDEFAULT,
618 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
622 /***********************************************************************
623 * CreateUpDownControl [COMCTL32.16]
625 * Creates an up-down control
627 * PARAMS
628 * style [I] window styles
629 * x [I] horizontal position of the control
630 * y [I] vertical position of the control
631 * cx [I] with of the control
632 * cy [I] height of the control
633 * parent [I] handle to the parent window
634 * id [I] the control's identifier
635 * inst [I] handle to the application's module instance
636 * buddy [I] handle to the buddy window, can be NULL
637 * maxVal [I] upper limit of the control
638 * minVal [I] lower limit of the control
639 * curVal [I] current value of the control
641 * RETURNS
642 * Success: handle to the updown control
643 * Failure: 0
646 HWND WINAPI
647 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
648 HWND parent, INT id, HINSTANCE inst,
649 HWND buddy, INT maxVal, INT minVal, INT curVal)
651 HWND hUD =
652 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
653 parent, (HMENU)(DWORD_PTR)id, inst, 0);
654 if (hUD) {
655 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
656 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
657 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
660 return hUD;
664 /***********************************************************************
665 * InitCommonControls [COMCTL32.17]
667 * Registers the common controls.
669 * PARAMS
670 * No parameters.
672 * RETURNS
673 * No return values.
675 * NOTES
676 * This function is just a dummy - all the controls are registered at
677 * the DLL initialization time. See InitCommonControlsEx for details.
680 VOID WINAPI
681 InitCommonControls (void)
686 /***********************************************************************
687 * InitCommonControlsEx [COMCTL32.@]
689 * Registers the common controls.
691 * PARAMS
692 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
694 * RETURNS
695 * Success: TRUE
696 * Failure: FALSE
698 * NOTES
699 * Probably all versions of comctl32 initializes the Win95 controls in DllMain
700 * during DLL initialization. Starting from comctl32 v5.82 all the controls
701 * are initialized there. We follow this behaviour and this function is just
702 * a dummy.
704 * Note: when writing programs under Windows, if you don't call any function
705 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
706 * was the only comctl32 function you were calling and you remove it you may
707 * have a false impression that InitCommonControlsEx actually did something.
710 BOOL WINAPI
711 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
713 if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
714 return FALSE;
716 TRACE("%#lx\n", lpInitCtrls->dwICC);
717 return TRUE;
721 /***********************************************************************
722 * CreateToolbarEx [COMCTL32.@]
724 * Creates a toolbar window.
726 * PARAMS
727 * hwnd
728 * style
729 * wID
730 * nBitmaps
731 * hBMInst
732 * wBMID
733 * lpButtons
734 * iNumButtons
735 * dxButton
736 * dyButton
737 * dxBitmap
738 * dyBitmap
739 * uStructSize
741 * RETURNS
742 * Success: handle to the tool bar control
743 * Failure: 0
746 HWND WINAPI
747 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
748 HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
749 INT iNumButtons, INT dxButton, INT dyButton,
750 INT dxBitmap, INT dyBitmap, UINT uStructSize)
752 HWND hwndTB;
754 hwndTB =
755 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
756 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
757 if(hwndTB) {
758 TBADDBITMAP tbab;
760 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
762 /* set bitmap and button size */
763 /*If CreateToolbarEx receives 0, windows sets default values*/
764 if (dxBitmap < 0)
765 dxBitmap = 16;
766 if (dyBitmap < 0)
767 dyBitmap = 16;
768 if (dxBitmap == 0 || dyBitmap == 0)
769 dxBitmap = dyBitmap = 16;
770 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
772 if (dxButton < 0)
773 dxButton = dxBitmap;
774 if (dyButton < 0)
775 dyButton = dyBitmap;
776 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
777 if (dxButton != 0 && dyButton != 0)
778 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
781 /* add bitmaps */
782 if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
784 tbab.hInst = hBMInst;
785 tbab.nID = wBMID;
787 SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
789 /* add buttons */
790 if(iNumButtons > 0)
791 SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
794 return hwndTB;
798 /***********************************************************************
799 * CreateMappedBitmap [COMCTL32.8]
801 * Loads a bitmap resource using a colour map.
803 * PARAMS
804 * hInstance [I] Handle to the module containing the bitmap.
805 * idBitmap [I] The bitmap resource ID.
806 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
807 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
808 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
810 * RETURNS
811 * Success: handle to the new bitmap
812 * Failure: 0
815 HBITMAP WINAPI
816 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
817 LPCOLORMAP lpColorMap, INT iNumMaps)
819 HGLOBAL hglb;
820 HRSRC hRsrc;
821 const BITMAPINFOHEADER *lpBitmap;
822 LPBITMAPINFOHEADER lpBitmapInfo;
823 UINT nSize, nColorTableSize, iColor;
824 RGBQUAD *pColorTable;
825 INT i, iMaps, nWidth, nHeight;
826 HDC hdcScreen;
827 HBITMAP hbm;
828 LPCOLORMAP sysColorMap;
829 COLORREF cRef;
830 COLORMAP internalColorMap[4] =
831 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
833 /* initialize pointer to colortable and default color table */
834 if (lpColorMap) {
835 iMaps = iNumMaps;
836 sysColorMap = lpColorMap;
838 else {
839 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
840 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
841 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
842 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
843 iMaps = 4;
844 sysColorMap = internalColorMap;
847 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
848 if (hRsrc == 0)
849 return 0;
850 hglb = LoadResource (hInstance, hRsrc);
851 if (hglb == 0)
852 return 0;
853 lpBitmap = LockResource (hglb);
854 if (lpBitmap == NULL)
855 return 0;
857 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
858 nColorTableSize = lpBitmap->biClrUsed;
859 else if (lpBitmap->biBitCount <= 8)
860 nColorTableSize = (1 << lpBitmap->biBitCount);
861 else
862 nColorTableSize = 0;
863 nSize = lpBitmap->biSize;
864 if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
865 nSize += 3 * sizeof(DWORD);
866 nSize += nColorTableSize * sizeof(RGBQUAD);
867 lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
868 if (lpBitmapInfo == NULL)
869 return 0;
870 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
872 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
874 for (iColor = 0; iColor < nColorTableSize; iColor++) {
875 for (i = 0; i < iMaps; i++) {
876 cRef = RGB(pColorTable[iColor].rgbRed,
877 pColorTable[iColor].rgbGreen,
878 pColorTable[iColor].rgbBlue);
879 if ( cRef == sysColorMap[i].from) {
880 #if 0
881 if (wFlags & CBS_MASKED) {
882 if (sysColorMap[i].to != COLOR_BTNTEXT)
883 pColorTable[iColor] = RGB(255, 255, 255);
885 else
886 #endif
887 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
888 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
889 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
890 break;
894 nWidth = lpBitmapInfo->biWidth;
895 nHeight = lpBitmapInfo->biHeight;
896 hdcScreen = GetDC (NULL);
897 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
898 if (hbm) {
899 HDC hdcDst = CreateCompatibleDC (hdcScreen);
900 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
901 const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
902 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
903 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
904 SRCCOPY);
905 SelectObject (hdcDst, hbmOld);
906 DeleteDC (hdcDst);
908 ReleaseDC (NULL, hdcScreen);
909 GlobalFree (lpBitmapInfo);
910 FreeResource (hglb);
912 return hbm;
916 /***********************************************************************
917 * CreateToolbar [COMCTL32.7]
919 * Creates a toolbar control.
921 * PARAMS
922 * hwnd
923 * style
924 * wID
925 * nBitmaps
926 * hBMInst
927 * wBMID
928 * lpButtons
929 * iNumButtons
931 * RETURNS
932 * Success: handle to the tool bar control
933 * Failure: 0
935 * NOTES
936 * Do not use this function anymore. Use CreateToolbarEx instead.
939 HWND WINAPI
940 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
941 HINSTANCE hBMInst, UINT wBMID,
942 LPCTBBUTTON lpButtons,INT iNumButtons)
944 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
945 hBMInst, wBMID, lpButtons,
946 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
950 /***********************************************************************
951 * DllGetVersion [COMCTL32.@]
953 * Retrieves version information of the 'COMCTL32.DLL'
955 * PARAMS
956 * pdvi [O] pointer to version information structure.
958 * RETURNS
959 * Success: S_OK
960 * Failure: E_INVALIDARG
962 * NOTES
963 * Returns version of a comctl32.dll from IE4.01 SP1.
966 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
968 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
969 WARN("wrong DLLVERSIONINFO size from app\n");
970 return E_INVALIDARG;
973 pdvi->dwMajorVersion = COMCTL32_VERSION;
974 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
975 pdvi->dwBuildNumber = 2919;
976 pdvi->dwPlatformID = 6304;
978 TRACE("%lu.%lu.%lu.%lu\n", pdvi->dwMajorVersion, pdvi->dwMinorVersion,
979 pdvi->dwBuildNumber, pdvi->dwPlatformID);
981 return S_OK;
984 /***********************************************************************
985 * DllInstall (COMCTL32.@)
987 * Installs the ComCtl32 DLL.
989 * RETURNS
990 * Success: S_OK
991 * Failure: A HRESULT error
993 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
995 TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
996 return S_OK;
999 /***********************************************************************
1000 * _TrackMouseEvent [COMCTL32.@]
1002 * Requests notification of mouse events
1004 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1005 * to the hwnd specified in the ptme structure. After the event message
1006 * is posted to the hwnd, the entry in the queue is removed.
1008 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1009 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1010 * immediately and the TME_LEAVE flag being ignored.
1012 * PARAMS
1013 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1015 * RETURNS
1016 * Success: non-zero
1017 * Failure: zero
1019 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1023 BOOL WINAPI
1024 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1026 return TrackMouseEvent (ptme);
1029 /*************************************************************************
1030 * GetMUILanguage [COMCTL32.@]
1032 * Returns the user interface language in use by the current process.
1034 * RETURNS
1035 * Language ID in use by the current process.
1037 LANGID WINAPI GetMUILanguage (VOID)
1039 return COMCTL32_uiLang;
1043 /*************************************************************************
1044 * InitMUILanguage [COMCTL32.@]
1046 * Sets the user interface language to be used by the current process.
1048 * RETURNS
1049 * Nothing.
1051 VOID WINAPI InitMUILanguage (LANGID uiLang)
1053 COMCTL32_uiLang = uiLang;
1057 /***********************************************************************
1058 * SetWindowSubclass [COMCTL32.410]
1060 * Starts a window subclass
1062 * PARAMS
1063 * hWnd [in] handle to window subclass.
1064 * pfnSubclass [in] Pointer to new window procedure.
1065 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1066 * dwRef [in] Reference data to pass to window procedure.
1068 * RETURNS
1069 * Success: non-zero
1070 * Failure: zero
1072 * BUGS
1073 * If an application manually subclasses a window after subclassing it with
1074 * this API and then with this API again, then none of the previous
1075 * subclasses get called or the original window procedure.
1078 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1079 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1081 LPSUBCLASS_INFO stack;
1082 LPSUBCLASSPROCS proc;
1084 TRACE("%p, %p, %Ix, %Ix\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1086 if (!hWnd || !pfnSubclass)
1087 return FALSE;
1089 /* Since the window procedure that we set here has two additional arguments,
1090 * we can't simply set it as the new window procedure of the window. So we
1091 * set our own window procedure and then calculate the other two arguments
1092 * from there. */
1094 /* See if we have been called for this window */
1095 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1096 if (!stack) {
1097 /* allocate stack */
1098 stack = Alloc (sizeof(SUBCLASS_INFO));
1099 if (!stack) {
1100 ERR ("Failed to allocate our Subclassing stack\n");
1101 return FALSE;
1103 SetPropW (hWnd, COMCTL32_wSubclass, stack);
1105 /* set window procedure to our own and save the current one */
1106 stack->is_unicode = IsWindowUnicode (hWnd);
1107 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1108 (DWORD_PTR)COMCTL32_SubclassProc);
1110 else {
1111 /* Check to see if we have called this function with the same uIDSubClass
1112 * and pfnSubclass */
1113 proc = stack->SubclassProcs;
1114 while (proc) {
1115 if ((proc->id == uIDSubclass) &&
1116 (proc->subproc == pfnSubclass)) {
1117 proc->ref = dwRef;
1118 return TRUE;
1120 proc = proc->next;
1124 proc = Alloc(sizeof(SUBCLASSPROCS));
1125 if (!proc) {
1126 ERR ("Failed to allocate subclass entry in stack\n");
1127 if (stack->is_unicode)
1128 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1129 else
1130 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1131 Free (stack);
1132 RemovePropW( hWnd, COMCTL32_wSubclass );
1133 return FALSE;
1136 proc->subproc = pfnSubclass;
1137 proc->ref = dwRef;
1138 proc->id = uIDSubclass;
1139 proc->next = stack->SubclassProcs;
1140 stack->SubclassProcs = proc;
1142 return TRUE;
1146 /***********************************************************************
1147 * GetWindowSubclass [COMCTL32.411]
1149 * Gets the Reference data from a subclass.
1151 * PARAMS
1152 * hWnd [in] Handle to the window which we are subclassing
1153 * pfnSubclass [in] Pointer to the subclass procedure
1154 * uID [in] Unique identifier of the subclassing procedure
1155 * pdwRef [out] Pointer to the reference data
1157 * RETURNS
1158 * Success: Non-zero
1159 * Failure: 0
1162 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1163 UINT_PTR uID, DWORD_PTR *pdwRef)
1165 const SUBCLASS_INFO *stack;
1166 const SUBCLASSPROCS *proc;
1168 TRACE("%p, %p, %Ix, %p\n", hWnd, pfnSubclass, uID, pdwRef);
1170 /* See if we have been called for this window */
1171 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1172 if (!stack)
1173 goto done;
1175 proc = stack->SubclassProcs;
1176 while (proc) {
1177 if ((proc->id == uID) &&
1178 (proc->subproc == pfnSubclass)) {
1179 if (pdwRef)
1180 *pdwRef = proc->ref;
1181 return TRUE;
1183 proc = proc->next;
1186 done:
1187 if (pdwRef)
1188 *pdwRef = 0;
1189 return FALSE;
1193 /***********************************************************************
1194 * RemoveWindowSubclass [COMCTL32.412]
1196 * Removes a window subclass.
1198 * PARAMS
1199 * hWnd [in] Handle to the window which we are subclassing
1200 * pfnSubclass [in] Pointer to the subclass procedure
1201 * uID [in] Unique identifier of this subclass
1203 * RETURNS
1204 * Success: non-zero
1205 * Failure: zero
1208 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1210 LPSUBCLASS_INFO stack;
1211 LPSUBCLASSPROCS prevproc = NULL;
1212 LPSUBCLASSPROCS proc;
1213 BOOL ret = FALSE;
1215 TRACE("%p, %p, %Ix.\n", hWnd, pfnSubclass, uID);
1217 /* Find the Subclass to remove */
1218 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1219 if (!stack)
1220 return FALSE;
1222 proc = stack->SubclassProcs;
1223 while (proc) {
1224 if ((proc->id == uID) &&
1225 (proc->subproc == pfnSubclass)) {
1227 if (!prevproc)
1228 stack->SubclassProcs = proc->next;
1229 else
1230 prevproc->next = proc->next;
1232 if (stack->stackpos == proc)
1233 stack->stackpos = stack->stackpos->next;
1235 Free (proc);
1236 ret = TRUE;
1237 break;
1239 prevproc = proc;
1240 proc = proc->next;
1243 if (!stack->SubclassProcs && !stack->running) {
1244 TRACE("Last Subclass removed, cleaning up\n");
1245 /* clean up our heap and reset the original window procedure */
1246 if ((WNDPROC)GetWindowLongPtrW (hWnd, GWLP_WNDPROC) != COMCTL32_SubclassProc)
1247 WARN("Window procedure has been modified, skipping restore\n");
1248 else if (stack->is_unicode)
1249 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1250 else
1251 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1252 Free (stack);
1253 RemovePropW( hWnd, COMCTL32_wSubclass );
1256 return ret;
1259 /***********************************************************************
1260 * COMCTL32_SubclassProc (internal)
1262 * Window procedure for all subclassed windows.
1263 * Saves the current subclassing stack position to support nested messages
1265 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1267 LPSUBCLASS_INFO stack;
1268 LPSUBCLASSPROCS proc;
1269 LRESULT ret;
1271 TRACE("%p, %#x, %#Ix, %#Ix\n", hWnd, uMsg, wParam, lParam);
1273 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1274 if (!stack) {
1275 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1276 return 0;
1279 /* Save our old stackpos to properly handle nested messages */
1280 proc = stack->stackpos;
1281 stack->stackpos = stack->SubclassProcs;
1282 stack->running++;
1283 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1284 stack->running--;
1285 stack->stackpos = proc;
1287 if (!stack->SubclassProcs && !stack->running) {
1288 TRACE("Last Subclass removed, cleaning up\n");
1289 /* clean up our heap and reset the original window procedure */
1290 if (stack->is_unicode)
1291 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1292 else
1293 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1294 Free (stack);
1295 RemovePropW( hWnd, COMCTL32_wSubclass );
1297 return ret;
1300 /***********************************************************************
1301 * DefSubclassProc [COMCTL32.413]
1303 * Calls the next window procedure (i.e. the one before this subclass)
1305 * PARAMS
1306 * hWnd [in] The window that we're subclassing
1307 * uMsg [in] Message
1308 * wParam [in] WPARAM
1309 * lParam [in] LPARAM
1311 * RETURNS
1312 * Success: non-zero
1313 * Failure: zero
1316 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1318 LPSUBCLASS_INFO stack;
1319 LRESULT ret;
1321 TRACE("%p, %#x, %#Ix, %#Ix\n", hWnd, uMsg, wParam, lParam);
1323 /* retrieve our little stack from the Properties */
1324 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1325 if (!stack) {
1326 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1327 return 0;
1330 /* If we are at the end of stack then we have to call the original
1331 * window procedure */
1332 if (!stack->stackpos) {
1333 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1334 } else {
1335 const SUBCLASSPROCS *proc = stack->stackpos;
1336 stack->stackpos = stack->stackpos->next;
1337 /* call the Subclass procedure from the stack */
1338 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1339 proc->id, proc->ref);
1342 return ret;
1346 /***********************************************************************
1347 * COMCTL32_CreateToolTip [NOT AN API]
1349 * Creates a tooltip for the control specified in hwnd and does all
1350 * necessary setup and notifications.
1352 * PARAMS
1353 * hwndOwner [I] Handle to the window that will own the tool tip.
1355 * RETURNS
1356 * Success: Handle of tool tip window.
1357 * Failure: NULL
1360 HWND
1361 COMCTL32_CreateToolTip(HWND hwndOwner)
1363 HWND hwndToolTip;
1365 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1366 CW_USEDEFAULT, CW_USEDEFAULT,
1367 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1368 0, 0, 0);
1370 /* Send NM_TOOLTIPSCREATED notification */
1371 if (hwndToolTip)
1373 NMTOOLTIPSCREATED nmttc;
1374 /* true owner can be different if hwndOwner is a child window */
1375 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1376 nmttc.hdr.hwndFrom = hwndTrueOwner;
1377 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1378 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1379 nmttc.hwndToolTips = hwndToolTip;
1381 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1382 GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
1385 return hwndToolTip;
1389 /***********************************************************************
1390 * COMCTL32_RefreshSysColors [NOT AN API]
1392 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1393 * refresh the color values in the color structure
1395 * PARAMS
1396 * none
1398 * RETURNS
1399 * none
1402 VOID
1403 COMCTL32_RefreshSysColors(void)
1405 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1406 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1407 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1408 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1409 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1410 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1411 comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1412 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1413 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1414 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1415 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1416 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1417 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1418 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1419 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1420 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1421 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1424 /***********************************************************************
1425 * COMCTL32_DrawInsertMark [NOT AN API]
1427 * Draws an insertion mark (which looks similar to an 'I').
1429 * PARAMS
1430 * hDC [I] Device context to draw onto.
1431 * lpRect [I] Co-ordinates of insertion mark.
1432 * clrInsertMark [I] Colour of the insertion mark.
1433 * bHorizontal [I] True if insert mark should be drawn horizontally,
1434 * vertical otherwise.
1436 * RETURNS
1437 * none
1439 * NOTES
1440 * Draws up to but not including the bottom co-ordinate when drawing
1441 * vertically or the right co-ordinate when horizontal.
1443 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1445 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1446 HPEN hOldPen;
1447 static const DWORD adwPolyPoints[] = {4,4,4};
1448 LONG lCentre = (bHorizontal ?
1449 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1450 lpRect->left + (lpRect->right - lpRect->left)/2);
1451 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1452 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1453 const POINT aptInsertMark[] =
1455 /* top (V) or left (H) arrow */
1456 {lCentre , l1 + 2},
1457 {lCentre - 2, l1 },
1458 {lCentre + 3, l1 },
1459 {lCentre + 1, l1 + 2},
1460 /* middle line */
1461 {lCentre , l2 - 2},
1462 {lCentre , l1 - 1},
1463 {lCentre + 1, l1 - 1},
1464 {lCentre + 1, l2 - 2},
1465 /* bottom (V) or right (H) arrow */
1466 {lCentre , l2 - 3},
1467 {lCentre - 2, l2 - 1},
1468 {lCentre + 3, l2 - 1},
1469 {lCentre + 1, l2 - 3},
1471 hOldPen = SelectObject(hDC, hPen);
1472 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, ARRAY_SIZE(adwPolyPoints));
1473 SelectObject(hDC, hOldPen);
1474 DeleteObject(hPen);
1477 /***********************************************************************
1478 * COMCTL32_EnsureBitmapSize [internal]
1480 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1481 * the height is at least cyMinHeight. If the bitmap already has these
1482 * dimensions nothing changes.
1484 * PARAMS
1485 * hBitmap [I/O] Bitmap to modify. The handle may change
1486 * cxMinWidth [I] If the width of the bitmap is smaller, then it will
1487 * be enlarged to this value
1488 * cyMinHeight [I] If the height of the bitmap is smaller, then it will
1489 * be enlarged to this value
1490 * cyBackground [I] The color with which the new area will be filled
1492 * RETURNS
1493 * none
1495 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1497 int cxNew, cyNew;
1498 BITMAP bmp;
1499 HBITMAP hNewBitmap;
1500 HBITMAP hNewDCBitmap, hOldDCBitmap;
1501 HBRUSH hNewDCBrush;
1502 HDC hdcNew, hdcOld;
1504 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1505 return;
1506 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1507 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1508 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1509 return;
1511 hdcNew = CreateCompatibleDC(NULL);
1512 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1513 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1514 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1516 hdcOld = CreateCompatibleDC(NULL);
1517 hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1519 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1520 if (bmp.bmWidth < cxMinWidth)
1521 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1522 if (bmp.bmHeight < cyMinHeight)
1523 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1524 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1525 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1527 SelectObject(hdcNew, hNewDCBitmap);
1528 DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1529 DeleteDC(hdcNew);
1530 SelectObject(hdcOld, hOldDCBitmap);
1531 DeleteDC(hdcOld);
1533 DeleteObject(*pBitmap);
1534 *pBitmap = hNewBitmap;
1535 return;
1538 void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
1540 HDC hdc = GetDC(NULL);
1541 HFONT hOldFont;
1543 hOldFont = SelectObject(hdc, hFont);
1544 GetTextMetricsW(hdc, ptm);
1545 SelectObject(hdc, hOldFont);
1546 ReleaseDC(NULL, hdc);
1549 #ifndef OCM__BASE /* avoid including olectl.h */
1550 #define OCM__BASE (WM_USER+0x1c00)
1551 #endif
1553 /***********************************************************************
1554 * COMCTL32_IsReflectedMessage [internal]
1556 * Some parents reflect notify messages - for some messages sent by the child,
1557 * they send it back with the message code increased by OCM__BASE (0x2000).
1558 * This allows better subclassing of controls. We don't need to handle such
1559 * messages but we don't want to print ERRs for them, so this helper function
1560 * identifies them.
1562 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1563 * collision with defined CCM_ codes.
1565 BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
1567 switch (uMsg)
1569 case OCM__BASE + WM_COMMAND:
1570 case OCM__BASE + WM_CTLCOLORBTN:
1571 case OCM__BASE + WM_CTLCOLOREDIT:
1572 case OCM__BASE + WM_CTLCOLORDLG:
1573 case OCM__BASE + WM_CTLCOLORLISTBOX:
1574 case OCM__BASE + WM_CTLCOLORMSGBOX:
1575 case OCM__BASE + WM_CTLCOLORSCROLLBAR:
1576 case OCM__BASE + WM_CTLCOLORSTATIC:
1577 case OCM__BASE + WM_DRAWITEM:
1578 case OCM__BASE + WM_MEASUREITEM:
1579 case OCM__BASE + WM_DELETEITEM:
1580 case OCM__BASE + WM_VKEYTOITEM:
1581 case OCM__BASE + WM_CHARTOITEM:
1582 case OCM__BASE + WM_COMPAREITEM:
1583 case OCM__BASE + WM_HSCROLL:
1584 case OCM__BASE + WM_VSCROLL:
1585 case OCM__BASE + WM_PARENTNOTIFY:
1586 case OCM__BASE + WM_NOTIFY:
1587 return TRUE;
1588 default:
1589 return FALSE;
1593 /***********************************************************************
1594 * MirrorIcon [COMCTL32.414]
1596 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1598 * PARAMS
1599 * phicon1 [I/O] Icon.
1600 * phicon2 [I/O] Icon.
1602 * RETURNS
1603 * Success: TRUE.
1604 * Failure: FALSE.
1606 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1608 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1609 return FALSE;
1612 static inline BOOL IsDelimiter(WCHAR c)
1614 switch(c)
1616 case '/':
1617 case '\\':
1618 case '.':
1619 case ' ':
1620 return TRUE;
1622 return FALSE;
1625 static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1627 if (code == WB_ISDELIMITER)
1628 return IsDelimiter(lpch[ichCurrent]);
1629 else
1631 int dir = (code == WB_LEFT) ? -1 : 1;
1632 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1633 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1635 return ichCurrent;
1638 /***********************************************************************
1639 * SetPathWordBreakProc [COMCTL32.384]
1641 * Sets the word break procedure for an edit control to one that understands
1642 * paths so that the user can jump over directories.
1644 * PARAMS
1645 * hwnd [I] Handle to edit control.
1646 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1648 * RETURNS
1649 * Result from EM_SETWORDBREAKPROC message.
1651 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1653 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1654 (LPARAM)(bSet ? PathWordBreakProc : NULL));
1657 /***********************************************************************
1658 * DrawShadowText [COMCTL32.@]
1660 * Draw text with shadow.
1662 int WINAPI DrawShadowText(HDC hdc, LPCWSTR text, UINT length, RECT *rect, DWORD flags,
1663 COLORREF crText, COLORREF crShadow, int offset_x, int offset_y)
1665 int bkmode, ret;
1666 COLORREF clr;
1667 RECT r;
1669 FIXME("%p, %s, %d, %p, %#lx, %#lx, %#lx, %d, %d: semi-stub\n", hdc, debugstr_w(text),
1670 length, rect, flags, crText, crShadow, offset_x, offset_y);
1672 bkmode = SetBkMode(hdc, TRANSPARENT);
1673 clr = SetTextColor(hdc, crShadow);
1675 /* FIXME: for shadow we need to render normally, blur it, and blend with current background. */
1676 r = *rect;
1677 OffsetRect(&r, 1, 1);
1678 DrawTextW(hdc, text, length, &r, flags);
1680 SetTextColor(hdc, crText);
1682 /* with text color on top of a shadow */
1683 ret = DrawTextW(hdc, text, length, rect, flags);
1685 SetTextColor(hdc, clr);
1686 SetBkMode(hdc, bkmode);
1688 return ret;
1691 /***********************************************************************
1692 * LoadIconWithScaleDown [COMCTL32.@]
1694 HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
1696 TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
1698 *icon = NULL;
1700 if (!name)
1701 return E_INVALIDARG;
1703 *icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
1704 (hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
1705 if (!*icon)
1706 return HRESULT_FROM_WIN32(GetLastError());
1708 return S_OK;
1711 /***********************************************************************
1712 * LoadIconMetric [COMCTL32.@]
1714 HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
1716 int cx, cy;
1718 TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
1720 if (size == LIM_SMALL)
1722 cx = GetSystemMetrics(SM_CXSMICON);
1723 cy = GetSystemMetrics(SM_CYSMICON);
1725 else if (size == LIM_LARGE)
1727 cx = GetSystemMetrics(SM_CXICON);
1728 cy = GetSystemMetrics(SM_CYICON);
1730 else
1732 *icon = NULL;
1733 return E_INVALIDARG;
1736 return LoadIconWithScaleDown(hinst, name, cx, cy, icon);
1739 static const WCHAR strMRUList[] = L"MRUList";
1741 /**************************************************************************
1742 * Alloc [COMCTL32.71]
1744 * Allocates memory block from the dll's private heap
1746 void * WINAPI Alloc(DWORD size)
1748 return LocalAlloc(LMEM_ZEROINIT, size);
1751 /**************************************************************************
1752 * ReAlloc [COMCTL32.72]
1754 * Changes the size of an allocated memory block or allocates a memory
1755 * block using the dll's private heap.
1758 void * WINAPI ReAlloc(void *src, DWORD size)
1760 if (src)
1761 return LocalReAlloc(src, size, LMEM_ZEROINIT | LMEM_MOVEABLE);
1762 else
1763 return LocalAlloc(LMEM_ZEROINIT, size);
1766 /**************************************************************************
1767 * Free [COMCTL32.73]
1769 * Frees an allocated memory block from the dll's private heap.
1771 BOOL WINAPI Free(void *mem)
1773 return !LocalFree(mem);
1776 /**************************************************************************
1777 * GetSize [COMCTL32.74]
1779 DWORD WINAPI GetSize(void *mem)
1781 return LocalSize(mem);
1784 /**************************************************************************
1785 * MRU-Functions {COMCTL32}
1787 * NOTES
1788 * The MRU-API is a set of functions to manipulate lists of M.R.U. (Most Recently
1789 * Used) items. It is an undocumented API that is used (at least) by the shell
1790 * and explorer to implement their recent documents feature.
1792 * Since these functions are undocumented, they are unsupported by MS and
1793 * may change at any time.
1795 * Internally, the list is implemented as a last in, last out list of items
1796 * persisted into the system registry under a caller chosen key. Each list
1797 * item is given a one character identifier in the Ascii range from 'a' to
1798 * '}'. A list of the identifiers in order from newest to oldest is stored
1799 * under the same key in a value named "MRUList".
1801 * Items are re-ordered by changing the order of the values in the MRUList
1802 * value. When a new item is added, it becomes the new value of the oldest
1803 * identifier, and that identifier is moved to the front of the MRUList value.
1805 * Wine stores MRU-lists in the same registry format as Windows, so when
1806 * switching between the builtin and native comctl32.dll no problems or
1807 * incompatibilities should occur.
1809 * The following undocumented structure is used to create an MRU-list:
1810 *|typedef INT (CALLBACK *MRUStringCmpFn)(LPCTSTR lhs, LPCTSTR rhs);
1811 *|typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
1813 *|typedef struct tagMRUINFO
1815 *| DWORD cbSize;
1816 *| UINT uMax;
1817 *| UINT fFlags;
1818 *| HKEY hKey;
1819 *| LPTSTR lpszSubKey;
1820 *| PROC lpfnCompare;
1821 *|} MRUINFO, *LPMRUINFO;
1823 * MEMBERS
1824 * cbSize [I] The size of the MRUINFO structure. This must be set
1825 * to sizeof(MRUINFO) by the caller.
1826 * uMax [I] The maximum number of items allowed in the list. Because
1827 * of the limited number of identifiers, this should be set to
1828 * a value from 1 to 30 by the caller.
1829 * fFlags [I] If bit 0 is set, the list will be used to store binary
1830 * data, otherwise it is assumed to store strings. If bit 1
1831 * is set, every change made to the list will be reflected in
1832 * the registry immediately, otherwise changes will only be
1833 * written when the list is closed.
1834 * hKey [I] The registry key that the list should be written under.
1835 * This must be supplied by the caller.
1836 * lpszSubKey [I] A caller supplied name of a subkey under hKey to write
1837 * the list to. This may not be blank.
1838 * lpfnCompare [I] A caller supplied comparison function, which may be either
1839 * an MRUStringCmpFn if dwFlags does not have bit 0 set, or a
1840 * MRUBinaryCmpFn otherwise.
1842 * FUNCTIONS
1843 * - Create an MRU-list with CreateMRUList() or CreateMRUListLazy().
1844 * - Add items to an MRU-list with AddMRUString() or AddMRUData().
1845 * - Remove items from an MRU-list with DelMRUString().
1846 * - Find data in an MRU-list with FindMRUString() or FindMRUData().
1847 * - Iterate through an MRU-list with EnumMRUList().
1848 * - Free an MRU-list with FreeMRUList().
1851 typedef INT (CALLBACK *MRUStringCmpFnA)(LPCSTR lhs, LPCSTR rhs);
1852 typedef INT (CALLBACK *MRUStringCmpFnW)(LPCWSTR lhs, LPCWSTR rhs);
1853 typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
1855 struct MRUINFOA
1857 DWORD cbSize;
1858 UINT uMax;
1859 UINT fFlags;
1860 HKEY hKey;
1861 LPSTR lpszSubKey;
1862 union
1864 MRUStringCmpFnA string_cmpfn;
1865 MRUBinaryCmpFn binary_cmpfn;
1866 } u;
1869 struct MRUINFOW
1871 DWORD cbSize;
1872 UINT uMax;
1873 UINT fFlags;
1874 HKEY hKey;
1875 LPWSTR lpszSubKey;
1876 union
1878 MRUStringCmpFnW string_cmpfn;
1879 MRUBinaryCmpFn binary_cmpfn;
1880 } u;
1883 /* MRUINFO.fFlags */
1884 #define MRU_STRING 0 /* list will contain strings */
1885 #define MRU_BINARY 1 /* list will contain binary data */
1886 #define MRU_CACHEWRITE 2 /* only save list order to reg. is FreeMRUList */
1888 /* If list is a string list lpfnCompare has the following prototype
1889 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
1890 * for binary lists the prototype is
1891 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
1892 * where cbData is the no. of bytes to compare.
1893 * Need to check what return value means identical - 0?
1896 typedef struct tagWINEMRUITEM
1898 DWORD size; /* size of data stored */
1899 DWORD itemFlag; /* flags */
1900 BYTE datastart;
1901 } WINEMRUITEM, *LPWINEMRUITEM;
1903 /* itemFlag */
1904 #define WMRUIF_CHANGED 0x0001 /* this dataitem changed */
1906 typedef struct tagWINEMRULIST
1908 struct MRUINFOW extview; /* original create information */
1909 BOOL isUnicode; /* is compare fn Unicode */
1910 DWORD wineFlags; /* internal flags */
1911 DWORD cursize; /* current size of realMRU */
1912 LPWSTR realMRU; /* pointer to string of index names */
1913 LPWINEMRUITEM *array; /* array of pointers to data */
1914 /* in 'a' to 'z' order */
1915 } WINEMRULIST, *LPWINEMRULIST;
1917 /* wineFlags */
1918 #define WMRUF_CHANGED 0x0001 /* MRU list has changed */
1920 /**************************************************************************
1921 * MRU_SaveChanged (internal)
1923 * Local MRU saving code
1925 static void MRU_SaveChanged(WINEMRULIST *mp)
1927 UINT i, err;
1928 HKEY newkey;
1929 WCHAR realname[2];
1930 WINEMRUITEM *witem;
1932 /* or should we do the following instead of RegOpenKeyEx:
1935 /* open the sub key */
1936 if ((err = RegOpenKeyExW(mp->extview.hKey, mp->extview.lpszSubKey, 0, KEY_WRITE, &newkey)))
1938 /* not present - what to do ??? */
1939 ERR("Could not open key, error=%d, attempting to create\n", err);
1940 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
1941 KEY_READ | KEY_WRITE, 0, &newkey, 0)))
1943 ERR("failed to create key /%s/, err=%d\n", debugstr_w(mp->extview.lpszSubKey), err);
1944 return;
1948 if (mp->wineFlags & WMRUF_CHANGED)
1950 mp->wineFlags &= ~WMRUF_CHANGED;
1951 if ((err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (BYTE *)mp->realMRU,
1952 (lstrlenW(mp->realMRU) + 1)*sizeof(WCHAR))))
1954 ERR("error saving MRUList, err=%d\n", err);
1956 TRACE("saving MRUList=/%s/\n", debugstr_w(mp->realMRU));
1959 realname[1] = 0;
1960 for (i = 0; i < mp->cursize; ++i)
1962 witem = mp->array[i];
1963 if (witem->itemFlag & WMRUIF_CHANGED)
1965 witem->itemFlag &= ~WMRUIF_CHANGED;
1966 realname[0] = 'a' + i;
1967 if ((err = RegSetValueExW(newkey, realname, 0, (mp->extview.fFlags & MRU_BINARY) ?
1968 REG_BINARY : REG_SZ, &witem->datastart, witem->size)))
1970 ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err);
1972 TRACE("saving value for name /%s/ size %ld\n", debugstr_w(realname), witem->size);
1975 RegCloseKey(newkey);
1978 /**************************************************************************
1979 * FreeMRUList [COMCTL32.152]
1981 * Frees a most-recently-used items list.
1983 void WINAPI FreeMRUList(HANDLE hMRUList)
1985 WINEMRULIST *mp = hMRUList;
1986 unsigned int i;
1988 TRACE("%p.\n", hMRUList);
1990 if (!hMRUList)
1991 return;
1993 if (mp->wineFlags & WMRUF_CHANGED)
1995 /* need to open key and then save the info */
1996 MRU_SaveChanged(mp);
1999 for (i = 0; i < mp->extview.uMax; ++i)
2000 Free(mp->array[i]);
2002 Free(mp->realMRU);
2003 Free(mp->array);
2004 Free(mp->extview.lpszSubKey);
2005 Free(mp);
2008 /**************************************************************************
2009 * FindMRUData [COMCTL32.169]
2011 * Searches binary list for item that matches data of given length.
2012 * Returns position in list order 0 -> MRU and value corresponding to item's reg.
2013 * name will be stored in it ('a' -> 0).
2016 INT WINAPI FindMRUData(HANDLE hList, const void *data, DWORD cbData, int *pos)
2018 const WINEMRULIST *mp = hList;
2019 INT ret;
2020 UINT i;
2021 LPSTR dataA = NULL;
2023 if (!mp || !mp->extview.u.string_cmpfn)
2024 return -1;
2026 if (!(mp->extview.fFlags & MRU_BINARY) && !mp->isUnicode)
2028 DWORD len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
2029 dataA = Alloc(len);
2030 WideCharToMultiByte(CP_ACP, 0, data, -1, dataA, len, NULL, NULL);
2033 for (i = 0; i < mp->cursize; ++i)
2035 if (mp->extview.fFlags & MRU_BINARY)
2037 if (!mp->extview.u.binary_cmpfn(data, &mp->array[i]->datastart, cbData))
2038 break;
2040 else
2042 if (mp->isUnicode)
2044 if (!mp->extview.u.string_cmpfn(data, (LPWSTR)&mp->array[i]->datastart))
2045 break;
2047 else
2049 DWORD len = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
2050 NULL, 0, NULL, NULL);
2051 LPSTR itemA = Alloc(len);
2052 INT cmp;
2053 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1, itemA, len, NULL, NULL);
2055 cmp = mp->extview.u.string_cmpfn((LPWSTR)dataA, (LPWSTR)itemA);
2056 Free(itemA);
2057 if (!cmp)
2058 break;
2063 Free(dataA);
2064 if (i < mp->cursize)
2065 ret = i;
2066 else
2067 ret = -1;
2068 if (pos && (ret != -1))
2069 *pos = 'a' + i;
2071 TRACE("%p, %p, %ld, %p, returning %d.\n", hList, data, cbData, pos, ret);
2073 return ret;
2076 /**************************************************************************
2077 * AddMRUData [COMCTL32.167]
2079 * Add item to MRU binary list. If item already exists in list then it is
2080 * simply moved up to the top of the list and not added again. If list is
2081 * full then the least recently used item is removed to make room.
2084 INT WINAPI AddMRUData(HANDLE hList, const void *data, DWORD cbData)
2086 WINEMRULIST *mp = hList;
2087 WINEMRUITEM *witem;
2088 INT i, replace;
2090 if ((replace = FindMRUData(hList, data, cbData, NULL)) >= 0)
2092 /* Item exists, just move it to the front */
2093 LPWSTR pos = wcschr(mp->realMRU, replace + 'a');
2094 while (pos > mp->realMRU)
2096 pos[0] = pos[-1];
2097 pos--;
2100 else
2102 /* either add a new entry or replace oldest */
2103 if (mp->cursize < mp->extview.uMax)
2105 /* Add in a new item */
2106 replace = mp->cursize;
2107 mp->cursize++;
2109 else
2111 /* get the oldest entry and replace data */
2112 replace = mp->realMRU[mp->cursize - 1] - 'a';
2113 Free(mp->array[replace]);
2116 /* Allocate space for new item and move in the data */
2117 mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM));
2118 witem->itemFlag |= WMRUIF_CHANGED;
2119 witem->size = cbData;
2120 memcpy( &witem->datastart, data, cbData);
2122 /* now rotate MRU list */
2123 for (i = mp->cursize - 1; i >= 1; --i)
2124 mp->realMRU[i] = mp->realMRU[i-1];
2127 /* The new item gets the front spot */
2128 mp->wineFlags |= WMRUF_CHANGED;
2129 mp->realMRU[0] = replace + 'a';
2131 TRACE("%p, %p, %ld adding data, /%c/ now most current\n", hList, data, cbData, replace+'a');
2133 if (!(mp->extview.fFlags & MRU_CACHEWRITE))
2135 /* save changed stuff right now */
2136 MRU_SaveChanged(mp);
2139 return replace;
2142 /**************************************************************************
2143 * AddMRUStringW [COMCTL32.401]
2145 * Add an item to an MRU string list.
2148 INT WINAPI AddMRUStringW(HANDLE hList, const WCHAR *str)
2150 TRACE("%p, %s.\n", hList, debugstr_w(str));
2152 if (!hList)
2153 return -1;
2155 if (!str || IsBadStringPtrW(str, -1))
2157 SetLastError(ERROR_INVALID_PARAMETER);
2158 return 0;
2161 return AddMRUData(hList, str, (lstrlenW(str) + 1) * sizeof(WCHAR));
2164 /**************************************************************************
2165 * AddMRUStringA [COMCTL32.153]
2167 INT WINAPI AddMRUStringA(HANDLE hList, const char *str)
2169 WCHAR *strW;
2170 DWORD len;
2171 INT ret;
2173 TRACE("%p, %s.\n", hList, debugstr_a(str));
2175 if (!hList)
2176 return -1;
2178 if (IsBadStringPtrA(str, -1))
2180 SetLastError(ERROR_INVALID_PARAMETER);
2181 return 0;
2184 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0) * sizeof(WCHAR);
2185 strW = Alloc(len);
2186 if (!strW)
2187 return -1;
2189 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len/sizeof(WCHAR));
2190 ret = AddMRUData(hList, strW, len);
2191 Free(strW);
2192 return ret;
2195 /**************************************************************************
2196 * DelMRUString [COMCTL32.156]
2198 * Removes item from either string or binary list (despite its name)
2200 * PARAMS
2201 * hList [I] list handle
2202 * nItemPos [I] item position to remove 0 -> MRU
2204 * RETURNS
2205 * TRUE if successful, FALSE if nItemPos is out of range.
2207 BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos)
2209 FIXME("(%p, %d): stub\n", hList, nItemPos);
2210 return TRUE;
2213 /**************************************************************************
2214 * FindMRUStringW [COMCTL32.402]
2216 INT WINAPI FindMRUStringW(HANDLE hList, const WCHAR *str, int *pos)
2218 return FindMRUData(hList, str, (lstrlenW(str) + 1) * sizeof(WCHAR), pos);
2221 /**************************************************************************
2222 * FindMRUStringA [COMCTL32.155]
2224 * Searches string list for item that matches given string.
2226 * RETURNS
2227 * Position in list 0 -> MRU. -1 if item not found.
2229 INT WINAPI FindMRUStringA(HANDLE hList, const char *str, int *pos)
2231 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
2232 WCHAR *strW = Alloc(len * sizeof(*strW));
2233 INT ret;
2235 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
2236 ret = FindMRUData(hList, strW, len * sizeof(WCHAR), pos);
2237 Free(strW);
2238 return ret;
2241 /*************************************************************************
2242 * create_mru_list (internal)
2244 static HANDLE create_mru_list(WINEMRULIST *mp)
2246 UINT i, err;
2247 HKEY newkey;
2248 DWORD datasize, dwdisp;
2249 WCHAR realname[2];
2250 WINEMRUITEM *witem;
2251 DWORD type;
2253 /* get space to save indices that will turn into names
2254 * but in order of most to least recently used
2256 mp->realMRU = Alloc((mp->extview.uMax + 2) * sizeof(WCHAR));
2258 /* get space to save pointers to actual data in order of
2259 * 'a' to 'z' (0 to n).
2261 mp->array = Alloc(mp->extview.uMax * sizeof(LPVOID));
2263 /* open the sub key */
2264 if ((err = RegCreateKeyExW(mp->extview.hKey, mp->extview.lpszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
2265 KEY_READ | KEY_WRITE, 0, &newkey, &dwdisp)))
2267 /* error - what to do ??? */
2268 ERR("%lu, %u, %x, %p, %s, %p: Could not open key, error=%d\n", mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
2269 mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.u.string_cmpfn, err);
2270 return 0;
2273 /* get values from key 'MRUList' */
2274 if (newkey)
2276 datasize = (mp->extview.uMax + 1) * sizeof(WCHAR);
2277 if (RegQueryValueExW( newkey, strMRUList, 0, &type, (BYTE *)mp->realMRU, &datasize))
2279 /* not present - set size to 1 (will become 0 later) */
2280 datasize = 1;
2281 *mp->realMRU = 0;
2283 else
2284 datasize /= sizeof(WCHAR);
2286 TRACE("MRU list = %s, datasize = %ld\n", debugstr_w(mp->realMRU), datasize);
2288 mp->cursize = datasize - 1;
2289 /* datasize now has number of items in the MRUList */
2291 /* get actual values for each entry */
2292 realname[1] = 0;
2293 for (i = 0; i < mp->cursize; ++i)
2295 realname[0] = 'a' + i;
2296 if (RegQueryValueExW(newkey, realname, 0, &type, 0, &datasize))
2298 /* not present - what to do ??? */
2299 ERR("Key %s not found 1\n", debugstr_w(realname));
2301 mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM));
2302 witem->size = datasize;
2303 if (RegQueryValueExW(newkey, realname, 0, &type, &witem->datastart, &datasize))
2305 /* not present - what to do ??? */
2306 ERR("Key %s not found 2\n", debugstr_w(realname));
2309 RegCloseKey( newkey );
2311 else
2312 mp->cursize = 0;
2314 TRACE("%lu, %u, %x, %p, %s, %p: Current Size = %ld\n", mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
2315 mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.u.string_cmpfn, mp->cursize);
2316 return mp;
2319 /**************************************************************************
2320 * CreateMRUListLazyW [COMCTL32.404]
2322 HANDLE WINAPI CreateMRUListLazyW(const struct MRUINFOW *info, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
2324 WINEMRULIST *mp;
2326 /* Native does not check for a NULL. */
2327 if (!info->hKey || IsBadStringPtrW(info->lpszSubKey, -1))
2328 return NULL;
2330 mp = Alloc(sizeof(*mp));
2331 memcpy(&mp->extview, info, sizeof(*info));
2332 mp->extview.lpszSubKey = Alloc((lstrlenW(info->lpszSubKey) + 1) * sizeof(WCHAR));
2333 lstrcpyW(mp->extview.lpszSubKey, info->lpszSubKey);
2334 mp->isUnicode = TRUE;
2336 return create_mru_list(mp);
2339 /**************************************************************************
2340 * CreateMRUListLazyA [COMCTL32.157]
2342 * Creates a most-recently-used list.
2344 HANDLE WINAPI CreateMRUListLazyA(const struct MRUINFOA *info, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
2346 WINEMRULIST *mp;
2347 DWORD len;
2349 /* Native does not check for a NULL lpcml */
2351 if (!info->hKey || IsBadStringPtrA(info->lpszSubKey, -1))
2352 return 0;
2354 mp = Alloc(sizeof(*mp));
2355 memcpy(&mp->extview, info, sizeof(*info));
2356 len = MultiByteToWideChar(CP_ACP, 0, info->lpszSubKey, -1, NULL, 0);
2357 mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR));
2358 MultiByteToWideChar(CP_ACP, 0, info->lpszSubKey, -1, mp->extview.lpszSubKey, len);
2359 mp->isUnicode = FALSE;
2360 return create_mru_list(mp);
2363 /**************************************************************************
2364 * CreateMRUListW [COMCTL32.400]
2366 HANDLE WINAPI CreateMRUListW(const struct MRUINFOW *info)
2368 return CreateMRUListLazyW(info, 0, 0, 0);
2371 /**************************************************************************
2372 * CreateMRUListA [COMCTL32.151]
2374 HANDLE WINAPI CreateMRUListA(const struct MRUINFOA *info)
2376 return CreateMRUListLazyA(info, 0, 0, 0);
2379 /**************************************************************************
2380 * EnumMRUListW [COMCTL32.403]
2382 * Enumerate item in a most-recently-used list
2384 * PARAMS
2385 * hList [I] list handle
2386 * nItemPos [I] item position to enumerate
2387 * lpBuffer [O] buffer to receive item
2388 * nBufferSize [I] size of buffer
2390 * RETURNS
2391 * For binary lists specifies how many bytes were copied to buffer, for
2392 * string lists specifies full length of string. Enumerating past the end
2393 * of list returns -1.
2394 * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
2395 * the list.
2397 INT WINAPI EnumMRUListW(HANDLE hList, INT nItemPos, void *buffer, DWORD nBufferSize)
2399 const WINEMRULIST *mp = hList;
2400 const WINEMRUITEM *witem;
2401 INT desired, datasize;
2403 if (!mp) return -1;
2404 if ((nItemPos < 0) || !buffer) return mp->cursize;
2405 if (nItemPos >= mp->cursize) return -1;
2406 desired = mp->realMRU[nItemPos];
2407 desired -= 'a';
2408 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
2409 witem = mp->array[desired];
2410 datasize = min(witem->size, nBufferSize);
2411 memcpy(buffer, &witem->datastart, datasize);
2412 TRACE("(%p, %d, %p, %ld): returning len %d\n", hList, nItemPos, buffer, nBufferSize, datasize);
2413 return datasize;
2416 /**************************************************************************
2417 * EnumMRUListA [COMCTL32.154]
2419 INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, void *buffer, DWORD nBufferSize)
2421 const WINEMRULIST *mp = hList;
2422 WINEMRUITEM *witem;
2423 INT desired, datasize;
2424 DWORD lenA;
2426 if (!mp) return -1;
2427 if ((nItemPos < 0) || !buffer) return mp->cursize;
2428 if (nItemPos >= mp->cursize) return -1;
2429 desired = mp->realMRU[nItemPos];
2430 desired -= 'a';
2431 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
2432 witem = mp->array[desired];
2433 if (mp->extview.fFlags & MRU_BINARY)
2435 datasize = min(witem->size, nBufferSize);
2436 memcpy(buffer, &witem->datastart, datasize);
2438 else
2440 lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, NULL, 0, NULL, NULL);
2441 datasize = min(lenA, nBufferSize);
2442 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, buffer, datasize, NULL, NULL);
2443 ((char *)buffer)[ datasize - 1 ] = '\0';
2444 datasize = lenA - 1;
2446 TRACE("(%p, %d, %p, %ld): returning len=%d\n", hList, nItemPos, buffer, nBufferSize, datasize);
2447 return datasize;
2450 /**************************************************************************
2451 * Str_GetPtrWtoA [internal]
2453 * Converts a unicode string into a multi byte string
2457 INT Str_GetPtrWtoA(const WCHAR *src, char *dst, INT nMaxLen)
2459 INT len;
2461 TRACE("%s, %p, %d.\n", debugstr_w(src), dst, nMaxLen);
2463 if (!dst && src)
2464 return WideCharToMultiByte(CP_ACP, 0, src, -1, 0, 0, NULL, NULL);
2466 if (!nMaxLen)
2467 return 0;
2469 if (!src)
2471 dst[0] = 0;
2472 return 0;
2475 len = WideCharToMultiByte(CP_ACP, 0, src, -1, 0, 0, NULL, NULL);
2476 if (len >= nMaxLen)
2477 len = nMaxLen - 1;
2479 WideCharToMultiByte(CP_ACP, 0, src, -1, dst, len, NULL, NULL);
2480 dst[len] = '\0';
2482 return len;
2485 /**************************************************************************
2486 * Str_GetPtrAtoW [internal]
2488 * Converts a multibyte string into a unicode string
2491 INT Str_GetPtrAtoW(const char *src, WCHAR *dst, INT nMaxLen)
2493 INT len;
2495 TRACE("%s, %p, %d.\n", debugstr_a(src), dst, nMaxLen);
2497 if (!dst && src)
2498 return MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
2500 if (!nMaxLen)
2501 return 0;
2503 if (!src)
2505 *dst = 0;
2506 return 0;
2509 len = MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
2510 if (len >= nMaxLen)
2511 len = nMaxLen - 1;
2513 MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
2514 dst[len] = 0;
2516 return len;
2519 /**************************************************************************
2520 * Str_SetPtrAtoW [internal]
2522 * Converts a multi byte string to a unicode string.
2523 * If the pointer to the destination buffer is NULL a buffer is allocated.
2524 * If the destination buffer is too small to keep the converted multi byte
2525 * string the destination buffer is reallocated. If the source pointer is
2527 BOOL Str_SetPtrAtoW(WCHAR **dst, const char *src)
2529 TRACE("%p, %s.\n", dst, debugstr_a(src));
2531 if (src)
2533 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
2534 LPWSTR ptr = ReAlloc(*dst, len * sizeof(**dst));
2536 if (!ptr)
2537 return FALSE;
2538 MultiByteToWideChar(CP_ACP, 0, src, -1, ptr, len);
2539 *dst = ptr;
2541 else
2543 Free(*dst);
2544 *dst = NULL;
2547 return TRUE;
2550 /**************************************************************************
2551 * Str_SetPtrWtoA [internal]
2553 * Converts a unicode string to a multi byte string.
2554 * If the pointer to the destination buffer is NULL a buffer is allocated.
2555 * If the destination buffer is too small to keep the converted wide
2556 * string the destination buffer is reallocated. If the source pointer is
2557 * NULL, the destination buffer is freed.
2559 BOOL Str_SetPtrWtoA(char **dst, const WCHAR *src)
2561 TRACE("%p, %s.\n", dst, debugstr_w(src));
2563 if (src)
2565 INT len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, FALSE);
2566 LPSTR ptr = ReAlloc(*dst, len * sizeof(**dst));
2568 if (!ptr)
2569 return FALSE;
2570 WideCharToMultiByte(CP_ACP, 0, src, -1, ptr, len, NULL, FALSE);
2571 *dst = ptr;
2573 else
2575 Free(*dst);
2576 *dst = NULL;
2579 return TRUE;
2582 /**************************************************************************
2583 * Notification functions
2586 struct NOTIFYDATA
2588 HWND hwndFrom;
2589 HWND hwndTo;
2590 DWORD dwParam3;
2591 DWORD dwParam4;
2592 DWORD dwParam5;
2593 DWORD dwParam6;
2596 /**************************************************************************
2597 * DoNotify [Internal]
2600 static LRESULT DoNotify(const struct NOTIFYDATA *notify, UINT code, NMHDR *hdr)
2602 NMHDR nmhdr;
2603 NMHDR *lpNmh = NULL;
2604 UINT idFrom = 0;
2606 TRACE("%p, %p, %d, %p, %#lx.\n", notify->hwndFrom, notify->hwndTo, code, hdr, notify->dwParam5);
2608 if (!notify->hwndTo)
2609 return 0;
2611 if (notify->hwndFrom == (HWND)-1)
2613 lpNmh = hdr;
2614 idFrom = hdr->idFrom;
2616 else
2618 if (notify->hwndFrom)
2619 idFrom = GetDlgCtrlID(notify->hwndFrom);
2621 lpNmh = hdr ? hdr : &nmhdr;
2622 lpNmh->hwndFrom = notify->hwndFrom;
2623 lpNmh->idFrom = idFrom;
2624 lpNmh->code = code;
2627 return SendMessageW(notify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
2630 /**************************************************************************
2631 * SendNotify [COMCTL32.341]
2633 * Sends a WM_NOTIFY message to the specified window.
2636 LRESULT WINAPI SendNotify(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr)
2638 struct NOTIFYDATA notify;
2640 TRACE("%p, %p, %d, %p.\n", hwndTo, hwndFrom, code, hdr);
2642 notify.hwndFrom = hwndFrom;
2643 notify.hwndTo = hwndTo;
2644 notify.dwParam5 = 0;
2645 notify.dwParam6 = 0;
2647 return DoNotify(&notify, code, hdr);
2650 /**************************************************************************
2651 * SendNotifyEx [COMCTL32.342]
2653 * Sends a WM_NOTIFY message to the specified window.
2655 * PARAMS
2656 * hwndFrom [I] Window to receive the message
2657 * hwndTo [I] Window that the message is from
2658 * code [I] Notification code
2659 * hdr [I] The NMHDR and any additional information to send or NULL
2660 * dwParam5 [I] Unknown
2662 * RETURNS
2663 * Success: return value from notification
2664 * Failure: 0
2666 * NOTES
2667 * If hwndFrom is -1 then the identifier of the control sending the
2668 * message is taken from the NMHDR structure.
2669 * If hwndFrom is not -1 then lpHdr can be NULL.
2671 LRESULT WINAPI SendNotifyEx(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr, DWORD dwParam5)
2673 struct NOTIFYDATA notify;
2674 HWND hwndNotify;
2676 TRACE("%p, %p, %d, %p, %#lx\n", hwndFrom, hwndTo, code, hdr, dwParam5);
2678 hwndNotify = hwndTo;
2679 if (!hwndTo)
2681 if (IsWindow(hwndFrom))
2683 hwndNotify = GetParent(hwndFrom);
2684 if (!hwndNotify)
2685 return 0;
2689 notify.hwndFrom = hwndFrom;
2690 notify.hwndTo = hwndNotify;
2691 notify.dwParam5 = dwParam5;
2692 notify.dwParam6 = 0;
2694 return DoNotify(&notify, code, hdr);