include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / comctl32 / commctrl.c
blobd87e63e813ee16b19dfb46d352879d03a3e49584
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 #include "windef.h"
63 #include "winbase.h"
64 #include "wingdi.h"
65 #include "winuser.h"
66 #include "winnls.h"
67 #include "commctrl.h"
68 #include "winerror.h"
69 #include "winreg.h"
70 #define NO_SHLWAPI_STREAM
71 #include "shlwapi.h"
72 #include "comctl32.h"
73 #include "uxtheme.h"
74 #include "wine/debug.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
79 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
81 static LPWSTR COMCTL32_wSubclass = NULL;
82 HMODULE COMCTL32_hModule = 0;
83 static LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
84 HBRUSH COMCTL32_hPattern55AABrush = NULL;
85 COMCTL32_SysColor comctl32_color;
87 static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
89 static const WORD wPattern55AA[] =
91 0x5555, 0xaaaa, 0x5555, 0xaaaa,
92 0x5555, 0xaaaa, 0x5555, 0xaaaa
95 static const WCHAR strCC32SubclassInfo[] = L"CC32SubclassInfo";
97 static void unregister_versioned_classes(void)
99 #define VERSION "6.0.2600.2982!"
100 static const char *classes[] =
102 VERSION WC_BUTTONA,
103 VERSION WC_COMBOBOXA,
104 VERSION "ComboLBox",
105 VERSION WC_EDITA,
106 VERSION WC_LISTBOXA,
107 VERSION WC_STATICA,
109 int i;
111 for (i = 0; i < ARRAY_SIZE(classes); i++)
112 UnregisterClassA(classes[i], NULL);
114 #undef VERSION
117 BOOL WINAPI RegisterClassNameW(const WCHAR *class)
119 static const struct
121 const WCHAR nameW[16];
122 void (*fn_register)(void);
124 classes[] =
126 { L"Button", BUTTON_Register },
127 { L"ComboBox", COMBO_Register },
128 { L"ComboLBox", COMBOLBOX_Register },
129 { L"Edit", EDIT_Register },
130 { L"ListBox", LISTBOX_Register },
131 { L"Static", STATIC_Register },
134 int min = 0, max = ARRAY_SIZE(classes) - 1;
136 while (min <= max)
138 int res, pos = (min + max) / 2;
139 if (!(res = wcsicmp(class, classes[pos].nameW)))
141 classes[pos].fn_register();
142 return TRUE;
144 if (res < 0) max = pos - 1;
145 else min = pos + 1;
148 return FALSE;
151 /***********************************************************************
152 * DllMain [Internal]
154 * Initializes the internal 'COMCTL32.DLL'.
156 * PARAMS
157 * hinstDLL [I] handle to the 'dlls' instance
158 * fdwReason [I]
159 * lpvReserved [I] reserved, must be NULL
161 * RETURNS
162 * Success: TRUE
163 * Failure: FALSE
166 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
168 TRACE("%p, %#lx, %p\n", hinstDLL, fdwReason, lpvReserved);
170 switch (fdwReason) {
171 case DLL_PROCESS_ATTACH:
172 DisableThreadLibraryCalls(hinstDLL);
174 COMCTL32_hModule = hinstDLL;
176 /* add global subclassing atom (used by 'tooltip' and 'updown') */
177 COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
178 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
180 /* create local pattern brush */
181 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
182 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
184 /* Get all the colors at DLL load */
185 COMCTL32_RefreshSysColors();
187 /* like comctl32 5.82+ register all the common control classes */
188 ANIMATE_Register ();
189 COMBOEX_Register ();
190 DATETIME_Register ();
191 FLATSB_Register ();
192 HEADER_Register ();
193 HOTKEY_Register ();
194 IPADDRESS_Register ();
195 LISTVIEW_Register ();
196 MONTHCAL_Register ();
197 NATIVEFONT_Register ();
198 PAGER_Register ();
199 PROGRESS_Register ();
200 REBAR_Register ();
201 STATUS_Register ();
202 SYSLINK_Register ();
203 TAB_Register ();
204 TOOLBAR_Register ();
205 TOOLTIPS_Register ();
206 TRACKBAR_Register ();
207 TREEVIEW_Register ();
208 UPDOWN_Register ();
209 break;
211 case DLL_PROCESS_DETACH:
212 if (lpvReserved) break;
214 /* unregister all common control classes */
215 ANIMATE_Unregister ();
216 COMBOEX_Unregister ();
217 DATETIME_Unregister ();
218 FLATSB_Unregister ();
219 HEADER_Unregister ();
220 HOTKEY_Unregister ();
221 IPADDRESS_Unregister ();
222 LISTVIEW_Unregister ();
223 MONTHCAL_Unregister ();
224 NATIVEFONT_Unregister ();
225 PAGER_Unregister ();
226 PROGRESS_Unregister ();
227 REBAR_Unregister ();
228 STATUS_Unregister ();
229 SYSLINK_Unregister ();
230 TAB_Unregister ();
231 TOOLBAR_Unregister ();
232 TOOLTIPS_Unregister ();
233 TRACKBAR_Unregister ();
234 TREEVIEW_Unregister ();
235 UPDOWN_Unregister ();
237 unregister_versioned_classes ();
239 /* delete local pattern brush */
240 DeleteObject (COMCTL32_hPattern55AABrush);
241 DeleteObject (COMCTL32_hPattern55AABitmap);
243 /* delete global subclassing atom */
244 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
245 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
246 break;
249 return TRUE;
253 /***********************************************************************
254 * MenuHelp [COMCTL32.2]
256 * Handles the setting of status bar help messages when the user
257 * selects menu items.
259 * PARAMS
260 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
261 * wParam [I] wParam of the message uMsg
262 * lParam [I] lParam of the message uMsg
263 * hMainMenu [I] handle to the application's main menu
264 * hInst [I] handle to the module that contains string resources
265 * hwndStatus [I] handle to the status bar window
266 * lpwIDs [I] pointer to an array of integers (see NOTES)
268 * RETURNS
269 * No return value
271 * NOTES
272 * The official documentation is incomplete!
273 * This is the correct documentation:
275 * uMsg:
276 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
277 * WM_MENUSELECT messages.
279 * lpwIDs:
280 * (will be written ...)
283 VOID WINAPI
284 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
285 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
287 UINT uMenuID = 0;
289 if (!IsWindow (hwndStatus))
290 return;
292 switch (uMsg) {
293 case WM_MENUSELECT:
294 TRACE("WM_MENUSELECT wParam %#Ix, lParam %#Ix\n", wParam, lParam);
296 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
297 /* menu was closed */
298 TRACE("menu was closed!\n");
299 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
301 else {
302 /* menu item was selected */
303 if (HIWORD(wParam) & MF_POPUP)
304 uMenuID = *(lpwIDs+1);
305 else
306 uMenuID = (UINT)LOWORD(wParam);
307 TRACE("uMenuID = %u\n", uMenuID);
309 if (uMenuID) {
310 WCHAR szText[256];
312 if (!LoadStringW (hInst, uMenuID, szText, ARRAY_SIZE(szText)))
313 szText[0] = '\0';
315 SendMessageW (hwndStatus, SB_SETTEXTW,
316 255 | SBT_NOBORDERS, (LPARAM)szText);
317 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
320 break;
322 case WM_COMMAND :
323 TRACE("WM_COMMAND wParam %#Ix, lParam %#Ix\n", wParam, lParam);
324 /* WM_COMMAND is not invalid since it is documented
325 * in the windows api reference. So don't output
326 * any FIXME for WM_COMMAND
328 WARN("We don't care about the WM_COMMAND\n");
329 break;
331 default:
332 FIXME("Invalid Message 0x%x!\n", uMsg);
333 break;
338 /***********************************************************************
339 * ShowHideMenuCtl [COMCTL32.3]
341 * Shows or hides controls and updates the corresponding menu item.
343 * PARAMS
344 * hwnd [I] handle to the client window.
345 * uFlags [I] menu command id.
346 * lpInfo [I] pointer to an array of integers. (See NOTES.)
348 * RETURNS
349 * Success: TRUE
350 * Failure: FALSE
352 * NOTES
353 * The official documentation is incomplete!
354 * This is the correct documentation:
356 * hwnd
357 * Handle to the window that contains the menu and controls.
359 * uFlags
360 * Identifier of the menu item to receive or lose a check mark.
362 * lpInfo
363 * The array of integers contains pairs of values. BOTH values of
364 * the first pair must be the handles to the application's main menu.
365 * Each subsequent pair consists of a menu id and control id.
368 BOOL WINAPI
369 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
371 LPINT lpMenuId;
373 TRACE("%p, %Ix, %p\n", hwnd, uFlags, lpInfo);
375 if (lpInfo == NULL)
376 return FALSE;
378 if (!(lpInfo[0]) || !(lpInfo[1]))
379 return FALSE;
381 /* search for control */
382 lpMenuId = &lpInfo[2];
383 while (*lpMenuId != uFlags)
384 lpMenuId += 2;
386 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
387 /* uncheck menu item */
388 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
390 /* hide control */
391 lpMenuId++;
392 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
393 SWP_HIDEWINDOW);
395 else {
396 /* check menu item */
397 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
399 /* show control */
400 lpMenuId++;
401 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
402 SWP_SHOWWINDOW);
405 return TRUE;
409 /***********************************************************************
410 * GetEffectiveClientRect [COMCTL32.4]
412 * Calculates the coordinates of a rectangle in the client area.
414 * PARAMS
415 * hwnd [I] handle to the client window.
416 * lpRect [O] pointer to the rectangle of the client window
417 * lpInfo [I] pointer to an array of integers (see NOTES)
419 * RETURNS
420 * No return value.
422 * NOTES
423 * The official documentation is incomplete!
424 * This is the correct documentation:
426 * lpInfo
427 * (will be written ...)
430 VOID WINAPI
431 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
433 RECT rcCtrl;
434 const INT *lpRun;
435 HWND hwndCtrl;
437 TRACE("(%p %p %p)\n",
438 hwnd, lpRect, lpInfo);
440 GetClientRect (hwnd, lpRect);
441 lpRun = lpInfo;
443 do {
444 lpRun += 2;
445 if (*lpRun == 0)
446 return;
447 lpRun++;
448 hwndCtrl = GetDlgItem (hwnd, *lpRun);
449 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
450 TRACE("control id 0x%x\n", *lpRun);
451 GetWindowRect (hwndCtrl, &rcCtrl);
452 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
453 SubtractRect (lpRect, lpRect, &rcCtrl);
455 lpRun++;
456 } while (*lpRun);
459 void COMCTL32_DrawStatusText(HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style, BOOL draw_background)
461 RECT r = *lprc;
462 UINT border;
463 COLORREF oldbkcolor;
465 if (draw_background)
467 if (style & SBT_POPOUT)
468 border = BDR_RAISEDOUTER;
469 else if (style & SBT_NOBORDERS)
470 border = 0;
471 else
472 border = BDR_SUNKENOUTER;
474 oldbkcolor = SetBkColor (hdc, comctl32_color.clrBtnFace);
475 DrawEdge (hdc, &r, border, BF_MIDDLE|BF_RECT|BF_ADJUST);
476 SetBkColor (hdc, oldbkcolor);
479 /* now draw text */
480 if (text) {
481 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
482 COLORREF oldtextcolor;
483 UINT align = DT_LEFT;
484 int strCnt = 0;
486 oldtextcolor = SetTextColor (hdc, comctl32_color.clrBtnText);
487 if (style & SBT_RTLREADING)
488 FIXME("Unsupported RTL style!\n");
489 r.left += 3;
490 do {
491 if (*text == '\t') {
492 if (strCnt) {
493 DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
494 strCnt = 0;
496 if (align==DT_RIGHT) {
497 break;
499 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
500 } else {
501 strCnt++;
503 } while(*text++);
505 if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
506 SetBkMode (hdc, oldbkmode);
507 SetTextColor (hdc, oldtextcolor);
511 /***********************************************************************
512 * DrawStatusTextW [COMCTL32.@]
514 * Draws text with borders, like in a status bar.
516 * PARAMS
517 * hdc [I] handle to the window's display context
518 * lprc [I] pointer to a rectangle
519 * text [I] pointer to the text
520 * style [I] drawing style
522 * RETURNS
523 * No return value.
525 * NOTES
526 * The style variable can have one of the following values:
527 * (will be written ...)
530 void WINAPI DrawStatusTextW(HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
532 COMCTL32_DrawStatusText(hdc, lprc, text, style, TRUE);
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("%#lx\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("%lu.%lu.%lu.%lu\n", pdvi->dwMajorVersion, pdvi->dwMinorVersion,
977 pdvi->dwBuildNumber, pdvi->dwPlatformID);
979 return S_OK;
982 /***********************************************************************
983 * DllInstall (COMCTL32.@)
985 * Installs the ComCtl32 DLL.
987 * RETURNS
988 * Success: S_OK
989 * Failure: A HRESULT error
991 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
993 TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
994 return S_OK;
997 /***********************************************************************
998 * _TrackMouseEvent [COMCTL32.@]
1000 * Requests notification of mouse events
1002 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1003 * to the hwnd specified in the ptme structure. After the event message
1004 * is posted to the hwnd, the entry in the queue is removed.
1006 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1007 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1008 * immediately and the TME_LEAVE flag being ignored.
1010 * PARAMS
1011 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1013 * RETURNS
1014 * Success: non-zero
1015 * Failure: zero
1017 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1021 BOOL WINAPI
1022 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1024 return TrackMouseEvent (ptme);
1027 /*************************************************************************
1028 * GetMUILanguage [COMCTL32.@]
1030 * Returns the user interface language in use by the current process.
1032 * RETURNS
1033 * Language ID in use by the current process.
1035 LANGID WINAPI GetMUILanguage (VOID)
1037 return COMCTL32_uiLang;
1041 /*************************************************************************
1042 * InitMUILanguage [COMCTL32.@]
1044 * Sets the user interface language to be used by the current process.
1046 * RETURNS
1047 * Nothing.
1049 VOID WINAPI InitMUILanguage (LANGID uiLang)
1051 COMCTL32_uiLang = uiLang;
1055 /***********************************************************************
1056 * SetWindowSubclass [COMCTL32.410]
1058 * Starts a window subclass
1060 * PARAMS
1061 * hWnd [in] handle to window subclass.
1062 * pfnSubclass [in] Pointer to new window procedure.
1063 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1064 * dwRef [in] Reference data to pass to window procedure.
1066 * RETURNS
1067 * Success: non-zero
1068 * Failure: zero
1070 * BUGS
1071 * If an application manually subclasses a window after subclassing it with
1072 * this API and then with this API again, then none of the previous
1073 * subclasses get called or the original window procedure.
1076 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1077 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1079 LPSUBCLASS_INFO stack;
1080 LPSUBCLASSPROCS proc;
1082 TRACE("%p, %p, %Ix, %Ix\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1084 if (!hWnd || !pfnSubclass)
1085 return FALSE;
1087 /* Since the window procedure that we set here has two additional arguments,
1088 * we can't simply set it as the new window procedure of the window. So we
1089 * set our own window procedure and then calculate the other two arguments
1090 * from there. */
1092 /* See if we have been called for this window */
1093 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1094 if (!stack) {
1095 /* allocate stack */
1096 stack = Alloc (sizeof(SUBCLASS_INFO));
1097 if (!stack) {
1098 ERR ("Failed to allocate our Subclassing stack\n");
1099 return FALSE;
1101 SetPropW (hWnd, COMCTL32_wSubclass, stack);
1103 /* set window procedure to our own and save the current one */
1104 stack->is_unicode = IsWindowUnicode (hWnd);
1105 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1106 (DWORD_PTR)COMCTL32_SubclassProc);
1108 else {
1109 /* Check to see if we have called this function with the same uIDSubClass
1110 * and pfnSubclass */
1111 proc = stack->SubclassProcs;
1112 while (proc) {
1113 if ((proc->id == uIDSubclass) &&
1114 (proc->subproc == pfnSubclass)) {
1115 proc->ref = dwRef;
1116 return TRUE;
1118 proc = proc->next;
1122 proc = Alloc(sizeof(SUBCLASSPROCS));
1123 if (!proc) {
1124 ERR ("Failed to allocate subclass entry in stack\n");
1125 if (stack->is_unicode)
1126 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1127 else
1128 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1129 Free (stack);
1130 RemovePropW( hWnd, COMCTL32_wSubclass );
1131 return FALSE;
1134 proc->subproc = pfnSubclass;
1135 proc->ref = dwRef;
1136 proc->id = uIDSubclass;
1137 proc->next = stack->SubclassProcs;
1138 stack->SubclassProcs = proc;
1140 return TRUE;
1144 /***********************************************************************
1145 * GetWindowSubclass [COMCTL32.411]
1147 * Gets the Reference data from a subclass.
1149 * PARAMS
1150 * hWnd [in] Handle to the window which we are subclassing
1151 * pfnSubclass [in] Pointer to the subclass procedure
1152 * uID [in] Unique identifier of the subclassing procedure
1153 * pdwRef [out] Pointer to the reference data
1155 * RETURNS
1156 * Success: Non-zero
1157 * Failure: 0
1160 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1161 UINT_PTR uID, DWORD_PTR *pdwRef)
1163 const SUBCLASS_INFO *stack;
1164 const SUBCLASSPROCS *proc;
1166 TRACE("%p, %p, %Ix, %p\n", hWnd, pfnSubclass, uID, pdwRef);
1168 /* See if we have been called for this window */
1169 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1170 if (!stack)
1171 goto done;
1173 proc = stack->SubclassProcs;
1174 while (proc) {
1175 if ((proc->id == uID) &&
1176 (proc->subproc == pfnSubclass)) {
1177 if (pdwRef)
1178 *pdwRef = proc->ref;
1179 return TRUE;
1181 proc = proc->next;
1184 done:
1185 if (pdwRef)
1186 *pdwRef = 0;
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, %Ix.\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 ((WNDPROC)GetWindowLongPtrW (hWnd, GWLP_WNDPROC) != COMCTL32_SubclassProc)
1245 WARN("Window procedure has been modified, skipping restore\n");
1246 else if (stack->is_unicode)
1247 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1248 else
1249 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1250 Free (stack);
1251 RemovePropW( hWnd, COMCTL32_wSubclass );
1254 return ret;
1257 /***********************************************************************
1258 * COMCTL32_SubclassProc (internal)
1260 * Window procedure for all subclassed windows.
1261 * Saves the current subclassing stack position to support nested messages
1263 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1265 LPSUBCLASS_INFO stack;
1266 LPSUBCLASSPROCS proc;
1267 LRESULT ret;
1269 TRACE("%p, %#x, %#Ix, %#Ix\n", hWnd, uMsg, wParam, lParam);
1271 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1272 if (!stack) {
1273 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1274 return 0;
1277 /* Save our old stackpos to properly handle nested messages */
1278 proc = stack->stackpos;
1279 stack->stackpos = stack->SubclassProcs;
1280 stack->running++;
1281 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1282 stack->running--;
1283 stack->stackpos = proc;
1285 if (!stack->SubclassProcs && !stack->running) {
1286 TRACE("Last Subclass removed, cleaning up\n");
1287 /* clean up our heap and reset the original window procedure */
1288 if (stack->is_unicode)
1289 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1290 else
1291 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1292 Free (stack);
1293 RemovePropW( hWnd, COMCTL32_wSubclass );
1295 return ret;
1298 /***********************************************************************
1299 * DefSubclassProc [COMCTL32.413]
1301 * Calls the next window procedure (i.e. the one before this subclass)
1303 * PARAMS
1304 * hWnd [in] The window that we're subclassing
1305 * uMsg [in] Message
1306 * wParam [in] WPARAM
1307 * lParam [in] LPARAM
1309 * RETURNS
1310 * Success: non-zero
1311 * Failure: zero
1314 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1316 LPSUBCLASS_INFO stack;
1317 LRESULT ret;
1319 TRACE("%p, %#x, %#Ix, %#Ix\n", hWnd, uMsg, wParam, lParam);
1321 /* retrieve our little stack from the Properties */
1322 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1323 if (!stack) {
1324 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1325 return 0;
1328 /* If we are at the end of stack then we have to call the original
1329 * window procedure */
1330 if (!stack->stackpos) {
1331 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1332 } else {
1333 const SUBCLASSPROCS *proc = stack->stackpos;
1334 stack->stackpos = stack->stackpos->next;
1335 /* call the Subclass procedure from the stack */
1336 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1337 proc->id, proc->ref);
1340 return ret;
1344 /***********************************************************************
1345 * COMCTL32_CreateToolTip [NOT AN API]
1347 * Creates a tooltip for the control specified in hwnd and does all
1348 * necessary setup and notifications.
1350 * PARAMS
1351 * hwndOwner [I] Handle to the window that will own the tool tip.
1353 * RETURNS
1354 * Success: Handle of tool tip window.
1355 * Failure: NULL
1358 HWND
1359 COMCTL32_CreateToolTip(HWND hwndOwner)
1361 HWND hwndToolTip;
1363 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1364 CW_USEDEFAULT, CW_USEDEFAULT,
1365 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1366 0, 0, 0);
1368 /* Send NM_TOOLTIPSCREATED notification */
1369 if (hwndToolTip)
1371 NMTOOLTIPSCREATED nmttc;
1372 /* true owner can be different if hwndOwner is a child window */
1373 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1374 nmttc.hdr.hwndFrom = hwndTrueOwner;
1375 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1376 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1377 nmttc.hwndToolTips = hwndToolTip;
1379 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1380 GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
1383 return hwndToolTip;
1387 /***********************************************************************
1388 * COMCTL32_RefreshSysColors [NOT AN API]
1390 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1391 * refresh the color values in the color structure
1393 * PARAMS
1394 * none
1396 * RETURNS
1397 * none
1400 VOID
1401 COMCTL32_RefreshSysColors(void)
1403 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1404 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1405 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1406 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1407 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1408 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1409 comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1410 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1411 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1412 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1413 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1414 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1415 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1416 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1417 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1418 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1419 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1422 /***********************************************************************
1423 * COMCTL32_DrawInsertMark [NOT AN API]
1425 * Draws an insertion mark (which looks similar to an 'I').
1427 * PARAMS
1428 * hDC [I] Device context to draw onto.
1429 * lpRect [I] Co-ordinates of insertion mark.
1430 * clrInsertMark [I] Colour of the insertion mark.
1431 * bHorizontal [I] True if insert mark should be drawn horizontally,
1432 * vertical otherwise.
1434 * RETURNS
1435 * none
1437 * NOTES
1438 * Draws up to but not including the bottom co-ordinate when drawing
1439 * vertically or the right co-ordinate when horizontal.
1441 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1443 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1444 HPEN hOldPen;
1445 static const DWORD adwPolyPoints[] = {4,4,4};
1446 LONG lCentre = (bHorizontal ?
1447 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1448 lpRect->left + (lpRect->right - lpRect->left)/2);
1449 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1450 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1451 const POINT aptInsertMark[] =
1453 /* top (V) or left (H) arrow */
1454 {lCentre , l1 + 2},
1455 {lCentre - 2, l1 },
1456 {lCentre + 3, l1 },
1457 {lCentre + 1, l1 + 2},
1458 /* middle line */
1459 {lCentre , l2 - 2},
1460 {lCentre , l1 - 1},
1461 {lCentre + 1, l1 - 1},
1462 {lCentre + 1, l2 - 2},
1463 /* bottom (V) or right (H) arrow */
1464 {lCentre , l2 - 3},
1465 {lCentre - 2, l2 - 1},
1466 {lCentre + 3, l2 - 1},
1467 {lCentre + 1, l2 - 3},
1469 hOldPen = SelectObject(hDC, hPen);
1470 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, ARRAY_SIZE(adwPolyPoints));
1471 SelectObject(hDC, hOldPen);
1472 DeleteObject(hPen);
1475 /***********************************************************************
1476 * COMCTL32_EnsureBitmapSize [internal]
1478 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1479 * the height is at least cyMinHeight. If the bitmap already has these
1480 * dimensions nothing changes.
1482 * PARAMS
1483 * hBitmap [I/O] Bitmap to modify. The handle may change
1484 * cxMinWidth [I] If the width of the bitmap is smaller, then it will
1485 * be enlarged to this value
1486 * cyMinHeight [I] If the height of the bitmap is smaller, then it will
1487 * be enlarged to this value
1488 * cyBackground [I] The color with which the new area will be filled
1490 * RETURNS
1491 * none
1493 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1495 int cxNew, cyNew;
1496 BITMAP bmp;
1497 HBITMAP hNewBitmap;
1498 HBITMAP hNewDCBitmap, hOldDCBitmap;
1499 HBRUSH hNewDCBrush;
1500 HDC hdcNew, hdcOld;
1502 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1503 return;
1504 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1505 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1506 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1507 return;
1509 hdcNew = CreateCompatibleDC(NULL);
1510 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1511 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1512 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1514 hdcOld = CreateCompatibleDC(NULL);
1515 hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1517 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1518 if (bmp.bmWidth < cxMinWidth)
1519 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1520 if (bmp.bmHeight < cyMinHeight)
1521 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1522 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1523 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1525 SelectObject(hdcNew, hNewDCBitmap);
1526 DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1527 DeleteDC(hdcNew);
1528 SelectObject(hdcOld, hOldDCBitmap);
1529 DeleteDC(hdcOld);
1531 DeleteObject(*pBitmap);
1532 *pBitmap = hNewBitmap;
1533 return;
1536 void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
1538 HDC hdc = GetDC(NULL);
1539 HFONT hOldFont;
1541 hOldFont = SelectObject(hdc, hFont);
1542 GetTextMetricsW(hdc, ptm);
1543 SelectObject(hdc, hOldFont);
1544 ReleaseDC(NULL, hdc);
1547 #ifndef OCM__BASE /* avoid including olectl.h */
1548 #define OCM__BASE (WM_USER+0x1c00)
1549 #endif
1551 /***********************************************************************
1552 * COMCTL32_IsReflectedMessage [internal]
1554 * Some parents reflect notify messages - for some messages sent by the child,
1555 * they send it back with the message code increased by OCM__BASE (0x2000).
1556 * This allows better subclassing of controls. We don't need to handle such
1557 * messages but we don't want to print ERRs for them, so this helper function
1558 * identifies them.
1560 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1561 * collision with defined CCM_ codes.
1563 BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
1565 switch (uMsg)
1567 case OCM__BASE + WM_COMMAND:
1568 case OCM__BASE + WM_CTLCOLORBTN:
1569 case OCM__BASE + WM_CTLCOLOREDIT:
1570 case OCM__BASE + WM_CTLCOLORDLG:
1571 case OCM__BASE + WM_CTLCOLORLISTBOX:
1572 case OCM__BASE + WM_CTLCOLORMSGBOX:
1573 case OCM__BASE + WM_CTLCOLORSCROLLBAR:
1574 case OCM__BASE + WM_CTLCOLORSTATIC:
1575 case OCM__BASE + WM_DRAWITEM:
1576 case OCM__BASE + WM_MEASUREITEM:
1577 case OCM__BASE + WM_DELETEITEM:
1578 case OCM__BASE + WM_VKEYTOITEM:
1579 case OCM__BASE + WM_CHARTOITEM:
1580 case OCM__BASE + WM_COMPAREITEM:
1581 case OCM__BASE + WM_HSCROLL:
1582 case OCM__BASE + WM_VSCROLL:
1583 case OCM__BASE + WM_PARENTNOTIFY:
1584 case OCM__BASE + WM_NOTIFY:
1585 return TRUE;
1586 default:
1587 return FALSE;
1591 /***********************************************************************
1592 * MirrorIcon [COMCTL32.414]
1594 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1596 * PARAMS
1597 * phicon1 [I/O] Icon.
1598 * phicon2 [I/O] Icon.
1600 * RETURNS
1601 * Success: TRUE.
1602 * Failure: FALSE.
1604 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1606 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1607 return FALSE;
1610 static inline BOOL IsDelimiter(WCHAR c)
1612 switch(c)
1614 case '/':
1615 case '\\':
1616 case '.':
1617 case ' ':
1618 return TRUE;
1620 return FALSE;
1623 static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1625 if (code == WB_ISDELIMITER)
1626 return IsDelimiter(lpch[ichCurrent]);
1627 else
1629 int dir = (code == WB_LEFT) ? -1 : 1;
1630 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1631 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1633 return ichCurrent;
1636 /***********************************************************************
1637 * SetPathWordBreakProc [COMCTL32.384]
1639 * Sets the word break procedure for an edit control to one that understands
1640 * paths so that the user can jump over directories.
1642 * PARAMS
1643 * hwnd [I] Handle to edit control.
1644 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1646 * RETURNS
1647 * Result from EM_SETWORDBREAKPROC message.
1649 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1651 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1652 (LPARAM)(bSet ? PathWordBreakProc : NULL));
1655 /***********************************************************************
1656 * DrawShadowText [COMCTL32.@]
1658 * Draw text with shadow.
1660 int WINAPI DrawShadowText(HDC hdc, LPCWSTR text, UINT length, RECT *rect, DWORD flags,
1661 COLORREF crText, COLORREF crShadow, int offset_x, int offset_y)
1663 int bkmode, ret;
1664 COLORREF clr;
1665 RECT r;
1667 FIXME("%p, %s, %d, %p, %#lx, %#lx, %#lx, %d, %d: semi-stub\n", hdc, debugstr_w(text),
1668 length, rect, flags, crText, crShadow, offset_x, offset_y);
1670 bkmode = SetBkMode(hdc, TRANSPARENT);
1671 clr = SetTextColor(hdc, crShadow);
1673 /* FIXME: for shadow we need to render normally, blur it, and blend with current background. */
1674 r = *rect;
1675 OffsetRect(&r, 1, 1);
1676 DrawTextW(hdc, text, length, &r, flags);
1678 SetTextColor(hdc, crText);
1680 /* with text color on top of a shadow */
1681 ret = DrawTextW(hdc, text, length, rect, flags);
1683 SetTextColor(hdc, clr);
1684 SetBkMode(hdc, bkmode);
1686 return ret;
1689 /***********************************************************************
1690 * LoadIconWithScaleDown [COMCTL32.@]
1692 HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
1694 TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
1696 *icon = NULL;
1698 if (!name)
1699 return E_INVALIDARG;
1701 *icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
1702 (hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
1703 if (!*icon)
1704 return HRESULT_FROM_WIN32(GetLastError());
1706 return S_OK;
1709 /***********************************************************************
1710 * LoadIconMetric [COMCTL32.@]
1712 HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
1714 int cx, cy;
1716 TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
1718 if (size == LIM_SMALL)
1720 cx = GetSystemMetrics(SM_CXSMICON);
1721 cy = GetSystemMetrics(SM_CYSMICON);
1723 else if (size == LIM_LARGE)
1725 cx = GetSystemMetrics(SM_CXICON);
1726 cy = GetSystemMetrics(SM_CYICON);
1728 else
1730 *icon = NULL;
1731 return E_INVALIDARG;
1734 return LoadIconWithScaleDown(hinst, name, cx, cy, icon);
1737 static const WCHAR strMRUList[] = L"MRUList";
1739 /**************************************************************************
1740 * Alloc [COMCTL32.71]
1742 * Allocates memory block from the dll's private heap
1744 void * WINAPI Alloc(DWORD size)
1746 return LocalAlloc(LMEM_ZEROINIT, size);
1749 /**************************************************************************
1750 * ReAlloc [COMCTL32.72]
1752 * Changes the size of an allocated memory block or allocates a memory
1753 * block using the dll's private heap.
1756 void * WINAPI ReAlloc(void *src, DWORD size)
1758 if (src)
1759 return LocalReAlloc(src, size, LMEM_ZEROINIT | LMEM_MOVEABLE);
1760 else
1761 return LocalAlloc(LMEM_ZEROINIT, size);
1764 /**************************************************************************
1765 * Free [COMCTL32.73]
1767 * Frees an allocated memory block from the dll's private heap.
1769 BOOL WINAPI Free(void *mem)
1771 return !LocalFree(mem);
1774 /**************************************************************************
1775 * GetSize [COMCTL32.74]
1777 DWORD WINAPI GetSize(void *mem)
1779 return LocalSize(mem);
1782 /**************************************************************************
1783 * MRU-Functions {COMCTL32}
1785 * NOTES
1786 * The MRU-API is a set of functions to manipulate lists of M.R.U. (Most Recently
1787 * Used) items. It is an undocumented API that is used (at least) by the shell
1788 * and explorer to implement their recent documents feature.
1790 * Since these functions are undocumented, they are unsupported by MS and
1791 * may change at any time.
1793 * Internally, the list is implemented as a last in, last out list of items
1794 * persisted into the system registry under a caller chosen key. Each list
1795 * item is given a one character identifier in the Ascii range from 'a' to
1796 * '}'. A list of the identifiers in order from newest to oldest is stored
1797 * under the same key in a value named "MRUList".
1799 * Items are re-ordered by changing the order of the values in the MRUList
1800 * value. When a new item is added, it becomes the new value of the oldest
1801 * identifier, and that identifier is moved to the front of the MRUList value.
1803 * Wine stores MRU-lists in the same registry format as Windows, so when
1804 * switching between the builtin and native comctl32.dll no problems or
1805 * incompatibilities should occur.
1807 * The following undocumented structure is used to create an MRU-list:
1808 *|typedef INT (CALLBACK *MRUStringCmpFn)(LPCTSTR lhs, LPCTSTR rhs);
1809 *|typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
1811 *|typedef struct tagMRUINFO
1813 *| DWORD cbSize;
1814 *| UINT uMax;
1815 *| UINT fFlags;
1816 *| HKEY hKey;
1817 *| LPTSTR lpszSubKey;
1818 *| PROC lpfnCompare;
1819 *|} MRUINFO, *LPMRUINFO;
1821 * MEMBERS
1822 * cbSize [I] The size of the MRUINFO structure. This must be set
1823 * to sizeof(MRUINFO) by the caller.
1824 * uMax [I] The maximum number of items allowed in the list. Because
1825 * of the limited number of identifiers, this should be set to
1826 * a value from 1 to 30 by the caller.
1827 * fFlags [I] If bit 0 is set, the list will be used to store binary
1828 * data, otherwise it is assumed to store strings. If bit 1
1829 * is set, every change made to the list will be reflected in
1830 * the registry immediately, otherwise changes will only be
1831 * written when the list is closed.
1832 * hKey [I] The registry key that the list should be written under.
1833 * This must be supplied by the caller.
1834 * lpszSubKey [I] A caller supplied name of a subkey under hKey to write
1835 * the list to. This may not be blank.
1836 * lpfnCompare [I] A caller supplied comparison function, which may be either
1837 * an MRUStringCmpFn if dwFlags does not have bit 0 set, or a
1838 * MRUBinaryCmpFn otherwise.
1840 * FUNCTIONS
1841 * - Create an MRU-list with CreateMRUList() or CreateMRUListLazy().
1842 * - Add items to an MRU-list with AddMRUString() or AddMRUData().
1843 * - Remove items from an MRU-list with DelMRUString().
1844 * - Find data in an MRU-list with FindMRUString() or FindMRUData().
1845 * - Iterate through an MRU-list with EnumMRUList().
1846 * - Free an MRU-list with FreeMRUList().
1849 typedef INT (CALLBACK *MRUStringCmpFnA)(LPCSTR lhs, LPCSTR rhs);
1850 typedef INT (CALLBACK *MRUStringCmpFnW)(LPCWSTR lhs, LPCWSTR rhs);
1851 typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
1853 struct MRUINFOA
1855 DWORD cbSize;
1856 UINT uMax;
1857 UINT fFlags;
1858 HKEY hKey;
1859 LPSTR lpszSubKey;
1860 union
1862 MRUStringCmpFnA string_cmpfn;
1863 MRUBinaryCmpFn binary_cmpfn;
1864 } u;
1867 struct MRUINFOW
1869 DWORD cbSize;
1870 UINT uMax;
1871 UINT fFlags;
1872 HKEY hKey;
1873 LPWSTR lpszSubKey;
1874 union
1876 MRUStringCmpFnW string_cmpfn;
1877 MRUBinaryCmpFn binary_cmpfn;
1878 } u;
1881 /* MRUINFO.fFlags */
1882 #define MRU_STRING 0 /* list will contain strings */
1883 #define MRU_BINARY 1 /* list will contain binary data */
1884 #define MRU_CACHEWRITE 2 /* only save list order to reg. is FreeMRUList */
1886 /* If list is a string list lpfnCompare has the following prototype
1887 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
1888 * for binary lists the prototype is
1889 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
1890 * where cbData is the no. of bytes to compare.
1891 * Need to check what return value means identical - 0?
1894 typedef struct tagWINEMRUITEM
1896 DWORD size; /* size of data stored */
1897 DWORD itemFlag; /* flags */
1898 BYTE datastart;
1899 } WINEMRUITEM, *LPWINEMRUITEM;
1901 /* itemFlag */
1902 #define WMRUIF_CHANGED 0x0001 /* this dataitem changed */
1904 typedef struct tagWINEMRULIST
1906 struct MRUINFOW extview; /* original create information */
1907 BOOL isUnicode; /* is compare fn Unicode */
1908 DWORD wineFlags; /* internal flags */
1909 DWORD cursize; /* current size of realMRU */
1910 LPWSTR realMRU; /* pointer to string of index names */
1911 LPWINEMRUITEM *array; /* array of pointers to data */
1912 /* in 'a' to 'z' order */
1913 } WINEMRULIST, *LPWINEMRULIST;
1915 /* wineFlags */
1916 #define WMRUF_CHANGED 0x0001 /* MRU list has changed */
1918 /**************************************************************************
1919 * MRU_SaveChanged (internal)
1921 * Local MRU saving code
1923 static void MRU_SaveChanged(WINEMRULIST *mp)
1925 UINT i, err;
1926 HKEY newkey;
1927 WCHAR realname[2];
1928 WINEMRUITEM *witem;
1930 /* or should we do the following instead of RegOpenKeyEx:
1933 /* open the sub key */
1934 if ((err = RegOpenKeyExW(mp->extview.hKey, mp->extview.lpszSubKey, 0, KEY_WRITE, &newkey)))
1936 /* not present - what to do ??? */
1937 ERR("Could not open key, error=%d, attempting to create\n", err);
1938 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
1939 KEY_READ | KEY_WRITE, 0, &newkey, 0)))
1941 ERR("failed to create key /%s/, err=%d\n", debugstr_w(mp->extview.lpszSubKey), err);
1942 return;
1946 if (mp->wineFlags & WMRUF_CHANGED)
1948 mp->wineFlags &= ~WMRUF_CHANGED;
1949 if ((err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (BYTE *)mp->realMRU,
1950 (lstrlenW(mp->realMRU) + 1)*sizeof(WCHAR))))
1952 ERR("error saving MRUList, err=%d\n", err);
1954 TRACE("saving MRUList=/%s/\n", debugstr_w(mp->realMRU));
1957 realname[1] = 0;
1958 for (i = 0; i < mp->cursize; ++i)
1960 witem = mp->array[i];
1961 if (witem->itemFlag & WMRUIF_CHANGED)
1963 witem->itemFlag &= ~WMRUIF_CHANGED;
1964 realname[0] = 'a' + i;
1965 if ((err = RegSetValueExW(newkey, realname, 0, (mp->extview.fFlags & MRU_BINARY) ?
1966 REG_BINARY : REG_SZ, &witem->datastart, witem->size)))
1968 ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err);
1970 TRACE("saving value for name /%s/ size %ld\n", debugstr_w(realname), witem->size);
1973 RegCloseKey(newkey);
1976 /**************************************************************************
1977 * FreeMRUList [COMCTL32.152]
1979 * Frees a most-recently-used items list.
1981 void WINAPI FreeMRUList(HANDLE hMRUList)
1983 WINEMRULIST *mp = hMRUList;
1984 unsigned int i;
1986 TRACE("%p.\n", hMRUList);
1988 if (!hMRUList)
1989 return;
1991 if (mp->wineFlags & WMRUF_CHANGED)
1993 /* need to open key and then save the info */
1994 MRU_SaveChanged(mp);
1997 for (i = 0; i < mp->extview.uMax; ++i)
1998 Free(mp->array[i]);
2000 Free(mp->realMRU);
2001 Free(mp->array);
2002 Free(mp->extview.lpszSubKey);
2003 Free(mp);
2006 /**************************************************************************
2007 * FindMRUData [COMCTL32.169]
2009 * Searches binary list for item that matches data of given length.
2010 * Returns position in list order 0 -> MRU and value corresponding to item's reg.
2011 * name will be stored in it ('a' -> 0).
2014 INT WINAPI FindMRUData(HANDLE hList, const void *data, DWORD cbData, int *pos)
2016 const WINEMRULIST *mp = hList;
2017 INT ret;
2018 UINT i;
2019 LPSTR dataA = NULL;
2021 if (!mp || !mp->extview.u.string_cmpfn)
2022 return -1;
2024 if (!(mp->extview.fFlags & MRU_BINARY) && !mp->isUnicode)
2026 DWORD len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
2027 dataA = Alloc(len);
2028 WideCharToMultiByte(CP_ACP, 0, data, -1, dataA, len, NULL, NULL);
2031 for (i = 0; i < mp->cursize; ++i)
2033 if (mp->extview.fFlags & MRU_BINARY)
2035 if (!mp->extview.u.binary_cmpfn(data, &mp->array[i]->datastart, cbData))
2036 break;
2038 else
2040 if (mp->isUnicode)
2042 if (!mp->extview.u.string_cmpfn(data, (LPWSTR)&mp->array[i]->datastart))
2043 break;
2045 else
2047 DWORD len = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
2048 NULL, 0, NULL, NULL);
2049 LPSTR itemA = Alloc(len);
2050 INT cmp;
2051 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1, itemA, len, NULL, NULL);
2053 cmp = mp->extview.u.string_cmpfn((LPWSTR)dataA, (LPWSTR)itemA);
2054 Free(itemA);
2055 if (!cmp)
2056 break;
2061 Free(dataA);
2062 if (i < mp->cursize)
2063 ret = i;
2064 else
2065 ret = -1;
2066 if (pos && (ret != -1))
2067 *pos = 'a' + i;
2069 TRACE("%p, %p, %ld, %p, returning %d.\n", hList, data, cbData, pos, ret);
2071 return ret;
2074 /**************************************************************************
2075 * AddMRUData [COMCTL32.167]
2077 * Add item to MRU binary list. If item already exists in list then it is
2078 * simply moved up to the top of the list and not added again. If list is
2079 * full then the least recently used item is removed to make room.
2082 INT WINAPI AddMRUData(HANDLE hList, const void *data, DWORD cbData)
2084 WINEMRULIST *mp = hList;
2085 WINEMRUITEM *witem;
2086 INT i, replace;
2088 if ((replace = FindMRUData(hList, data, cbData, NULL)) >= 0)
2090 /* Item exists, just move it to the front */
2091 LPWSTR pos = wcschr(mp->realMRU, replace + 'a');
2092 while (pos > mp->realMRU)
2094 pos[0] = pos[-1];
2095 pos--;
2098 else
2100 /* either add a new entry or replace oldest */
2101 if (mp->cursize < mp->extview.uMax)
2103 /* Add in a new item */
2104 replace = mp->cursize;
2105 mp->cursize++;
2107 else
2109 /* get the oldest entry and replace data */
2110 replace = mp->realMRU[mp->cursize - 1] - 'a';
2111 Free(mp->array[replace]);
2114 /* Allocate space for new item and move in the data */
2115 mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM));
2116 witem->itemFlag |= WMRUIF_CHANGED;
2117 witem->size = cbData;
2118 memcpy( &witem->datastart, data, cbData);
2120 /* now rotate MRU list */
2121 for (i = mp->cursize - 1; i >= 1; --i)
2122 mp->realMRU[i] = mp->realMRU[i-1];
2125 /* The new item gets the front spot */
2126 mp->wineFlags |= WMRUF_CHANGED;
2127 mp->realMRU[0] = replace + 'a';
2129 TRACE("%p, %p, %ld adding data, /%c/ now most current\n", hList, data, cbData, replace+'a');
2131 if (!(mp->extview.fFlags & MRU_CACHEWRITE))
2133 /* save changed stuff right now */
2134 MRU_SaveChanged(mp);
2137 return replace;
2140 /**************************************************************************
2141 * AddMRUStringW [COMCTL32.401]
2143 * Add an item to an MRU string list.
2146 INT WINAPI AddMRUStringW(HANDLE hList, const WCHAR *str)
2148 TRACE("%p, %s.\n", hList, debugstr_w(str));
2150 if (!hList)
2151 return -1;
2153 if (!str || IsBadStringPtrW(str, -1))
2155 SetLastError(ERROR_INVALID_PARAMETER);
2156 return 0;
2159 return AddMRUData(hList, str, (lstrlenW(str) + 1) * sizeof(WCHAR));
2162 /**************************************************************************
2163 * AddMRUStringA [COMCTL32.153]
2165 INT WINAPI AddMRUStringA(HANDLE hList, const char *str)
2167 WCHAR *strW;
2168 DWORD len;
2169 INT ret;
2171 TRACE("%p, %s.\n", hList, debugstr_a(str));
2173 if (!hList)
2174 return -1;
2176 if (IsBadStringPtrA(str, -1))
2178 SetLastError(ERROR_INVALID_PARAMETER);
2179 return 0;
2182 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0) * sizeof(WCHAR);
2183 strW = Alloc(len);
2184 if (!strW)
2185 return -1;
2187 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len/sizeof(WCHAR));
2188 ret = AddMRUData(hList, strW, len);
2189 Free(strW);
2190 return ret;
2193 /**************************************************************************
2194 * DelMRUString [COMCTL32.156]
2196 * Removes item from either string or binary list (despite its name)
2198 * PARAMS
2199 * hList [I] list handle
2200 * nItemPos [I] item position to remove 0 -> MRU
2202 * RETURNS
2203 * TRUE if successful, FALSE if nItemPos is out of range.
2205 BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos)
2207 FIXME("(%p, %d): stub\n", hList, nItemPos);
2208 return TRUE;
2211 /**************************************************************************
2212 * FindMRUStringW [COMCTL32.402]
2214 INT WINAPI FindMRUStringW(HANDLE hList, const WCHAR *str, int *pos)
2216 return FindMRUData(hList, str, (lstrlenW(str) + 1) * sizeof(WCHAR), pos);
2219 /**************************************************************************
2220 * FindMRUStringA [COMCTL32.155]
2222 * Searches string list for item that matches given string.
2224 * RETURNS
2225 * Position in list 0 -> MRU. -1 if item not found.
2227 INT WINAPI FindMRUStringA(HANDLE hList, const char *str, int *pos)
2229 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
2230 WCHAR *strW = Alloc(len * sizeof(*strW));
2231 INT ret;
2233 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
2234 ret = FindMRUData(hList, strW, len * sizeof(WCHAR), pos);
2235 Free(strW);
2236 return ret;
2239 /*************************************************************************
2240 * create_mru_list (internal)
2242 static HANDLE create_mru_list(WINEMRULIST *mp)
2244 UINT i, err;
2245 HKEY newkey;
2246 DWORD datasize, dwdisp;
2247 WCHAR realname[2];
2248 WINEMRUITEM *witem;
2249 DWORD type;
2251 /* get space to save indices that will turn into names
2252 * but in order of most to least recently used
2254 mp->realMRU = Alloc((mp->extview.uMax + 2) * sizeof(WCHAR));
2256 /* get space to save pointers to actual data in order of
2257 * 'a' to 'z' (0 to n).
2259 mp->array = Alloc(mp->extview.uMax * sizeof(LPVOID));
2261 /* open the sub key */
2262 if ((err = RegCreateKeyExW(mp->extview.hKey, mp->extview.lpszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
2263 KEY_READ | KEY_WRITE, 0, &newkey, &dwdisp)))
2265 /* error - what to do ??? */
2266 ERR("%lu, %u, %x, %p, %s, %p: Could not open key, error=%d\n", mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
2267 mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.u.string_cmpfn, err);
2268 return 0;
2271 /* get values from key 'MRUList' */
2272 if (newkey)
2274 datasize = (mp->extview.uMax + 1) * sizeof(WCHAR);
2275 if (RegQueryValueExW( newkey, strMRUList, 0, &type, (BYTE *)mp->realMRU, &datasize))
2277 /* not present - set size to 1 (will become 0 later) */
2278 datasize = 1;
2279 *mp->realMRU = 0;
2281 else
2282 datasize /= sizeof(WCHAR);
2284 TRACE("MRU list = %s, datasize = %ld\n", debugstr_w(mp->realMRU), datasize);
2286 mp->cursize = datasize - 1;
2287 /* datasize now has number of items in the MRUList */
2289 /* get actual values for each entry */
2290 realname[1] = 0;
2291 for (i = 0; i < mp->cursize; ++i)
2293 realname[0] = 'a' + i;
2294 if (RegQueryValueExW(newkey, realname, 0, &type, 0, &datasize))
2296 /* not present - what to do ??? */
2297 ERR("Key %s not found 1\n", debugstr_w(realname));
2299 mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM));
2300 witem->size = datasize;
2301 if (RegQueryValueExW(newkey, realname, 0, &type, &witem->datastart, &datasize))
2303 /* not present - what to do ??? */
2304 ERR("Key %s not found 2\n", debugstr_w(realname));
2307 RegCloseKey( newkey );
2309 else
2310 mp->cursize = 0;
2312 TRACE("%lu, %u, %x, %p, %s, %p: Current Size = %ld\n", mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
2313 mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.u.string_cmpfn, mp->cursize);
2314 return mp;
2317 /**************************************************************************
2318 * CreateMRUListLazyW [COMCTL32.404]
2320 HANDLE WINAPI CreateMRUListLazyW(const struct MRUINFOW *info, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
2322 WINEMRULIST *mp;
2324 /* Native does not check for a NULL. */
2325 if (!info->hKey || IsBadStringPtrW(info->lpszSubKey, -1))
2326 return NULL;
2328 mp = Alloc(sizeof(*mp));
2329 memcpy(&mp->extview, info, sizeof(*info));
2330 mp->extview.lpszSubKey = Alloc((lstrlenW(info->lpszSubKey) + 1) * sizeof(WCHAR));
2331 lstrcpyW(mp->extview.lpszSubKey, info->lpszSubKey);
2332 mp->isUnicode = TRUE;
2334 return create_mru_list(mp);
2337 /**************************************************************************
2338 * CreateMRUListLazyA [COMCTL32.157]
2340 * Creates a most-recently-used list.
2342 HANDLE WINAPI CreateMRUListLazyA(const struct MRUINFOA *info, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
2344 WINEMRULIST *mp;
2345 DWORD len;
2347 /* Native does not check for a NULL lpcml */
2349 if (!info->hKey || IsBadStringPtrA(info->lpszSubKey, -1))
2350 return 0;
2352 mp = Alloc(sizeof(*mp));
2353 memcpy(&mp->extview, info, sizeof(*info));
2354 len = MultiByteToWideChar(CP_ACP, 0, info->lpszSubKey, -1, NULL, 0);
2355 mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR));
2356 MultiByteToWideChar(CP_ACP, 0, info->lpszSubKey, -1, mp->extview.lpszSubKey, len);
2357 mp->isUnicode = FALSE;
2358 return create_mru_list(mp);
2361 /**************************************************************************
2362 * CreateMRUListW [COMCTL32.400]
2364 HANDLE WINAPI CreateMRUListW(const struct MRUINFOW *info)
2366 return CreateMRUListLazyW(info, 0, 0, 0);
2369 /**************************************************************************
2370 * CreateMRUListA [COMCTL32.151]
2372 HANDLE WINAPI CreateMRUListA(const struct MRUINFOA *info)
2374 return CreateMRUListLazyA(info, 0, 0, 0);
2377 /**************************************************************************
2378 * EnumMRUListW [COMCTL32.403]
2380 * Enumerate item in a most-recently-used list
2382 * PARAMS
2383 * hList [I] list handle
2384 * nItemPos [I] item position to enumerate
2385 * lpBuffer [O] buffer to receive item
2386 * nBufferSize [I] size of buffer
2388 * RETURNS
2389 * For binary lists specifies how many bytes were copied to buffer, for
2390 * string lists specifies full length of string. Enumerating past the end
2391 * of list returns -1.
2392 * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
2393 * the list.
2395 INT WINAPI EnumMRUListW(HANDLE hList, INT nItemPos, void *buffer, DWORD nBufferSize)
2397 const WINEMRULIST *mp = hList;
2398 const WINEMRUITEM *witem;
2399 INT desired, datasize;
2401 if (!mp) return -1;
2402 if ((nItemPos < 0) || !buffer) return mp->cursize;
2403 if (nItemPos >= mp->cursize) return -1;
2404 desired = mp->realMRU[nItemPos];
2405 desired -= 'a';
2406 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
2407 witem = mp->array[desired];
2408 datasize = min(witem->size, nBufferSize);
2409 memcpy(buffer, &witem->datastart, datasize);
2410 TRACE("(%p, %d, %p, %ld): returning len %d\n", hList, nItemPos, buffer, nBufferSize, datasize);
2411 return datasize;
2414 /**************************************************************************
2415 * EnumMRUListA [COMCTL32.154]
2417 INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, void *buffer, DWORD nBufferSize)
2419 const WINEMRULIST *mp = hList;
2420 WINEMRUITEM *witem;
2421 INT desired, datasize;
2422 DWORD lenA;
2424 if (!mp) return -1;
2425 if ((nItemPos < 0) || !buffer) return mp->cursize;
2426 if (nItemPos >= mp->cursize) return -1;
2427 desired = mp->realMRU[nItemPos];
2428 desired -= 'a';
2429 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
2430 witem = mp->array[desired];
2431 if (mp->extview.fFlags & MRU_BINARY)
2433 datasize = min(witem->size, nBufferSize);
2434 memcpy(buffer, &witem->datastart, datasize);
2436 else
2438 lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, NULL, 0, NULL, NULL);
2439 datasize = min(lenA, nBufferSize);
2440 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, buffer, datasize, NULL, NULL);
2441 ((char *)buffer)[ datasize - 1 ] = '\0';
2442 datasize = lenA - 1;
2444 TRACE("(%p, %d, %p, %ld): returning len=%d\n", hList, nItemPos, buffer, nBufferSize, datasize);
2445 return datasize;
2448 /**************************************************************************
2449 * Str_GetPtrWtoA [internal]
2451 * Converts a unicode string into a multi byte string
2455 INT Str_GetPtrWtoA(const WCHAR *src, char *dst, INT nMaxLen)
2457 INT len;
2459 TRACE("%s, %p, %d.\n", debugstr_w(src), dst, nMaxLen);
2461 if (!dst && src)
2462 return WideCharToMultiByte(CP_ACP, 0, src, -1, 0, 0, NULL, NULL);
2464 if (!nMaxLen)
2465 return 0;
2467 if (!src)
2469 dst[0] = 0;
2470 return 0;
2473 len = WideCharToMultiByte(CP_ACP, 0, src, -1, 0, 0, NULL, NULL);
2474 if (len >= nMaxLen)
2475 len = nMaxLen - 1;
2477 WideCharToMultiByte(CP_ACP, 0, src, -1, dst, len, NULL, NULL);
2478 dst[len] = '\0';
2480 return len;
2483 /**************************************************************************
2484 * Str_GetPtrAtoW [internal]
2486 * Converts a multibyte string into a unicode string
2489 INT Str_GetPtrAtoW(const char *src, WCHAR *dst, INT nMaxLen)
2491 INT len;
2493 TRACE("%s, %p, %d.\n", debugstr_a(src), dst, nMaxLen);
2495 if (!dst && src)
2496 return MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
2498 if (!nMaxLen)
2499 return 0;
2501 if (!src)
2503 *dst = 0;
2504 return 0;
2507 len = MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
2508 if (len >= nMaxLen)
2509 len = nMaxLen - 1;
2511 MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
2512 dst[len] = 0;
2514 return len;
2517 /**************************************************************************
2518 * Str_SetPtrAtoW [internal]
2520 * Converts a multi byte string to a unicode string.
2521 * If the pointer to the destination buffer is NULL a buffer is allocated.
2522 * If the destination buffer is too small to keep the converted multi byte
2523 * string the destination buffer is reallocated. If the source pointer is
2525 BOOL Str_SetPtrAtoW(WCHAR **dst, const char *src)
2527 TRACE("%p, %s.\n", dst, debugstr_a(src));
2529 if (src)
2531 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
2532 LPWSTR ptr = ReAlloc(*dst, len * sizeof(**dst));
2534 if (!ptr)
2535 return FALSE;
2536 MultiByteToWideChar(CP_ACP, 0, src, -1, ptr, len);
2537 *dst = ptr;
2539 else
2541 Free(*dst);
2542 *dst = NULL;
2545 return TRUE;
2548 /**************************************************************************
2549 * Str_SetPtrWtoA [internal]
2551 * Converts a unicode string to a multi byte string.
2552 * If the pointer to the destination buffer is NULL a buffer is allocated.
2553 * If the destination buffer is too small to keep the converted wide
2554 * string the destination buffer is reallocated. If the source pointer is
2555 * NULL, the destination buffer is freed.
2557 BOOL Str_SetPtrWtoA(char **dst, const WCHAR *src)
2559 TRACE("%p, %s.\n", dst, debugstr_w(src));
2561 if (src)
2563 INT len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, FALSE);
2564 LPSTR ptr = ReAlloc(*dst, len * sizeof(**dst));
2566 if (!ptr)
2567 return FALSE;
2568 WideCharToMultiByte(CP_ACP, 0, src, -1, ptr, len, NULL, FALSE);
2569 *dst = ptr;
2571 else
2573 Free(*dst);
2574 *dst = NULL;
2577 return TRUE;
2580 /**************************************************************************
2581 * Notification functions
2584 struct NOTIFYDATA
2586 HWND hwndFrom;
2587 HWND hwndTo;
2588 DWORD dwParam3;
2589 DWORD dwParam4;
2590 DWORD dwParam5;
2591 DWORD dwParam6;
2594 /**************************************************************************
2595 * DoNotify [Internal]
2598 static LRESULT DoNotify(const struct NOTIFYDATA *notify, UINT code, NMHDR *hdr)
2600 NMHDR nmhdr;
2601 NMHDR *lpNmh = NULL;
2602 UINT idFrom = 0;
2604 TRACE("%p, %p, %d, %p, %#lx.\n", notify->hwndFrom, notify->hwndTo, code, hdr, notify->dwParam5);
2606 if (!notify->hwndTo)
2607 return 0;
2609 if (notify->hwndFrom == (HWND)-1)
2611 lpNmh = hdr;
2612 idFrom = hdr->idFrom;
2614 else
2616 if (notify->hwndFrom)
2617 idFrom = GetDlgCtrlID(notify->hwndFrom);
2619 lpNmh = hdr ? hdr : &nmhdr;
2620 lpNmh->hwndFrom = notify->hwndFrom;
2621 lpNmh->idFrom = idFrom;
2622 lpNmh->code = code;
2625 return SendMessageW(notify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
2628 /**************************************************************************
2629 * SendNotify [COMCTL32.341]
2631 * Sends a WM_NOTIFY message to the specified window.
2634 LRESULT WINAPI SendNotify(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr)
2636 struct NOTIFYDATA notify;
2638 TRACE("%p, %p, %d, %p.\n", hwndTo, hwndFrom, code, hdr);
2640 notify.hwndFrom = hwndFrom;
2641 notify.hwndTo = hwndTo;
2642 notify.dwParam5 = 0;
2643 notify.dwParam6 = 0;
2645 return DoNotify(&notify, code, hdr);
2648 /**************************************************************************
2649 * SendNotifyEx [COMCTL32.342]
2651 * Sends a WM_NOTIFY message to the specified window.
2653 * PARAMS
2654 * hwndFrom [I] Window to receive the message
2655 * hwndTo [I] Window that the message is from
2656 * code [I] Notification code
2657 * hdr [I] The NMHDR and any additional information to send or NULL
2658 * dwParam5 [I] Unknown
2660 * RETURNS
2661 * Success: return value from notification
2662 * Failure: 0
2664 * NOTES
2665 * If hwndFrom is -1 then the identifier of the control sending the
2666 * message is taken from the NMHDR structure.
2667 * If hwndFrom is not -1 then lpHdr can be NULL.
2669 LRESULT WINAPI SendNotifyEx(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr, DWORD dwParam5)
2671 struct NOTIFYDATA notify;
2672 HWND hwndNotify;
2674 TRACE("%p, %p, %d, %p, %#lx\n", hwndFrom, hwndTo, code, hdr, dwParam5);
2676 hwndNotify = hwndTo;
2677 if (!hwndTo)
2679 if (IsWindow(hwndFrom))
2681 hwndNotify = GetParent(hwndFrom);
2682 if (!hwndNotify)
2683 return 0;
2687 notify.hwndFrom = hwndFrom;
2688 notify.hwndTo = hwndNotify;
2689 notify.dwParam5 = dwParam5;
2690 notify.dwParam6 = 0;
2692 return DoNotify(&notify, code, hdr);