msvcrt: Use fpclass constants from public header.
[wine/zf.git] / dlls / comctl32 / commctrl.c
blobcb9c22a3a88ac5a326c2fd13e458b9a60d3bb112
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 "wine/debug.h"
77 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
80 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
82 static LPWSTR COMCTL32_wSubclass = NULL;
83 HMODULE COMCTL32_hModule = 0;
84 static LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
85 HBRUSH COMCTL32_hPattern55AABrush = NULL;
86 COMCTL32_SysColor comctl32_color;
88 static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
90 static const WORD wPattern55AA[] =
92 0x5555, 0xaaaa, 0x5555, 0xaaaa,
93 0x5555, 0xaaaa, 0x5555, 0xaaaa
96 static const WCHAR strCC32SubclassInfo[] = L"CC32SubclassInfo";
98 static void unregister_versioned_classes(void)
100 #define VERSION "6.0.2600.2982!"
101 static const char *classes[] =
103 VERSION WC_BUTTONA,
104 VERSION WC_COMBOBOXA,
105 VERSION "ComboLBox",
106 VERSION WC_EDITA,
107 VERSION WC_LISTBOXA,
108 VERSION WC_STATICA,
110 int i;
112 for (i = 0; i < ARRAY_SIZE(classes); i++)
113 UnregisterClassA(classes[i], NULL);
115 #undef VERSION
118 BOOL WINAPI RegisterClassNameW(const WCHAR *class)
120 static const struct
122 const WCHAR nameW[16];
123 void (*fn_register)(void);
125 classes[] =
127 { L"Button", BUTTON_Register },
128 { L"ComboBox", COMBO_Register },
129 { L"ComboLBox", COMBOLBOX_Register },
130 { L"Edit", EDIT_Register },
131 { L"ListBox", LISTBOX_Register },
132 { L"Static", STATIC_Register },
135 int min = 0, max = ARRAY_SIZE(classes) - 1;
137 while (min <= max)
139 int res, pos = (min + max) / 2;
140 if (!(res = wcsicmp(class, classes[pos].nameW)))
142 classes[pos].fn_register();
143 return TRUE;
145 if (res < 0) max = pos - 1;
146 else min = pos + 1;
149 return FALSE;
152 /***********************************************************************
153 * DllMain [Internal]
155 * Initializes the internal 'COMCTL32.DLL'.
157 * PARAMS
158 * hinstDLL [I] handle to the 'dlls' instance
159 * fdwReason [I]
160 * lpvReserved [I] reserved, must be NULL
162 * RETURNS
163 * Success: TRUE
164 * Failure: FALSE
167 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
169 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
171 switch (fdwReason) {
172 case DLL_PROCESS_ATTACH:
173 DisableThreadLibraryCalls(hinstDLL);
175 COMCTL32_hModule = hinstDLL;
177 /* add global subclassing atom (used by 'tooltip' and 'updown') */
178 COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
179 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
181 /* create local pattern brush */
182 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
183 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
185 /* Get all the colors at DLL load */
186 COMCTL32_RefreshSysColors();
188 /* like comctl32 5.82+ register all the common control classes */
189 ANIMATE_Register ();
190 COMBOEX_Register ();
191 DATETIME_Register ();
192 FLATSB_Register ();
193 HEADER_Register ();
194 HOTKEY_Register ();
195 IPADDRESS_Register ();
196 LISTVIEW_Register ();
197 MONTHCAL_Register ();
198 NATIVEFONT_Register ();
199 PAGER_Register ();
200 PROGRESS_Register ();
201 REBAR_Register ();
202 STATUS_Register ();
203 SYSLINK_Register ();
204 TAB_Register ();
205 TOOLBAR_Register ();
206 TOOLTIPS_Register ();
207 TRACKBAR_Register ();
208 TREEVIEW_Register ();
209 UPDOWN_Register ();
211 /* subclass user32 controls */
212 THEMING_Initialize ();
213 break;
215 case DLL_PROCESS_DETACH:
216 if (lpvReserved) break;
217 /* clean up subclassing */
218 THEMING_Uninitialize();
220 /* unregister all common control classes */
221 ANIMATE_Unregister ();
222 COMBOEX_Unregister ();
223 DATETIME_Unregister ();
224 FLATSB_Unregister ();
225 HEADER_Unregister ();
226 HOTKEY_Unregister ();
227 IPADDRESS_Unregister ();
228 LISTVIEW_Unregister ();
229 MONTHCAL_Unregister ();
230 NATIVEFONT_Unregister ();
231 PAGER_Unregister ();
232 PROGRESS_Unregister ();
233 REBAR_Unregister ();
234 STATUS_Unregister ();
235 SYSLINK_Unregister ();
236 TAB_Unregister ();
237 TOOLBAR_Unregister ();
238 TOOLTIPS_Unregister ();
239 TRACKBAR_Unregister ();
240 TREEVIEW_Unregister ();
241 UPDOWN_Unregister ();
243 unregister_versioned_classes ();
245 /* delete local pattern brush */
246 DeleteObject (COMCTL32_hPattern55AABrush);
247 DeleteObject (COMCTL32_hPattern55AABitmap);
249 /* delete global subclassing atom */
250 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
251 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
252 break;
255 return TRUE;
259 /***********************************************************************
260 * MenuHelp [COMCTL32.2]
262 * Handles the setting of status bar help messages when the user
263 * selects menu items.
265 * PARAMS
266 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
267 * wParam [I] wParam of the message uMsg
268 * lParam [I] lParam of the message uMsg
269 * hMainMenu [I] handle to the application's main menu
270 * hInst [I] handle to the module that contains string resources
271 * hwndStatus [I] handle to the status bar window
272 * lpwIDs [I] pointer to an array of integers (see NOTES)
274 * RETURNS
275 * No return value
277 * NOTES
278 * The official documentation is incomplete!
279 * This is the correct documentation:
281 * uMsg:
282 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
283 * WM_MENUSELECT messages.
285 * lpwIDs:
286 * (will be written ...)
289 VOID WINAPI
290 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
291 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
293 UINT uMenuID = 0;
295 if (!IsWindow (hwndStatus))
296 return;
298 switch (uMsg) {
299 case WM_MENUSELECT:
300 TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
301 wParam, lParam);
303 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
304 /* menu was closed */
305 TRACE("menu was closed!\n");
306 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
308 else {
309 /* menu item was selected */
310 if (HIWORD(wParam) & MF_POPUP)
311 uMenuID = *(lpwIDs+1);
312 else
313 uMenuID = (UINT)LOWORD(wParam);
314 TRACE("uMenuID = %u\n", uMenuID);
316 if (uMenuID) {
317 WCHAR szText[256];
319 if (!LoadStringW (hInst, uMenuID, szText, ARRAY_SIZE(szText)))
320 szText[0] = '\0';
322 SendMessageW (hwndStatus, SB_SETTEXTW,
323 255 | SBT_NOBORDERS, (LPARAM)szText);
324 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
327 break;
329 case WM_COMMAND :
330 TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
331 wParam, lParam);
332 /* WM_COMMAND is not invalid since it is documented
333 * in the windows api reference. So don't output
334 * any FIXME for WM_COMMAND
336 WARN("We don't care about the WM_COMMAND\n");
337 break;
339 default:
340 FIXME("Invalid Message 0x%x!\n", uMsg);
341 break;
346 /***********************************************************************
347 * ShowHideMenuCtl [COMCTL32.3]
349 * Shows or hides controls and updates the corresponding menu item.
351 * PARAMS
352 * hwnd [I] handle to the client window.
353 * uFlags [I] menu command id.
354 * lpInfo [I] pointer to an array of integers. (See NOTES.)
356 * RETURNS
357 * Success: TRUE
358 * Failure: FALSE
360 * NOTES
361 * The official documentation is incomplete!
362 * This is the correct documentation:
364 * hwnd
365 * Handle to the window that contains the menu and controls.
367 * uFlags
368 * Identifier of the menu item to receive or lose a check mark.
370 * lpInfo
371 * The array of integers contains pairs of values. BOTH values of
372 * the first pair must be the handles to the application's main menu.
373 * Each subsequent pair consists of a menu id and control id.
376 BOOL WINAPI
377 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
379 LPINT lpMenuId;
381 TRACE("%p, %lx, %p\n", hwnd, uFlags, lpInfo);
383 if (lpInfo == NULL)
384 return FALSE;
386 if (!(lpInfo[0]) || !(lpInfo[1]))
387 return FALSE;
389 /* search for control */
390 lpMenuId = &lpInfo[2];
391 while (*lpMenuId != uFlags)
392 lpMenuId += 2;
394 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
395 /* uncheck menu item */
396 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
398 /* hide control */
399 lpMenuId++;
400 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
401 SWP_HIDEWINDOW);
403 else {
404 /* check menu item */
405 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
407 /* show control */
408 lpMenuId++;
409 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
410 SWP_SHOWWINDOW);
413 return TRUE;
417 /***********************************************************************
418 * GetEffectiveClientRect [COMCTL32.4]
420 * Calculates the coordinates of a rectangle in the client area.
422 * PARAMS
423 * hwnd [I] handle to the client window.
424 * lpRect [O] pointer to the rectangle of the client window
425 * lpInfo [I] pointer to an array of integers (see NOTES)
427 * RETURNS
428 * No return value.
430 * NOTES
431 * The official documentation is incomplete!
432 * This is the correct documentation:
434 * lpInfo
435 * (will be written ...)
438 VOID WINAPI
439 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
441 RECT rcCtrl;
442 const INT *lpRun;
443 HWND hwndCtrl;
445 TRACE("(%p %p %p)\n",
446 hwnd, lpRect, lpInfo);
448 GetClientRect (hwnd, lpRect);
449 lpRun = lpInfo;
451 do {
452 lpRun += 2;
453 if (*lpRun == 0)
454 return;
455 lpRun++;
456 hwndCtrl = GetDlgItem (hwnd, *lpRun);
457 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
458 TRACE("control id 0x%x\n", *lpRun);
459 GetWindowRect (hwndCtrl, &rcCtrl);
460 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
461 SubtractRect (lpRect, lpRect, &rcCtrl);
463 lpRun++;
464 } while (*lpRun);
468 /***********************************************************************
469 * DrawStatusTextW [COMCTL32.@]
471 * Draws text with borders, like in a status bar.
473 * PARAMS
474 * hdc [I] handle to the window's display context
475 * lprc [I] pointer to a rectangle
476 * text [I] pointer to the text
477 * style [I] drawing style
479 * RETURNS
480 * No return value.
482 * NOTES
483 * The style variable can have one of the following values:
484 * (will be written ...)
487 void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
489 RECT r = *lprc;
490 UINT border = BDR_SUNKENOUTER;
491 COLORREF oldbkcolor;
493 if (style & SBT_POPOUT)
494 border = BDR_RAISEDOUTER;
495 else if (style & SBT_NOBORDERS)
496 border = 0;
498 oldbkcolor = SetBkColor (hdc, comctl32_color.clrBtnFace);
499 DrawEdge (hdc, &r, border, BF_MIDDLE|BF_RECT|BF_ADJUST);
501 /* now draw text */
502 if (text) {
503 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
504 COLORREF oldtextcolor;
505 UINT align = DT_LEFT;
506 int strCnt = 0;
508 oldtextcolor = SetTextColor (hdc, comctl32_color.clrBtnText);
509 if (style & SBT_RTLREADING)
510 FIXME("Unsupported RTL style!\n");
511 r.left += 3;
512 do {
513 if (*text == '\t') {
514 if (strCnt) {
515 DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
516 strCnt = 0;
518 if (align==DT_RIGHT) {
519 break;
521 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
522 } else {
523 strCnt++;
525 } while(*text++);
527 if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
528 SetBkMode (hdc, oldbkmode);
529 SetTextColor (hdc, oldtextcolor);
532 SetBkColor (hdc, oldbkcolor);
536 /***********************************************************************
537 * DrawStatusText [COMCTL32.@]
538 * DrawStatusTextA [COMCTL32.5]
540 * Draws text with borders, like in a status bar.
542 * PARAMS
543 * hdc [I] handle to the window's display context
544 * lprc [I] pointer to a rectangle
545 * text [I] pointer to the text
546 * style [I] drawing style
548 * RETURNS
549 * No return value.
552 void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
554 INT len;
555 LPWSTR textW = NULL;
557 if ( text ) {
558 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
559 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
560 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
563 DrawStatusTextW( hdc, lprc, textW, style );
564 Free( textW );
568 /***********************************************************************
569 * CreateStatusWindow [COMCTL32.@]
570 * CreateStatusWindowA [COMCTL32.6]
572 * Creates a status bar
574 * PARAMS
575 * style [I] window style
576 * text [I] pointer to the window text
577 * parent [I] handle to the parent window
578 * wid [I] control id of the status bar
580 * RETURNS
581 * Success: handle to the status window
582 * Failure: 0
585 HWND WINAPI
586 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
588 return CreateWindowA(STATUSCLASSNAMEA, text, style,
589 CW_USEDEFAULT, CW_USEDEFAULT,
590 CW_USEDEFAULT, CW_USEDEFAULT,
591 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
595 /***********************************************************************
596 * CreateStatusWindowW [COMCTL32.@]
598 * Creates a status bar control
600 * PARAMS
601 * style [I] window style
602 * text [I] pointer to the window text
603 * parent [I] handle to the parent window
604 * wid [I] control id of the status bar
606 * RETURNS
607 * Success: handle to the status window
608 * Failure: 0
611 HWND WINAPI
612 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
614 return CreateWindowW(STATUSCLASSNAMEW, text, style,
615 CW_USEDEFAULT, CW_USEDEFAULT,
616 CW_USEDEFAULT, CW_USEDEFAULT,
617 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
621 /***********************************************************************
622 * CreateUpDownControl [COMCTL32.16]
624 * Creates an up-down control
626 * PARAMS
627 * style [I] window styles
628 * x [I] horizontal position of the control
629 * y [I] vertical position of the control
630 * cx [I] with of the control
631 * cy [I] height of the control
632 * parent [I] handle to the parent window
633 * id [I] the control's identifier
634 * inst [I] handle to the application's module instance
635 * buddy [I] handle to the buddy window, can be NULL
636 * maxVal [I] upper limit of the control
637 * minVal [I] lower limit of the control
638 * curVal [I] current value of the control
640 * RETURNS
641 * Success: handle to the updown control
642 * Failure: 0
645 HWND WINAPI
646 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
647 HWND parent, INT id, HINSTANCE inst,
648 HWND buddy, INT maxVal, INT minVal, INT curVal)
650 HWND hUD =
651 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
652 parent, (HMENU)(DWORD_PTR)id, inst, 0);
653 if (hUD) {
654 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
655 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
656 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
659 return hUD;
663 /***********************************************************************
664 * InitCommonControls [COMCTL32.17]
666 * Registers the common controls.
668 * PARAMS
669 * No parameters.
671 * RETURNS
672 * No return values.
674 * NOTES
675 * This function is just a dummy - all the controls are registered at
676 * the DLL initialization time. See InitCommonControlsEx for details.
679 VOID WINAPI
680 InitCommonControls (void)
685 /***********************************************************************
686 * InitCommonControlsEx [COMCTL32.@]
688 * Registers the common controls.
690 * PARAMS
691 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
693 * RETURNS
694 * Success: TRUE
695 * Failure: FALSE
697 * NOTES
698 * Probably all versions of comctl32 initializes the Win95 controls in DllMain
699 * during DLL initialization. Starting from comctl32 v5.82 all the controls
700 * are initialized there. We follow this behaviour and this function is just
701 * a dummy.
703 * Note: when writing programs under Windows, if you don't call any function
704 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
705 * was the only comctl32 function you were calling and you remove it you may
706 * have a false impression that InitCommonControlsEx actually did something.
709 BOOL WINAPI
710 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
712 if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
713 return FALSE;
715 TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
716 return TRUE;
720 /***********************************************************************
721 * CreateToolbarEx [COMCTL32.@]
723 * Creates a toolbar window.
725 * PARAMS
726 * hwnd
727 * style
728 * wID
729 * nBitmaps
730 * hBMInst
731 * wBMID
732 * lpButtons
733 * iNumButtons
734 * dxButton
735 * dyButton
736 * dxBitmap
737 * dyBitmap
738 * uStructSize
740 * RETURNS
741 * Success: handle to the tool bar control
742 * Failure: 0
745 HWND WINAPI
746 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
747 HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
748 INT iNumButtons, INT dxButton, INT dyButton,
749 INT dxBitmap, INT dyBitmap, UINT uStructSize)
751 HWND hwndTB;
753 hwndTB =
754 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
755 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
756 if(hwndTB) {
757 TBADDBITMAP tbab;
759 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
761 /* set bitmap and button size */
762 /*If CreateToolbarEx receives 0, windows sets default values*/
763 if (dxBitmap < 0)
764 dxBitmap = 16;
765 if (dyBitmap < 0)
766 dyBitmap = 16;
767 if (dxBitmap == 0 || dyBitmap == 0)
768 dxBitmap = dyBitmap = 16;
769 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
771 if (dxButton < 0)
772 dxButton = dxBitmap;
773 if (dyButton < 0)
774 dyButton = dyBitmap;
775 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
776 if (dxButton != 0 && dyButton != 0)
777 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
780 /* add bitmaps */
781 if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
783 tbab.hInst = hBMInst;
784 tbab.nID = wBMID;
786 SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
788 /* add buttons */
789 if(iNumButtons > 0)
790 SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
793 return hwndTB;
797 /***********************************************************************
798 * CreateMappedBitmap [COMCTL32.8]
800 * Loads a bitmap resource using a colour map.
802 * PARAMS
803 * hInstance [I] Handle to the module containing the bitmap.
804 * idBitmap [I] The bitmap resource ID.
805 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
806 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
807 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
809 * RETURNS
810 * Success: handle to the new bitmap
811 * Failure: 0
814 HBITMAP WINAPI
815 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
816 LPCOLORMAP lpColorMap, INT iNumMaps)
818 HGLOBAL hglb;
819 HRSRC hRsrc;
820 const BITMAPINFOHEADER *lpBitmap;
821 LPBITMAPINFOHEADER lpBitmapInfo;
822 UINT nSize, nColorTableSize, iColor;
823 RGBQUAD *pColorTable;
824 INT i, iMaps, nWidth, nHeight;
825 HDC hdcScreen;
826 HBITMAP hbm;
827 LPCOLORMAP sysColorMap;
828 COLORREF cRef;
829 COLORMAP internalColorMap[4] =
830 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
832 /* initialize pointer to colortable and default color table */
833 if (lpColorMap) {
834 iMaps = iNumMaps;
835 sysColorMap = lpColorMap;
837 else {
838 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
839 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
840 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
841 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
842 iMaps = 4;
843 sysColorMap = internalColorMap;
846 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
847 if (hRsrc == 0)
848 return 0;
849 hglb = LoadResource (hInstance, hRsrc);
850 if (hglb == 0)
851 return 0;
852 lpBitmap = LockResource (hglb);
853 if (lpBitmap == NULL)
854 return 0;
856 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
857 nColorTableSize = lpBitmap->biClrUsed;
858 else if (lpBitmap->biBitCount <= 8)
859 nColorTableSize = (1 << lpBitmap->biBitCount);
860 else
861 nColorTableSize = 0;
862 nSize = lpBitmap->biSize;
863 if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
864 nSize += 3 * sizeof(DWORD);
865 nSize += nColorTableSize * sizeof(RGBQUAD);
866 lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
867 if (lpBitmapInfo == NULL)
868 return 0;
869 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
871 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
873 for (iColor = 0; iColor < nColorTableSize; iColor++) {
874 for (i = 0; i < iMaps; i++) {
875 cRef = RGB(pColorTable[iColor].rgbRed,
876 pColorTable[iColor].rgbGreen,
877 pColorTable[iColor].rgbBlue);
878 if ( cRef == sysColorMap[i].from) {
879 #if 0
880 if (wFlags & CBS_MASKED) {
881 if (sysColorMap[i].to != COLOR_BTNTEXT)
882 pColorTable[iColor] = RGB(255, 255, 255);
884 else
885 #endif
886 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
887 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
888 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
889 break;
893 nWidth = lpBitmapInfo->biWidth;
894 nHeight = lpBitmapInfo->biHeight;
895 hdcScreen = GetDC (NULL);
896 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
897 if (hbm) {
898 HDC hdcDst = CreateCompatibleDC (hdcScreen);
899 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
900 const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
901 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
902 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
903 SRCCOPY);
904 SelectObject (hdcDst, hbmOld);
905 DeleteDC (hdcDst);
907 ReleaseDC (NULL, hdcScreen);
908 GlobalFree (lpBitmapInfo);
909 FreeResource (hglb);
911 return hbm;
915 /***********************************************************************
916 * CreateToolbar [COMCTL32.7]
918 * Creates a toolbar control.
920 * PARAMS
921 * hwnd
922 * style
923 * wID
924 * nBitmaps
925 * hBMInst
926 * wBMID
927 * lpButtons
928 * iNumButtons
930 * RETURNS
931 * Success: handle to the tool bar control
932 * Failure: 0
934 * NOTES
935 * Do not use this function anymore. Use CreateToolbarEx instead.
938 HWND WINAPI
939 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
940 HINSTANCE hBMInst, UINT wBMID,
941 LPCTBBUTTON lpButtons,INT iNumButtons)
943 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
944 hBMInst, wBMID, lpButtons,
945 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
949 /***********************************************************************
950 * DllGetVersion [COMCTL32.@]
952 * Retrieves version information of the 'COMCTL32.DLL'
954 * PARAMS
955 * pdvi [O] pointer to version information structure.
957 * RETURNS
958 * Success: S_OK
959 * Failure: E_INVALIDARG
961 * NOTES
962 * Returns version of a comctl32.dll from IE4.01 SP1.
965 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
967 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
968 WARN("wrong DLLVERSIONINFO size from app\n");
969 return E_INVALIDARG;
972 pdvi->dwMajorVersion = COMCTL32_VERSION;
973 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
974 pdvi->dwBuildNumber = 2919;
975 pdvi->dwPlatformID = 6304;
977 TRACE("%u.%u.%u.%u\n",
978 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, %lx, %lx)\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 if (IsWindowUnicode (hWnd))
1107 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1108 (DWORD_PTR)COMCTL32_SubclassProc);
1109 else
1110 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1111 (DWORD_PTR)COMCTL32_SubclassProc);
1113 else {
1114 /* Check to see if we have called this function with the same uIDSubClass
1115 * and pfnSubclass */
1116 proc = stack->SubclassProcs;
1117 while (proc) {
1118 if ((proc->id == uIDSubclass) &&
1119 (proc->subproc == pfnSubclass)) {
1120 proc->ref = dwRef;
1121 return TRUE;
1123 proc = proc->next;
1127 proc = Alloc(sizeof(SUBCLASSPROCS));
1128 if (!proc) {
1129 ERR ("Failed to allocate subclass entry in stack\n");
1130 if (IsWindowUnicode (hWnd))
1131 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1132 else
1133 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1134 Free (stack);
1135 RemovePropW( hWnd, COMCTL32_wSubclass );
1136 return FALSE;
1139 proc->subproc = pfnSubclass;
1140 proc->ref = dwRef;
1141 proc->id = uIDSubclass;
1142 proc->next = stack->SubclassProcs;
1143 stack->SubclassProcs = proc;
1145 return TRUE;
1149 /***********************************************************************
1150 * GetWindowSubclass [COMCTL32.411]
1152 * Gets the Reference data from a subclass.
1154 * PARAMS
1155 * hWnd [in] Handle to the window which we are subclassing
1156 * pfnSubclass [in] Pointer to the subclass procedure
1157 * uID [in] Unique identifier of the subclassing procedure
1158 * pdwRef [out] Pointer to the reference data
1160 * RETURNS
1161 * Success: Non-zero
1162 * Failure: 0
1165 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1166 UINT_PTR uID, DWORD_PTR *pdwRef)
1168 const SUBCLASS_INFO *stack;
1169 const SUBCLASSPROCS *proc;
1171 TRACE ("(%p, %p, %lx, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1173 /* See if we have been called for this window */
1174 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1175 if (!stack)
1176 return FALSE;
1178 proc = stack->SubclassProcs;
1179 while (proc) {
1180 if ((proc->id == uID) &&
1181 (proc->subproc == pfnSubclass)) {
1182 *pdwRef = proc->ref;
1183 return TRUE;
1185 proc = proc->next;
1188 return FALSE;
1192 /***********************************************************************
1193 * RemoveWindowSubclass [COMCTL32.412]
1195 * Removes a window subclass.
1197 * PARAMS
1198 * hWnd [in] Handle to the window which we are subclassing
1199 * pfnSubclass [in] Pointer to the subclass procedure
1200 * uID [in] Unique identifier of this subclass
1202 * RETURNS
1203 * Success: non-zero
1204 * Failure: zero
1207 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1209 LPSUBCLASS_INFO stack;
1210 LPSUBCLASSPROCS prevproc = NULL;
1211 LPSUBCLASSPROCS proc;
1212 BOOL ret = FALSE;
1214 TRACE ("(%p, %p, %lx)\n", hWnd, pfnSubclass, uID);
1216 /* Find the Subclass to remove */
1217 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1218 if (!stack)
1219 return FALSE;
1221 proc = stack->SubclassProcs;
1222 while (proc) {
1223 if ((proc->id == uID) &&
1224 (proc->subproc == pfnSubclass)) {
1226 if (!prevproc)
1227 stack->SubclassProcs = proc->next;
1228 else
1229 prevproc->next = proc->next;
1231 if (stack->stackpos == proc)
1232 stack->stackpos = stack->stackpos->next;
1234 Free (proc);
1235 ret = TRUE;
1236 break;
1238 prevproc = proc;
1239 proc = proc->next;
1242 if (!stack->SubclassProcs && !stack->running) {
1243 TRACE("Last Subclass removed, cleaning up\n");
1244 /* clean up our heap and reset the original window procedure */
1245 if (IsWindowUnicode (hWnd))
1246 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1247 else
1248 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1249 Free (stack);
1250 RemovePropW( hWnd, COMCTL32_wSubclass );
1253 return ret;
1256 /***********************************************************************
1257 * COMCTL32_SubclassProc (internal)
1259 * Window procedure for all subclassed windows.
1260 * Saves the current subclassing stack position to support nested messages
1262 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1264 LPSUBCLASS_INFO stack;
1265 LPSUBCLASSPROCS proc;
1266 LRESULT ret;
1268 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1270 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1271 if (!stack) {
1272 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1273 return 0;
1276 /* Save our old stackpos to properly handle nested messages */
1277 proc = stack->stackpos;
1278 stack->stackpos = stack->SubclassProcs;
1279 stack->running++;
1280 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1281 stack->running--;
1282 stack->stackpos = proc;
1284 if (!stack->SubclassProcs && !stack->running) {
1285 TRACE("Last Subclass removed, cleaning up\n");
1286 /* clean up our heap and reset the original window procedure */
1287 if (IsWindowUnicode (hWnd))
1288 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1289 else
1290 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1291 Free (stack);
1292 RemovePropW( hWnd, COMCTL32_wSubclass );
1294 return ret;
1297 /***********************************************************************
1298 * DefSubclassProc [COMCTL32.413]
1300 * Calls the next window procedure (i.e. the one before this subclass)
1302 * PARAMS
1303 * hWnd [in] The window that we're subclassing
1304 * uMsg [in] Message
1305 * wParam [in] WPARAM
1306 * lParam [in] LPARAM
1308 * RETURNS
1309 * Success: non-zero
1310 * Failure: zero
1313 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1315 LPSUBCLASS_INFO stack;
1316 LRESULT ret;
1318 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1320 /* retrieve our little stack from the Properties */
1321 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1322 if (!stack) {
1323 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1324 return 0;
1327 /* If we are at the end of stack then we have to call the original
1328 * window procedure */
1329 if (!stack->stackpos) {
1330 if (IsWindowUnicode (hWnd))
1331 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1332 else
1333 ret = CallWindowProcA (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, 0x%08x, 0x%08x, 0x%08x, %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=%d\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, %d, %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, %d) 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("(%u %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 = %d\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("(%u %u %x %p %s %p): Current Size = %d\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, %d): 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, %d): 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, %#x.\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 %#x)\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);