ntoskrnl.exe: Reimplement KeSetTimerEx() on top of thread pool.
[wine.git] / dlls / comctl32 / commctrl.c
blob744188a64a14a51c997423eb297e4a7db468c3b3
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[] = {
97 'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
100 static void unregister_versioned_classes(void)
102 #define VERSION "6.0.2600.2982!"
103 static const char *classes[] =
105 VERSION WC_BUTTONA,
106 VERSION WC_COMBOBOXA,
107 VERSION "ComboLBox",
108 VERSION WC_EDITA,
109 VERSION WC_LISTBOXA,
110 VERSION WC_STATICA,
112 int i;
114 for (i = 0; i < ARRAY_SIZE(classes); i++)
115 UnregisterClassA(classes[i], NULL);
117 #undef VERSION
120 BOOL WINAPI RegisterClassNameW(const WCHAR *class)
122 static const struct
124 const WCHAR nameW[16];
125 void (*fn_register)(void);
127 classes[] =
129 { {'B','u','t','t','o','n',0}, BUTTON_Register },
130 { {'C','o','m','b','o','B','o','x',0}, COMBO_Register },
131 { {'C','o','m','b','o','L','B','o','x',0}, COMBOLBOX_Register },
132 { {'E','d','i','t',0}, EDIT_Register },
133 { {'L','i','s','t','B','o','x',0}, LISTBOX_Register },
134 { {'S','t','a','t','i','c',0}, STATIC_Register },
137 int min = 0, max = ARRAY_SIZE(classes) - 1;
139 while (min <= max)
141 int res, pos = (min + max) / 2;
142 if (!(res = wcsicmp(class, classes[pos].nameW)))
144 classes[pos].fn_register();
145 return TRUE;
147 if (res < 0) max = pos - 1;
148 else min = pos + 1;
151 return FALSE;
154 /***********************************************************************
155 * DllMain [Internal]
157 * Initializes the internal 'COMCTL32.DLL'.
159 * PARAMS
160 * hinstDLL [I] handle to the 'dlls' instance
161 * fdwReason [I]
162 * lpvReserved [I] reserved, must be NULL
164 * RETURNS
165 * Success: TRUE
166 * Failure: FALSE
169 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
171 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
173 switch (fdwReason) {
174 case DLL_PROCESS_ATTACH:
175 DisableThreadLibraryCalls(hinstDLL);
177 COMCTL32_hModule = hinstDLL;
179 /* add global subclassing atom (used by 'tooltip' and 'updown') */
180 COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
181 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
183 /* create local pattern brush */
184 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
185 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
187 /* Get all the colors at DLL load */
188 COMCTL32_RefreshSysColors();
190 /* like comctl32 5.82+ register all the common control classes */
191 ANIMATE_Register ();
192 COMBOEX_Register ();
193 DATETIME_Register ();
194 FLATSB_Register ();
195 HEADER_Register ();
196 HOTKEY_Register ();
197 IPADDRESS_Register ();
198 LISTVIEW_Register ();
199 MONTHCAL_Register ();
200 NATIVEFONT_Register ();
201 PAGER_Register ();
202 PROGRESS_Register ();
203 REBAR_Register ();
204 STATUS_Register ();
205 SYSLINK_Register ();
206 TAB_Register ();
207 TOOLBAR_Register ();
208 TOOLTIPS_Register ();
209 TRACKBAR_Register ();
210 TREEVIEW_Register ();
211 UPDOWN_Register ();
213 /* subclass user32 controls */
214 THEMING_Initialize ();
215 break;
217 case DLL_PROCESS_DETACH:
218 if (lpvReserved) break;
219 /* clean up subclassing */
220 THEMING_Uninitialize();
222 /* unregister all common control classes */
223 ANIMATE_Unregister ();
224 COMBOEX_Unregister ();
225 DATETIME_Unregister ();
226 FLATSB_Unregister ();
227 HEADER_Unregister ();
228 HOTKEY_Unregister ();
229 IPADDRESS_Unregister ();
230 LISTVIEW_Unregister ();
231 MONTHCAL_Unregister ();
232 NATIVEFONT_Unregister ();
233 PAGER_Unregister ();
234 PROGRESS_Unregister ();
235 REBAR_Unregister ();
236 STATUS_Unregister ();
237 SYSLINK_Unregister ();
238 TAB_Unregister ();
239 TOOLBAR_Unregister ();
240 TOOLTIPS_Unregister ();
241 TRACKBAR_Unregister ();
242 TREEVIEW_Unregister ();
243 UPDOWN_Unregister ();
245 unregister_versioned_classes ();
247 /* delete local pattern brush */
248 DeleteObject (COMCTL32_hPattern55AABrush);
249 DeleteObject (COMCTL32_hPattern55AABitmap);
251 /* delete global subclassing atom */
252 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
253 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
254 break;
257 return TRUE;
261 /***********************************************************************
262 * MenuHelp [COMCTL32.2]
264 * Handles the setting of status bar help messages when the user
265 * selects menu items.
267 * PARAMS
268 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
269 * wParam [I] wParam of the message uMsg
270 * lParam [I] lParam of the message uMsg
271 * hMainMenu [I] handle to the application's main menu
272 * hInst [I] handle to the module that contains string resources
273 * hwndStatus [I] handle to the status bar window
274 * lpwIDs [I] pointer to an array of integers (see NOTES)
276 * RETURNS
277 * No return value
279 * NOTES
280 * The official documentation is incomplete!
281 * This is the correct documentation:
283 * uMsg:
284 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
285 * WM_MENUSELECT messages.
287 * lpwIDs:
288 * (will be written ...)
291 VOID WINAPI
292 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
293 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
295 UINT uMenuID = 0;
297 if (!IsWindow (hwndStatus))
298 return;
300 switch (uMsg) {
301 case WM_MENUSELECT:
302 TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
303 wParam, lParam);
305 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
306 /* menu was closed */
307 TRACE("menu was closed!\n");
308 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
310 else {
311 /* menu item was selected */
312 if (HIWORD(wParam) & MF_POPUP)
313 uMenuID = *(lpwIDs+1);
314 else
315 uMenuID = (UINT)LOWORD(wParam);
316 TRACE("uMenuID = %u\n", uMenuID);
318 if (uMenuID) {
319 WCHAR szText[256];
321 if (!LoadStringW (hInst, uMenuID, szText, ARRAY_SIZE(szText)))
322 szText[0] = '\0';
324 SendMessageW (hwndStatus, SB_SETTEXTW,
325 255 | SBT_NOBORDERS, (LPARAM)szText);
326 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
329 break;
331 case WM_COMMAND :
332 TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
333 wParam, lParam);
334 /* WM_COMMAND is not invalid since it is documented
335 * in the windows api reference. So don't output
336 * any FIXME for WM_COMMAND
338 WARN("We don't care about the WM_COMMAND\n");
339 break;
341 default:
342 FIXME("Invalid Message 0x%x!\n", uMsg);
343 break;
348 /***********************************************************************
349 * ShowHideMenuCtl [COMCTL32.3]
351 * Shows or hides controls and updates the corresponding menu item.
353 * PARAMS
354 * hwnd [I] handle to the client window.
355 * uFlags [I] menu command id.
356 * lpInfo [I] pointer to an array of integers. (See NOTES.)
358 * RETURNS
359 * Success: TRUE
360 * Failure: FALSE
362 * NOTES
363 * The official documentation is incomplete!
364 * This is the correct documentation:
366 * hwnd
367 * Handle to the window that contains the menu and controls.
369 * uFlags
370 * Identifier of the menu item to receive or lose a check mark.
372 * lpInfo
373 * The array of integers contains pairs of values. BOTH values of
374 * the first pair must be the handles to the application's main menu.
375 * Each subsequent pair consists of a menu id and control id.
378 BOOL WINAPI
379 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
381 LPINT lpMenuId;
383 TRACE("%p, %lx, %p\n", hwnd, uFlags, lpInfo);
385 if (lpInfo == NULL)
386 return FALSE;
388 if (!(lpInfo[0]) || !(lpInfo[1]))
389 return FALSE;
391 /* search for control */
392 lpMenuId = &lpInfo[2];
393 while (*lpMenuId != uFlags)
394 lpMenuId += 2;
396 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
397 /* uncheck menu item */
398 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
400 /* hide control */
401 lpMenuId++;
402 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
403 SWP_HIDEWINDOW);
405 else {
406 /* check menu item */
407 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
409 /* show control */
410 lpMenuId++;
411 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
412 SWP_SHOWWINDOW);
415 return TRUE;
419 /***********************************************************************
420 * GetEffectiveClientRect [COMCTL32.4]
422 * Calculates the coordinates of a rectangle in the client area.
424 * PARAMS
425 * hwnd [I] handle to the client window.
426 * lpRect [O] pointer to the rectangle of the client window
427 * lpInfo [I] pointer to an array of integers (see NOTES)
429 * RETURNS
430 * No return value.
432 * NOTES
433 * The official documentation is incomplete!
434 * This is the correct documentation:
436 * lpInfo
437 * (will be written ...)
440 VOID WINAPI
441 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
443 RECT rcCtrl;
444 const INT *lpRun;
445 HWND hwndCtrl;
447 TRACE("(%p %p %p)\n",
448 hwnd, lpRect, lpInfo);
450 GetClientRect (hwnd, lpRect);
451 lpRun = lpInfo;
453 do {
454 lpRun += 2;
455 if (*lpRun == 0)
456 return;
457 lpRun++;
458 hwndCtrl = GetDlgItem (hwnd, *lpRun);
459 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
460 TRACE("control id 0x%x\n", *lpRun);
461 GetWindowRect (hwndCtrl, &rcCtrl);
462 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
463 SubtractRect (lpRect, lpRect, &rcCtrl);
465 lpRun++;
466 } while (*lpRun);
470 /***********************************************************************
471 * DrawStatusTextW [COMCTL32.@]
473 * Draws text with borders, like in a status bar.
475 * PARAMS
476 * hdc [I] handle to the window's display context
477 * lprc [I] pointer to a rectangle
478 * text [I] pointer to the text
479 * style [I] drawing style
481 * RETURNS
482 * No return value.
484 * NOTES
485 * The style variable can have one of the following values:
486 * (will be written ...)
489 void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
491 RECT r = *lprc;
492 UINT border = BDR_SUNKENOUTER;
493 COLORREF oldbkcolor;
495 if (style & SBT_POPOUT)
496 border = BDR_RAISEDOUTER;
497 else if (style & SBT_NOBORDERS)
498 border = 0;
500 oldbkcolor = SetBkColor (hdc, comctl32_color.clrBtnFace);
501 DrawEdge (hdc, &r, border, BF_MIDDLE|BF_RECT|BF_ADJUST);
503 /* now draw text */
504 if (text) {
505 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
506 COLORREF oldtextcolor;
507 UINT align = DT_LEFT;
508 int strCnt = 0;
510 oldtextcolor = SetTextColor (hdc, comctl32_color.clrBtnText);
511 if (style & SBT_RTLREADING)
512 FIXME("Unsupported RTL style!\n");
513 r.left += 3;
514 do {
515 if (*text == '\t') {
516 if (strCnt) {
517 DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
518 strCnt = 0;
520 if (align==DT_RIGHT) {
521 break;
523 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
524 } else {
525 strCnt++;
527 } while(*text++);
529 if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
530 SetBkMode (hdc, oldbkmode);
531 SetTextColor (hdc, oldtextcolor);
534 SetBkColor (hdc, oldbkcolor);
538 /***********************************************************************
539 * DrawStatusText [COMCTL32.@]
540 * DrawStatusTextA [COMCTL32.5]
542 * Draws text with borders, like in a status bar.
544 * PARAMS
545 * hdc [I] handle to the window's display context
546 * lprc [I] pointer to a rectangle
547 * text [I] pointer to the text
548 * style [I] drawing style
550 * RETURNS
551 * No return value.
554 void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
556 INT len;
557 LPWSTR textW = NULL;
559 if ( text ) {
560 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
561 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
562 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
565 DrawStatusTextW( hdc, lprc, textW, style );
566 Free( textW );
570 /***********************************************************************
571 * CreateStatusWindow [COMCTL32.@]
572 * CreateStatusWindowA [COMCTL32.6]
574 * Creates a status bar
576 * PARAMS
577 * style [I] window style
578 * text [I] pointer to the window text
579 * parent [I] handle to the parent window
580 * wid [I] control id of the status bar
582 * RETURNS
583 * Success: handle to the status window
584 * Failure: 0
587 HWND WINAPI
588 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
590 return CreateWindowA(STATUSCLASSNAMEA, text, style,
591 CW_USEDEFAULT, CW_USEDEFAULT,
592 CW_USEDEFAULT, CW_USEDEFAULT,
593 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
597 /***********************************************************************
598 * CreateStatusWindowW [COMCTL32.@]
600 * Creates a status bar control
602 * PARAMS
603 * style [I] window style
604 * text [I] pointer to the window text
605 * parent [I] handle to the parent window
606 * wid [I] control id of the status bar
608 * RETURNS
609 * Success: handle to the status window
610 * Failure: 0
613 HWND WINAPI
614 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
616 return CreateWindowW(STATUSCLASSNAMEW, text, style,
617 CW_USEDEFAULT, CW_USEDEFAULT,
618 CW_USEDEFAULT, CW_USEDEFAULT,
619 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
623 /***********************************************************************
624 * CreateUpDownControl [COMCTL32.16]
626 * Creates an up-down control
628 * PARAMS
629 * style [I] window styles
630 * x [I] horizontal position of the control
631 * y [I] vertical position of the control
632 * cx [I] with of the control
633 * cy [I] height of the control
634 * parent [I] handle to the parent window
635 * id [I] the control's identifier
636 * inst [I] handle to the application's module instance
637 * buddy [I] handle to the buddy window, can be NULL
638 * maxVal [I] upper limit of the control
639 * minVal [I] lower limit of the control
640 * curVal [I] current value of the control
642 * RETURNS
643 * Success: handle to the updown control
644 * Failure: 0
647 HWND WINAPI
648 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
649 HWND parent, INT id, HINSTANCE inst,
650 HWND buddy, INT maxVal, INT minVal, INT curVal)
652 HWND hUD =
653 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
654 parent, (HMENU)(DWORD_PTR)id, inst, 0);
655 if (hUD) {
656 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
657 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
658 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
661 return hUD;
665 /***********************************************************************
666 * InitCommonControls [COMCTL32.17]
668 * Registers the common controls.
670 * PARAMS
671 * No parameters.
673 * RETURNS
674 * No return values.
676 * NOTES
677 * This function is just a dummy - all the controls are registered at
678 * the DLL initialization time. See InitCommonControlsEx for details.
681 VOID WINAPI
682 InitCommonControls (void)
687 /***********************************************************************
688 * InitCommonControlsEx [COMCTL32.@]
690 * Registers the common controls.
692 * PARAMS
693 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
695 * RETURNS
696 * Success: TRUE
697 * Failure: FALSE
699 * NOTES
700 * Probably all versions of comctl32 initializes the Win95 controls in DllMain
701 * during DLL initialization. Starting from comctl32 v5.82 all the controls
702 * are initialized there. We follow this behaviour and this function is just
703 * a dummy.
705 * Note: when writing programs under Windows, if you don't call any function
706 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
707 * was the only comctl32 function you were calling and you remove it you may
708 * have a false impression that InitCommonControlsEx actually did something.
711 BOOL WINAPI
712 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
714 if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
715 return FALSE;
717 TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
718 return TRUE;
722 /***********************************************************************
723 * CreateToolbarEx [COMCTL32.@]
725 * Creates a toolbar window.
727 * PARAMS
728 * hwnd
729 * style
730 * wID
731 * nBitmaps
732 * hBMInst
733 * wBMID
734 * lpButtons
735 * iNumButtons
736 * dxButton
737 * dyButton
738 * dxBitmap
739 * dyBitmap
740 * uStructSize
742 * RETURNS
743 * Success: handle to the tool bar control
744 * Failure: 0
747 HWND WINAPI
748 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
749 HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
750 INT iNumButtons, INT dxButton, INT dyButton,
751 INT dxBitmap, INT dyBitmap, UINT uStructSize)
753 HWND hwndTB;
755 hwndTB =
756 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
757 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
758 if(hwndTB) {
759 TBADDBITMAP tbab;
761 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
763 /* set bitmap and button size */
764 /*If CreateToolbarEx receives 0, windows sets default values*/
765 if (dxBitmap < 0)
766 dxBitmap = 16;
767 if (dyBitmap < 0)
768 dyBitmap = 16;
769 if (dxBitmap == 0 || dyBitmap == 0)
770 dxBitmap = dyBitmap = 16;
771 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
773 if (dxButton < 0)
774 dxButton = dxBitmap;
775 if (dyButton < 0)
776 dyButton = dyBitmap;
777 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
778 if (dxButton != 0 && dyButton != 0)
779 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
782 /* add bitmaps */
783 if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
785 tbab.hInst = hBMInst;
786 tbab.nID = wBMID;
788 SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
790 /* add buttons */
791 if(iNumButtons > 0)
792 SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
795 return hwndTB;
799 /***********************************************************************
800 * CreateMappedBitmap [COMCTL32.8]
802 * Loads a bitmap resource using a colour map.
804 * PARAMS
805 * hInstance [I] Handle to the module containing the bitmap.
806 * idBitmap [I] The bitmap resource ID.
807 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
808 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
809 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
811 * RETURNS
812 * Success: handle to the new bitmap
813 * Failure: 0
816 HBITMAP WINAPI
817 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
818 LPCOLORMAP lpColorMap, INT iNumMaps)
820 HGLOBAL hglb;
821 HRSRC hRsrc;
822 const BITMAPINFOHEADER *lpBitmap;
823 LPBITMAPINFOHEADER lpBitmapInfo;
824 UINT nSize, nColorTableSize, iColor;
825 RGBQUAD *pColorTable;
826 INT i, iMaps, nWidth, nHeight;
827 HDC hdcScreen;
828 HBITMAP hbm;
829 LPCOLORMAP sysColorMap;
830 COLORREF cRef;
831 COLORMAP internalColorMap[4] =
832 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
834 /* initialize pointer to colortable and default color table */
835 if (lpColorMap) {
836 iMaps = iNumMaps;
837 sysColorMap = lpColorMap;
839 else {
840 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
841 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
842 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
843 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
844 iMaps = 4;
845 sysColorMap = internalColorMap;
848 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
849 if (hRsrc == 0)
850 return 0;
851 hglb = LoadResource (hInstance, hRsrc);
852 if (hglb == 0)
853 return 0;
854 lpBitmap = LockResource (hglb);
855 if (lpBitmap == NULL)
856 return 0;
858 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
859 nColorTableSize = lpBitmap->biClrUsed;
860 else if (lpBitmap->biBitCount <= 8)
861 nColorTableSize = (1 << lpBitmap->biBitCount);
862 else
863 nColorTableSize = 0;
864 nSize = lpBitmap->biSize;
865 if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
866 nSize += 3 * sizeof(DWORD);
867 nSize += nColorTableSize * sizeof(RGBQUAD);
868 lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
869 if (lpBitmapInfo == NULL)
870 return 0;
871 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
873 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
875 for (iColor = 0; iColor < nColorTableSize; iColor++) {
876 for (i = 0; i < iMaps; i++) {
877 cRef = RGB(pColorTable[iColor].rgbRed,
878 pColorTable[iColor].rgbGreen,
879 pColorTable[iColor].rgbBlue);
880 if ( cRef == sysColorMap[i].from) {
881 #if 0
882 if (wFlags & CBS_MASKED) {
883 if (sysColorMap[i].to != COLOR_BTNTEXT)
884 pColorTable[iColor] = RGB(255, 255, 255);
886 else
887 #endif
888 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
889 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
890 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
891 break;
895 nWidth = lpBitmapInfo->biWidth;
896 nHeight = lpBitmapInfo->biHeight;
897 hdcScreen = GetDC (NULL);
898 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
899 if (hbm) {
900 HDC hdcDst = CreateCompatibleDC (hdcScreen);
901 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
902 const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
903 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
904 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
905 SRCCOPY);
906 SelectObject (hdcDst, hbmOld);
907 DeleteDC (hdcDst);
909 ReleaseDC (NULL, hdcScreen);
910 GlobalFree (lpBitmapInfo);
911 FreeResource (hglb);
913 return hbm;
917 /***********************************************************************
918 * CreateToolbar [COMCTL32.7]
920 * Creates a toolbar control.
922 * PARAMS
923 * hwnd
924 * style
925 * wID
926 * nBitmaps
927 * hBMInst
928 * wBMID
929 * lpButtons
930 * iNumButtons
932 * RETURNS
933 * Success: handle to the tool bar control
934 * Failure: 0
936 * NOTES
937 * Do not use this function anymore. Use CreateToolbarEx instead.
940 HWND WINAPI
941 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
942 HINSTANCE hBMInst, UINT wBMID,
943 LPCTBBUTTON lpButtons,INT iNumButtons)
945 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
946 hBMInst, wBMID, lpButtons,
947 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
951 /***********************************************************************
952 * DllGetVersion [COMCTL32.@]
954 * Retrieves version information of the 'COMCTL32.DLL'
956 * PARAMS
957 * pdvi [O] pointer to version information structure.
959 * RETURNS
960 * Success: S_OK
961 * Failure: E_INVALIDARG
963 * NOTES
964 * Returns version of a comctl32.dll from IE4.01 SP1.
967 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
969 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
970 WARN("wrong DLLVERSIONINFO size from app\n");
971 return E_INVALIDARG;
974 pdvi->dwMajorVersion = COMCTL32_VERSION;
975 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
976 pdvi->dwBuildNumber = 2919;
977 pdvi->dwPlatformID = 6304;
979 TRACE("%u.%u.%u.%u\n",
980 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
981 pdvi->dwBuildNumber, pdvi->dwPlatformID);
983 return S_OK;
986 /***********************************************************************
987 * DllInstall (COMCTL32.@)
989 * Installs the ComCtl32 DLL.
991 * RETURNS
992 * Success: S_OK
993 * Failure: A HRESULT error
995 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
997 TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
998 return S_OK;
1001 /***********************************************************************
1002 * _TrackMouseEvent [COMCTL32.@]
1004 * Requests notification of mouse events
1006 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1007 * to the hwnd specified in the ptme structure. After the event message
1008 * is posted to the hwnd, the entry in the queue is removed.
1010 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1011 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1012 * immediately and the TME_LEAVE flag being ignored.
1014 * PARAMS
1015 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1017 * RETURNS
1018 * Success: non-zero
1019 * Failure: zero
1021 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1025 BOOL WINAPI
1026 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1028 return TrackMouseEvent (ptme);
1031 /*************************************************************************
1032 * GetMUILanguage [COMCTL32.@]
1034 * Returns the user interface language in use by the current process.
1036 * RETURNS
1037 * Language ID in use by the current process.
1039 LANGID WINAPI GetMUILanguage (VOID)
1041 return COMCTL32_uiLang;
1045 /*************************************************************************
1046 * InitMUILanguage [COMCTL32.@]
1048 * Sets the user interface language to be used by the current process.
1050 * RETURNS
1051 * Nothing.
1053 VOID WINAPI InitMUILanguage (LANGID uiLang)
1055 COMCTL32_uiLang = uiLang;
1059 /***********************************************************************
1060 * SetWindowSubclass [COMCTL32.410]
1062 * Starts a window subclass
1064 * PARAMS
1065 * hWnd [in] handle to window subclass.
1066 * pfnSubclass [in] Pointer to new window procedure.
1067 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1068 * dwRef [in] Reference data to pass to window procedure.
1070 * RETURNS
1071 * Success: non-zero
1072 * Failure: zero
1074 * BUGS
1075 * If an application manually subclasses a window after subclassing it with
1076 * this API and then with this API again, then none of the previous
1077 * subclasses get called or the original window procedure.
1080 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1081 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1083 LPSUBCLASS_INFO stack;
1084 LPSUBCLASSPROCS proc;
1086 TRACE ("(%p, %p, %lx, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1088 if (!hWnd || !pfnSubclass)
1089 return FALSE;
1091 /* Since the window procedure that we set here has two additional arguments,
1092 * we can't simply set it as the new window procedure of the window. So we
1093 * set our own window procedure and then calculate the other two arguments
1094 * from there. */
1096 /* See if we have been called for this window */
1097 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1098 if (!stack) {
1099 /* allocate stack */
1100 stack = Alloc (sizeof(SUBCLASS_INFO));
1101 if (!stack) {
1102 ERR ("Failed to allocate our Subclassing stack\n");
1103 return FALSE;
1105 SetPropW (hWnd, COMCTL32_wSubclass, stack);
1107 /* set window procedure to our own and save the current one */
1108 if (IsWindowUnicode (hWnd))
1109 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1110 (DWORD_PTR)COMCTL32_SubclassProc);
1111 else
1112 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1113 (DWORD_PTR)COMCTL32_SubclassProc);
1115 else {
1116 /* Check to see if we have called this function with the same uIDSubClass
1117 * and pfnSubclass */
1118 proc = stack->SubclassProcs;
1119 while (proc) {
1120 if ((proc->id == uIDSubclass) &&
1121 (proc->subproc == pfnSubclass)) {
1122 proc->ref = dwRef;
1123 return TRUE;
1125 proc = proc->next;
1129 proc = Alloc(sizeof(SUBCLASSPROCS));
1130 if (!proc) {
1131 ERR ("Failed to allocate subclass entry in stack\n");
1132 if (IsWindowUnicode (hWnd))
1133 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1134 else
1135 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1136 Free (stack);
1137 RemovePropW( hWnd, COMCTL32_wSubclass );
1138 return FALSE;
1141 proc->subproc = pfnSubclass;
1142 proc->ref = dwRef;
1143 proc->id = uIDSubclass;
1144 proc->next = stack->SubclassProcs;
1145 stack->SubclassProcs = proc;
1147 return TRUE;
1151 /***********************************************************************
1152 * GetWindowSubclass [COMCTL32.411]
1154 * Gets the Reference data from a subclass.
1156 * PARAMS
1157 * hWnd [in] Handle to the window which we are subclassing
1158 * pfnSubclass [in] Pointer to the subclass procedure
1159 * uID [in] Unique identifier of the subclassing procedure
1160 * pdwRef [out] Pointer to the reference data
1162 * RETURNS
1163 * Success: Non-zero
1164 * Failure: 0
1167 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1168 UINT_PTR uID, DWORD_PTR *pdwRef)
1170 const SUBCLASS_INFO *stack;
1171 const SUBCLASSPROCS *proc;
1173 TRACE ("(%p, %p, %lx, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1175 /* See if we have been called for this window */
1176 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1177 if (!stack)
1178 return FALSE;
1180 proc = stack->SubclassProcs;
1181 while (proc) {
1182 if ((proc->id == uID) &&
1183 (proc->subproc == pfnSubclass)) {
1184 *pdwRef = proc->ref;
1185 return TRUE;
1187 proc = proc->next;
1190 return FALSE;
1194 /***********************************************************************
1195 * RemoveWindowSubclass [COMCTL32.412]
1197 * Removes a window subclass.
1199 * PARAMS
1200 * hWnd [in] Handle to the window which we are subclassing
1201 * pfnSubclass [in] Pointer to the subclass procedure
1202 * uID [in] Unique identifier of this subclass
1204 * RETURNS
1205 * Success: non-zero
1206 * Failure: zero
1209 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1211 LPSUBCLASS_INFO stack;
1212 LPSUBCLASSPROCS prevproc = NULL;
1213 LPSUBCLASSPROCS proc;
1214 BOOL ret = FALSE;
1216 TRACE ("(%p, %p, %lx)\n", hWnd, pfnSubclass, uID);
1218 /* Find the Subclass to remove */
1219 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1220 if (!stack)
1221 return FALSE;
1223 proc = stack->SubclassProcs;
1224 while (proc) {
1225 if ((proc->id == uID) &&
1226 (proc->subproc == pfnSubclass)) {
1228 if (!prevproc)
1229 stack->SubclassProcs = proc->next;
1230 else
1231 prevproc->next = proc->next;
1233 if (stack->stackpos == proc)
1234 stack->stackpos = stack->stackpos->next;
1236 Free (proc);
1237 ret = TRUE;
1238 break;
1240 prevproc = proc;
1241 proc = proc->next;
1244 if (!stack->SubclassProcs && !stack->running) {
1245 TRACE("Last Subclass removed, cleaning up\n");
1246 /* clean up our heap and reset the original window procedure */
1247 if (IsWindowUnicode (hWnd))
1248 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1249 else
1250 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1251 Free (stack);
1252 RemovePropW( hWnd, COMCTL32_wSubclass );
1255 return ret;
1258 /***********************************************************************
1259 * COMCTL32_SubclassProc (internal)
1261 * Window procedure for all subclassed windows.
1262 * Saves the current subclassing stack position to support nested messages
1264 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1266 LPSUBCLASS_INFO stack;
1267 LPSUBCLASSPROCS proc;
1268 LRESULT ret;
1270 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1272 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1273 if (!stack) {
1274 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1275 return 0;
1278 /* Save our old stackpos to properly handle nested messages */
1279 proc = stack->stackpos;
1280 stack->stackpos = stack->SubclassProcs;
1281 stack->running++;
1282 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1283 stack->running--;
1284 stack->stackpos = proc;
1286 if (!stack->SubclassProcs && !stack->running) {
1287 TRACE("Last Subclass removed, cleaning up\n");
1288 /* clean up our heap and reset the original window procedure */
1289 if (IsWindowUnicode (hWnd))
1290 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1291 else
1292 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1293 Free (stack);
1294 RemovePropW( hWnd, COMCTL32_wSubclass );
1296 return ret;
1299 /***********************************************************************
1300 * DefSubclassProc [COMCTL32.413]
1302 * Calls the next window procedure (i.e. the one before this subclass)
1304 * PARAMS
1305 * hWnd [in] The window that we're subclassing
1306 * uMsg [in] Message
1307 * wParam [in] WPARAM
1308 * lParam [in] LPARAM
1310 * RETURNS
1311 * Success: non-zero
1312 * Failure: zero
1315 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1317 LPSUBCLASS_INFO stack;
1318 LRESULT ret;
1320 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1322 /* retrieve our little stack from the Properties */
1323 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1324 if (!stack) {
1325 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1326 return 0;
1329 /* If we are at the end of stack then we have to call the original
1330 * window procedure */
1331 if (!stack->stackpos) {
1332 if (IsWindowUnicode (hWnd))
1333 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1334 else
1335 ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1336 } else {
1337 const SUBCLASSPROCS *proc = stack->stackpos;
1338 stack->stackpos = stack->stackpos->next;
1339 /* call the Subclass procedure from the stack */
1340 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1341 proc->id, proc->ref);
1344 return ret;
1348 /***********************************************************************
1349 * COMCTL32_CreateToolTip [NOT AN API]
1351 * Creates a tooltip for the control specified in hwnd and does all
1352 * necessary setup and notifications.
1354 * PARAMS
1355 * hwndOwner [I] Handle to the window that will own the tool tip.
1357 * RETURNS
1358 * Success: Handle of tool tip window.
1359 * Failure: NULL
1362 HWND
1363 COMCTL32_CreateToolTip(HWND hwndOwner)
1365 HWND hwndToolTip;
1367 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1368 CW_USEDEFAULT, CW_USEDEFAULT,
1369 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1370 0, 0, 0);
1372 /* Send NM_TOOLTIPSCREATED notification */
1373 if (hwndToolTip)
1375 NMTOOLTIPSCREATED nmttc;
1376 /* true owner can be different if hwndOwner is a child window */
1377 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1378 nmttc.hdr.hwndFrom = hwndTrueOwner;
1379 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1380 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1381 nmttc.hwndToolTips = hwndToolTip;
1383 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1384 GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
1387 return hwndToolTip;
1391 /***********************************************************************
1392 * COMCTL32_RefreshSysColors [NOT AN API]
1394 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1395 * refresh the color values in the color structure
1397 * PARAMS
1398 * none
1400 * RETURNS
1401 * none
1404 VOID
1405 COMCTL32_RefreshSysColors(void)
1407 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1408 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1409 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1410 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1411 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1412 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1413 comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1414 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1415 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1416 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1417 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1418 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1419 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1420 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1421 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1422 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1423 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1426 /***********************************************************************
1427 * COMCTL32_DrawInsertMark [NOT AN API]
1429 * Draws an insertion mark (which looks similar to an 'I').
1431 * PARAMS
1432 * hDC [I] Device context to draw onto.
1433 * lpRect [I] Co-ordinates of insertion mark.
1434 * clrInsertMark [I] Colour of the insertion mark.
1435 * bHorizontal [I] True if insert mark should be drawn horizontally,
1436 * vertical otherwise.
1438 * RETURNS
1439 * none
1441 * NOTES
1442 * Draws up to but not including the bottom co-ordinate when drawing
1443 * vertically or the right co-ordinate when horizontal.
1445 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1447 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1448 HPEN hOldPen;
1449 static const DWORD adwPolyPoints[] = {4,4,4};
1450 LONG lCentre = (bHorizontal ?
1451 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1452 lpRect->left + (lpRect->right - lpRect->left)/2);
1453 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1454 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1455 const POINT aptInsertMark[] =
1457 /* top (V) or left (H) arrow */
1458 {lCentre , l1 + 2},
1459 {lCentre - 2, l1 },
1460 {lCentre + 3, l1 },
1461 {lCentre + 1, l1 + 2},
1462 /* middle line */
1463 {lCentre , l2 - 2},
1464 {lCentre , l1 - 1},
1465 {lCentre + 1, l1 - 1},
1466 {lCentre + 1, l2 - 2},
1467 /* bottom (V) or right (H) arrow */
1468 {lCentre , l2 - 3},
1469 {lCentre - 2, l2 - 1},
1470 {lCentre + 3, l2 - 1},
1471 {lCentre + 1, l2 - 3},
1473 hOldPen = SelectObject(hDC, hPen);
1474 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, ARRAY_SIZE(adwPolyPoints));
1475 SelectObject(hDC, hOldPen);
1476 DeleteObject(hPen);
1479 /***********************************************************************
1480 * COMCTL32_EnsureBitmapSize [internal]
1482 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1483 * the height is at least cyMinHeight. If the bitmap already has these
1484 * dimensions nothing changes.
1486 * PARAMS
1487 * hBitmap [I/O] Bitmap to modify. The handle may change
1488 * cxMinWidth [I] If the width of the bitmap is smaller, then it will
1489 * be enlarged to this value
1490 * cyMinHeight [I] If the height of the bitmap is smaller, then it will
1491 * be enlarged to this value
1492 * cyBackground [I] The color with which the new area will be filled
1494 * RETURNS
1495 * none
1497 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1499 int cxNew, cyNew;
1500 BITMAP bmp;
1501 HBITMAP hNewBitmap;
1502 HBITMAP hNewDCBitmap, hOldDCBitmap;
1503 HBRUSH hNewDCBrush;
1504 HDC hdcNew, hdcOld;
1506 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1507 return;
1508 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1509 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1510 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1511 return;
1513 hdcNew = CreateCompatibleDC(NULL);
1514 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1515 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1516 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1518 hdcOld = CreateCompatibleDC(NULL);
1519 hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1521 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1522 if (bmp.bmWidth < cxMinWidth)
1523 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1524 if (bmp.bmHeight < cyMinHeight)
1525 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1526 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1527 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1529 SelectObject(hdcNew, hNewDCBitmap);
1530 DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1531 DeleteDC(hdcNew);
1532 SelectObject(hdcOld, hOldDCBitmap);
1533 DeleteDC(hdcOld);
1535 DeleteObject(*pBitmap);
1536 *pBitmap = hNewBitmap;
1537 return;
1540 void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
1542 HDC hdc = GetDC(NULL);
1543 HFONT hOldFont;
1545 hOldFont = SelectObject(hdc, hFont);
1546 GetTextMetricsW(hdc, ptm);
1547 SelectObject(hdc, hOldFont);
1548 ReleaseDC(NULL, hdc);
1551 #ifndef OCM__BASE /* avoid including olectl.h */
1552 #define OCM__BASE (WM_USER+0x1c00)
1553 #endif
1555 /***********************************************************************
1556 * COMCTL32_IsReflectedMessage [internal]
1558 * Some parents reflect notify messages - for some messages sent by the child,
1559 * they send it back with the message code increased by OCM__BASE (0x2000).
1560 * This allows better subclassing of controls. We don't need to handle such
1561 * messages but we don't want to print ERRs for them, so this helper function
1562 * identifies them.
1564 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1565 * collision with defined CCM_ codes.
1567 BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
1569 switch (uMsg)
1571 case OCM__BASE + WM_COMMAND:
1572 case OCM__BASE + WM_CTLCOLORBTN:
1573 case OCM__BASE + WM_CTLCOLOREDIT:
1574 case OCM__BASE + WM_CTLCOLORDLG:
1575 case OCM__BASE + WM_CTLCOLORLISTBOX:
1576 case OCM__BASE + WM_CTLCOLORMSGBOX:
1577 case OCM__BASE + WM_CTLCOLORSCROLLBAR:
1578 case OCM__BASE + WM_CTLCOLORSTATIC:
1579 case OCM__BASE + WM_DRAWITEM:
1580 case OCM__BASE + WM_MEASUREITEM:
1581 case OCM__BASE + WM_DELETEITEM:
1582 case OCM__BASE + WM_VKEYTOITEM:
1583 case OCM__BASE + WM_CHARTOITEM:
1584 case OCM__BASE + WM_COMPAREITEM:
1585 case OCM__BASE + WM_HSCROLL:
1586 case OCM__BASE + WM_VSCROLL:
1587 case OCM__BASE + WM_PARENTNOTIFY:
1588 case OCM__BASE + WM_NOTIFY:
1589 return TRUE;
1590 default:
1591 return FALSE;
1595 /***********************************************************************
1596 * MirrorIcon [COMCTL32.414]
1598 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1600 * PARAMS
1601 * phicon1 [I/O] Icon.
1602 * phicon2 [I/O] Icon.
1604 * RETURNS
1605 * Success: TRUE.
1606 * Failure: FALSE.
1608 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1610 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1611 return FALSE;
1614 static inline BOOL IsDelimiter(WCHAR c)
1616 switch(c)
1618 case '/':
1619 case '\\':
1620 case '.':
1621 case ' ':
1622 return TRUE;
1624 return FALSE;
1627 static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1629 if (code == WB_ISDELIMITER)
1630 return IsDelimiter(lpch[ichCurrent]);
1631 else
1633 int dir = (code == WB_LEFT) ? -1 : 1;
1634 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1635 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1637 return ichCurrent;
1640 /***********************************************************************
1641 * SetPathWordBreakProc [COMCTL32.384]
1643 * Sets the word break procedure for an edit control to one that understands
1644 * paths so that the user can jump over directories.
1646 * PARAMS
1647 * hwnd [I] Handle to edit control.
1648 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1650 * RETURNS
1651 * Result from EM_SETWORDBREAKPROC message.
1653 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1655 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1656 (LPARAM)(bSet ? PathWordBreakProc : NULL));
1659 /***********************************************************************
1660 * DrawShadowText [COMCTL32.@]
1662 * Draw text with shadow.
1664 int WINAPI DrawShadowText(HDC hdc, LPCWSTR text, UINT length, RECT *rect, DWORD flags,
1665 COLORREF crText, COLORREF crShadow, int offset_x, int offset_y)
1667 int bkmode, ret;
1668 COLORREF clr;
1669 RECT r;
1671 FIXME("(%p, %s, %d, %p, 0x%08x, 0x%08x, 0x%08x, %d, %d): semi-stub\n", hdc, debugstr_w(text),
1672 length, rect, flags, crText, crShadow, offset_x, offset_y);
1674 bkmode = SetBkMode(hdc, TRANSPARENT);
1675 clr = SetTextColor(hdc, crShadow);
1677 /* FIXME: for shadow we need to render normally, blur it, and blend with current background. */
1678 r = *rect;
1679 OffsetRect(&r, 1, 1);
1680 DrawTextW(hdc, text, length, &r, flags);
1682 SetTextColor(hdc, crText);
1684 /* with text color on top of a shadow */
1685 ret = DrawTextW(hdc, text, length, rect, flags);
1687 SetTextColor(hdc, clr);
1688 SetBkMode(hdc, bkmode);
1690 return ret;
1693 /***********************************************************************
1694 * LoadIconWithScaleDown [COMCTL32.@]
1696 HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
1698 TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
1700 *icon = NULL;
1702 if (!name)
1703 return E_INVALIDARG;
1705 *icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
1706 (hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
1707 if (!*icon)
1708 return HRESULT_FROM_WIN32(GetLastError());
1710 return S_OK;
1713 /***********************************************************************
1714 * LoadIconMetric [COMCTL32.@]
1716 HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
1718 int cx, cy;
1720 TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
1722 if (size == LIM_SMALL)
1724 cx = GetSystemMetrics(SM_CXSMICON);
1725 cy = GetSystemMetrics(SM_CYSMICON);
1727 else if (size == LIM_LARGE)
1729 cx = GetSystemMetrics(SM_CXICON);
1730 cy = GetSystemMetrics(SM_CYICON);
1732 else
1734 *icon = NULL;
1735 return E_INVALIDARG;
1738 return LoadIconWithScaleDown(hinst, name, cx, cy, icon);
1741 static const WCHAR strMRUList[] = { 'M','R','U','L','i','s','t',0 };
1743 /**************************************************************************
1744 * Alloc [COMCTL32.71]
1746 * Allocates memory block from the dll's private heap
1748 void * WINAPI Alloc(DWORD size)
1750 return LocalAlloc(LMEM_ZEROINIT, size);
1753 /**************************************************************************
1754 * ReAlloc [COMCTL32.72]
1756 * Changes the size of an allocated memory block or allocates a memory
1757 * block using the dll's private heap.
1760 void * WINAPI ReAlloc(void *src, DWORD size)
1762 if (src)
1763 return LocalReAlloc(src, size, LMEM_ZEROINIT | LMEM_MOVEABLE);
1764 else
1765 return LocalAlloc(LMEM_ZEROINIT, size);
1768 /**************************************************************************
1769 * Free [COMCTL32.73]
1771 * Frees an allocated memory block from the dll's private heap.
1773 BOOL WINAPI Free(void *mem)
1775 return !LocalFree(mem);
1778 /**************************************************************************
1779 * GetSize [COMCTL32.74]
1781 DWORD WINAPI GetSize(void *mem)
1783 return LocalSize(mem);
1786 /**************************************************************************
1787 * MRU-Functions {COMCTL32}
1789 * NOTES
1790 * The MRU-API is a set of functions to manipulate lists of M.R.U. (Most Recently
1791 * Used) items. It is an undocumented API that is used (at least) by the shell
1792 * and explorer to implement their recent documents feature.
1794 * Since these functions are undocumented, they are unsupported by MS and
1795 * may change at any time.
1797 * Internally, the list is implemented as a last in, last out list of items
1798 * persisted into the system registry under a caller chosen key. Each list
1799 * item is given a one character identifier in the Ascii range from 'a' to
1800 * '}'. A list of the identifiers in order from newest to oldest is stored
1801 * under the same key in a value named "MRUList".
1803 * Items are re-ordered by changing the order of the values in the MRUList
1804 * value. When a new item is added, it becomes the new value of the oldest
1805 * identifier, and that identifier is moved to the front of the MRUList value.
1807 * Wine stores MRU-lists in the same registry format as Windows, so when
1808 * switching between the builtin and native comctl32.dll no problems or
1809 * incompatibilities should occur.
1811 * The following undocumented structure is used to create an MRU-list:
1812 *|typedef INT (CALLBACK *MRUStringCmpFn)(LPCTSTR lhs, LPCTSTR rhs);
1813 *|typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
1815 *|typedef struct tagMRUINFO
1817 *| DWORD cbSize;
1818 *| UINT uMax;
1819 *| UINT fFlags;
1820 *| HKEY hKey;
1821 *| LPTSTR lpszSubKey;
1822 *| PROC lpfnCompare;
1823 *|} MRUINFO, *LPMRUINFO;
1825 * MEMBERS
1826 * cbSize [I] The size of the MRUINFO structure. This must be set
1827 * to sizeof(MRUINFO) by the caller.
1828 * uMax [I] The maximum number of items allowed in the list. Because
1829 * of the limited number of identifiers, this should be set to
1830 * a value from 1 to 30 by the caller.
1831 * fFlags [I] If bit 0 is set, the list will be used to store binary
1832 * data, otherwise it is assumed to store strings. If bit 1
1833 * is set, every change made to the list will be reflected in
1834 * the registry immediately, otherwise changes will only be
1835 * written when the list is closed.
1836 * hKey [I] The registry key that the list should be written under.
1837 * This must be supplied by the caller.
1838 * lpszSubKey [I] A caller supplied name of a subkey under hKey to write
1839 * the list to. This may not be blank.
1840 * lpfnCompare [I] A caller supplied comparison function, which may be either
1841 * an MRUStringCmpFn if dwFlags does not have bit 0 set, or a
1842 * MRUBinaryCmpFn otherwise.
1844 * FUNCTIONS
1845 * - Create an MRU-list with CreateMRUList() or CreateMRUListLazy().
1846 * - Add items to an MRU-list with AddMRUString() or AddMRUData().
1847 * - Remove items from an MRU-list with DelMRUString().
1848 * - Find data in an MRU-list with FindMRUString() or FindMRUData().
1849 * - Iterate through an MRU-list with EnumMRUList().
1850 * - Free an MRU-list with FreeMRUList().
1853 typedef INT (CALLBACK *MRUStringCmpFnA)(LPCSTR lhs, LPCSTR rhs);
1854 typedef INT (CALLBACK *MRUStringCmpFnW)(LPCWSTR lhs, LPCWSTR rhs);
1855 typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
1857 struct MRUINFOA
1859 DWORD cbSize;
1860 UINT uMax;
1861 UINT fFlags;
1862 HKEY hKey;
1863 LPSTR lpszSubKey;
1864 union
1866 MRUStringCmpFnA string_cmpfn;
1867 MRUBinaryCmpFn binary_cmpfn;
1868 } u;
1871 struct MRUINFOW
1873 DWORD cbSize;
1874 UINT uMax;
1875 UINT fFlags;
1876 HKEY hKey;
1877 LPWSTR lpszSubKey;
1878 union
1880 MRUStringCmpFnW string_cmpfn;
1881 MRUBinaryCmpFn binary_cmpfn;
1882 } u;
1885 /* MRUINFO.fFlags */
1886 #define MRU_STRING 0 /* list will contain strings */
1887 #define MRU_BINARY 1 /* list will contain binary data */
1888 #define MRU_CACHEWRITE 2 /* only save list order to reg. is FreeMRUList */
1890 /* If list is a string list lpfnCompare has the following prototype
1891 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
1892 * for binary lists the prototype is
1893 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
1894 * where cbData is the no. of bytes to compare.
1895 * Need to check what return value means identical - 0?
1898 typedef struct tagWINEMRUITEM
1900 DWORD size; /* size of data stored */
1901 DWORD itemFlag; /* flags */
1902 BYTE datastart;
1903 } WINEMRUITEM, *LPWINEMRUITEM;
1905 /* itemFlag */
1906 #define WMRUIF_CHANGED 0x0001 /* this dataitem changed */
1908 typedef struct tagWINEMRULIST
1910 struct MRUINFOW extview; /* original create information */
1911 BOOL isUnicode; /* is compare fn Unicode */
1912 DWORD wineFlags; /* internal flags */
1913 DWORD cursize; /* current size of realMRU */
1914 LPWSTR realMRU; /* pointer to string of index names */
1915 LPWINEMRUITEM *array; /* array of pointers to data */
1916 /* in 'a' to 'z' order */
1917 } WINEMRULIST, *LPWINEMRULIST;
1919 /* wineFlags */
1920 #define WMRUF_CHANGED 0x0001 /* MRU list has changed */
1922 /**************************************************************************
1923 * MRU_SaveChanged (internal)
1925 * Local MRU saving code
1927 static void MRU_SaveChanged(WINEMRULIST *mp)
1929 UINT i, err;
1930 HKEY newkey;
1931 WCHAR realname[2];
1932 WINEMRUITEM *witem;
1934 /* or should we do the following instead of RegOpenKeyEx:
1937 /* open the sub key */
1938 if ((err = RegOpenKeyExW(mp->extview.hKey, mp->extview.lpszSubKey, 0, KEY_WRITE, &newkey)))
1940 /* not present - what to do ??? */
1941 ERR("Could not open key, error=%d, attempting to create\n", err);
1942 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
1943 KEY_READ | KEY_WRITE, 0, &newkey, 0)))
1945 ERR("failed to create key /%s/, err=%d\n", debugstr_w(mp->extview.lpszSubKey), err);
1946 return;
1950 if (mp->wineFlags & WMRUF_CHANGED)
1952 mp->wineFlags &= ~WMRUF_CHANGED;
1953 if ((err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (BYTE *)mp->realMRU,
1954 (lstrlenW(mp->realMRU) + 1)*sizeof(WCHAR))))
1956 ERR("error saving MRUList, err=%d\n", err);
1958 TRACE("saving MRUList=/%s/\n", debugstr_w(mp->realMRU));
1961 realname[1] = 0;
1962 for (i = 0; i < mp->cursize; ++i)
1964 witem = mp->array[i];
1965 if (witem->itemFlag & WMRUIF_CHANGED)
1967 witem->itemFlag &= ~WMRUIF_CHANGED;
1968 realname[0] = 'a' + i;
1969 if ((err = RegSetValueExW(newkey, realname, 0, (mp->extview.fFlags & MRU_BINARY) ?
1970 REG_BINARY : REG_SZ, &witem->datastart, witem->size)))
1972 ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err);
1974 TRACE("saving value for name /%s/ size=%d\n", debugstr_w(realname), witem->size);
1977 RegCloseKey(newkey);
1980 /**************************************************************************
1981 * FreeMRUList [COMCTL32.152]
1983 * Frees a most-recently-used items list.
1985 void WINAPI FreeMRUList(HANDLE hMRUList)
1987 WINEMRULIST *mp = hMRUList;
1988 unsigned int i;
1990 TRACE("%p.\n", hMRUList);
1992 if (!hMRUList)
1993 return;
1995 if (mp->wineFlags & WMRUF_CHANGED)
1997 /* need to open key and then save the info */
1998 MRU_SaveChanged(mp);
2001 for (i = 0; i < mp->extview.uMax; ++i)
2002 Free(mp->array[i]);
2004 Free(mp->realMRU);
2005 Free(mp->array);
2006 Free(mp->extview.lpszSubKey);
2007 Free(mp);
2010 /**************************************************************************
2011 * FindMRUData [COMCTL32.169]
2013 * Searches binary list for item that matches data of given length.
2014 * Returns position in list order 0 -> MRU and value corresponding to item's reg.
2015 * name will be stored in it ('a' -> 0).
2018 INT WINAPI FindMRUData(HANDLE hList, const void *data, DWORD cbData, int *pos)
2020 const WINEMRULIST *mp = hList;
2021 INT ret;
2022 UINT i;
2023 LPSTR dataA = NULL;
2025 if (!mp || !mp->extview.u.string_cmpfn)
2026 return -1;
2028 if (!(mp->extview.fFlags & MRU_BINARY) && !mp->isUnicode)
2030 DWORD len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
2031 dataA = Alloc(len);
2032 WideCharToMultiByte(CP_ACP, 0, data, -1, dataA, len, NULL, NULL);
2035 for (i = 0; i < mp->cursize; ++i)
2037 if (mp->extview.fFlags & MRU_BINARY)
2039 if (!mp->extview.u.binary_cmpfn(data, &mp->array[i]->datastart, cbData))
2040 break;
2042 else
2044 if (mp->isUnicode)
2046 if (!mp->extview.u.string_cmpfn(data, (LPWSTR)&mp->array[i]->datastart))
2047 break;
2049 else
2051 DWORD len = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
2052 NULL, 0, NULL, NULL);
2053 LPSTR itemA = Alloc(len);
2054 INT cmp;
2055 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1, itemA, len, NULL, NULL);
2057 cmp = mp->extview.u.string_cmpfn((LPWSTR)dataA, (LPWSTR)itemA);
2058 Free(itemA);
2059 if (!cmp)
2060 break;
2065 Free(dataA);
2066 if (i < mp->cursize)
2067 ret = i;
2068 else
2069 ret = -1;
2070 if (pos && (ret != -1))
2071 *pos = 'a' + i;
2073 TRACE("%p, %p, %d, %p, returning %d.\n", hList, data, cbData, pos, ret);
2075 return ret;
2078 /**************************************************************************
2079 * AddMRUData [COMCTL32.167]
2081 * Add item to MRU binary list. If item already exists in list then it is
2082 * simply moved up to the top of the list and not added again. If list is
2083 * full then the least recently used item is removed to make room.
2086 INT WINAPI AddMRUData(HANDLE hList, const void *data, DWORD cbData)
2088 WINEMRULIST *mp = hList;
2089 WINEMRUITEM *witem;
2090 INT i, replace;
2092 if ((replace = FindMRUData(hList, data, cbData, NULL)) >= 0)
2094 /* Item exists, just move it to the front */
2095 LPWSTR pos = wcschr(mp->realMRU, replace + 'a');
2096 while (pos > mp->realMRU)
2098 pos[0] = pos[-1];
2099 pos--;
2102 else
2104 /* either add a new entry or replace oldest */
2105 if (mp->cursize < mp->extview.uMax)
2107 /* Add in a new item */
2108 replace = mp->cursize;
2109 mp->cursize++;
2111 else
2113 /* get the oldest entry and replace data */
2114 replace = mp->realMRU[mp->cursize - 1] - 'a';
2115 Free(mp->array[replace]);
2118 /* Allocate space for new item and move in the data */
2119 mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM));
2120 witem->itemFlag |= WMRUIF_CHANGED;
2121 witem->size = cbData;
2122 memcpy( &witem->datastart, data, cbData);
2124 /* now rotate MRU list */
2125 for (i = mp->cursize - 1; i >= 1; --i)
2126 mp->realMRU[i] = mp->realMRU[i-1];
2129 /* The new item gets the front spot */
2130 mp->wineFlags |= WMRUF_CHANGED;
2131 mp->realMRU[0] = replace + 'a';
2133 TRACE("(%p, %p, %d) adding data, /%c/ now most current\n", hList, data, cbData, replace+'a');
2135 if (!(mp->extview.fFlags & MRU_CACHEWRITE))
2137 /* save changed stuff right now */
2138 MRU_SaveChanged(mp);
2141 return replace;
2144 /**************************************************************************
2145 * AddMRUStringW [COMCTL32.401]
2147 * Add an item to an MRU string list.
2150 INT WINAPI AddMRUStringW(HANDLE hList, const WCHAR *str)
2152 TRACE("%p, %s.\n", hList, debugstr_w(str));
2154 if (!hList)
2155 return -1;
2157 if (!str || IsBadStringPtrW(str, -1))
2159 SetLastError(ERROR_INVALID_PARAMETER);
2160 return 0;
2163 return AddMRUData(hList, str, (lstrlenW(str) + 1) * sizeof(WCHAR));
2166 /**************************************************************************
2167 * AddMRUStringA [COMCTL32.153]
2169 INT WINAPI AddMRUStringA(HANDLE hList, const char *str)
2171 WCHAR *strW;
2172 DWORD len;
2173 INT ret;
2175 TRACE("%p, %s.\n", hList, debugstr_a(str));
2177 if (!hList)
2178 return -1;
2180 if (IsBadStringPtrA(str, -1))
2182 SetLastError(ERROR_INVALID_PARAMETER);
2183 return 0;
2186 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0) * sizeof(WCHAR);
2187 strW = Alloc(len);
2188 if (!strW)
2189 return -1;
2191 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len/sizeof(WCHAR));
2192 ret = AddMRUData(hList, strW, len);
2193 Free(strW);
2194 return ret;
2197 /**************************************************************************
2198 * DelMRUString [COMCTL32.156]
2200 * Removes item from either string or binary list (despite its name)
2202 * PARAMS
2203 * hList [I] list handle
2204 * nItemPos [I] item position to remove 0 -> MRU
2206 * RETURNS
2207 * TRUE if successful, FALSE if nItemPos is out of range.
2209 BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos)
2211 FIXME("(%p, %d): stub\n", hList, nItemPos);
2212 return TRUE;
2215 /**************************************************************************
2216 * FindMRUStringW [COMCTL32.402]
2218 INT WINAPI FindMRUStringW(HANDLE hList, const WCHAR *str, int *pos)
2220 return FindMRUData(hList, str, (lstrlenW(str) + 1) * sizeof(WCHAR), pos);
2223 /**************************************************************************
2224 * FindMRUStringA [COMCTL32.155]
2226 * Searches string list for item that matches given string.
2228 * RETURNS
2229 * Position in list 0 -> MRU. -1 if item not found.
2231 INT WINAPI FindMRUStringA(HANDLE hList, const char *str, int *pos)
2233 DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
2234 WCHAR *strW = Alloc(len * sizeof(*strW));
2235 INT ret;
2237 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
2238 ret = FindMRUData(hList, strW, len * sizeof(WCHAR), pos);
2239 Free(strW);
2240 return ret;
2243 /*************************************************************************
2244 * create_mru_list (internal)
2246 static HANDLE create_mru_list(WINEMRULIST *mp)
2248 UINT i, err;
2249 HKEY newkey;
2250 DWORD datasize, dwdisp;
2251 WCHAR realname[2];
2252 WINEMRUITEM *witem;
2253 DWORD type;
2255 /* get space to save indices that will turn into names
2256 * but in order of most to least recently used
2258 mp->realMRU = Alloc((mp->extview.uMax + 2) * sizeof(WCHAR));
2260 /* get space to save pointers to actual data in order of
2261 * 'a' to 'z' (0 to n).
2263 mp->array = Alloc(mp->extview.uMax * sizeof(LPVOID));
2265 /* open the sub key */
2266 if ((err = RegCreateKeyExW(mp->extview.hKey, mp->extview.lpszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
2267 KEY_READ | KEY_WRITE, 0, &newkey, &dwdisp)))
2269 /* error - what to do ??? */
2270 ERR("(%u %u %x %p %s %p): Could not open key, error=%d\n", mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
2271 mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.u.string_cmpfn, err);
2272 return 0;
2275 /* get values from key 'MRUList' */
2276 if (newkey)
2278 datasize = (mp->extview.uMax + 1) * sizeof(WCHAR);
2279 if (RegQueryValueExW( newkey, strMRUList, 0, &type, (BYTE *)mp->realMRU, &datasize))
2281 /* not present - set size to 1 (will become 0 later) */
2282 datasize = 1;
2283 *mp->realMRU = 0;
2285 else
2286 datasize /= sizeof(WCHAR);
2288 TRACE("MRU list = %s, datasize = %d\n", debugstr_w(mp->realMRU), datasize);
2290 mp->cursize = datasize - 1;
2291 /* datasize now has number of items in the MRUList */
2293 /* get actual values for each entry */
2294 realname[1] = 0;
2295 for (i = 0; i < mp->cursize; ++i)
2297 realname[0] = 'a' + i;
2298 if (RegQueryValueExW(newkey, realname, 0, &type, 0, &datasize))
2300 /* not present - what to do ??? */
2301 ERR("Key %s not found 1\n", debugstr_w(realname));
2303 mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM));
2304 witem->size = datasize;
2305 if (RegQueryValueExW(newkey, realname, 0, &type, &witem->datastart, &datasize))
2307 /* not present - what to do ??? */
2308 ERR("Key %s not found 2\n", debugstr_w(realname));
2311 RegCloseKey( newkey );
2313 else
2314 mp->cursize = 0;
2316 TRACE("(%u %u %x %p %s %p): Current Size = %d\n", mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
2317 mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.u.string_cmpfn, mp->cursize);
2318 return mp;
2321 /**************************************************************************
2322 * CreateMRUListLazyW [COMCTL32.404]
2324 HANDLE WINAPI CreateMRUListLazyW(const struct MRUINFOW *info, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
2326 WINEMRULIST *mp;
2328 /* Native does not check for a NULL. */
2329 if (!info->hKey || IsBadStringPtrW(info->lpszSubKey, -1))
2330 return NULL;
2332 mp = Alloc(sizeof(*mp));
2333 memcpy(&mp->extview, info, sizeof(*info));
2334 mp->extview.lpszSubKey = Alloc((lstrlenW(info->lpszSubKey) + 1) * sizeof(WCHAR));
2335 lstrcpyW(mp->extview.lpszSubKey, info->lpszSubKey);
2336 mp->isUnicode = TRUE;
2338 return create_mru_list(mp);
2341 /**************************************************************************
2342 * CreateMRUListLazyA [COMCTL32.157]
2344 * Creates a most-recently-used list.
2346 HANDLE WINAPI CreateMRUListLazyA(const struct MRUINFOA *info, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
2348 WINEMRULIST *mp;
2349 DWORD len;
2351 /* Native does not check for a NULL lpcml */
2353 if (!info->hKey || IsBadStringPtrA(info->lpszSubKey, -1))
2354 return 0;
2356 mp = Alloc(sizeof(*mp));
2357 memcpy(&mp->extview, info, sizeof(*info));
2358 len = MultiByteToWideChar(CP_ACP, 0, info->lpszSubKey, -1, NULL, 0);
2359 mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR));
2360 MultiByteToWideChar(CP_ACP, 0, info->lpszSubKey, -1, mp->extview.lpszSubKey, len);
2361 mp->isUnicode = FALSE;
2362 return create_mru_list(mp);
2365 /**************************************************************************
2366 * CreateMRUListW [COMCTL32.400]
2368 HANDLE WINAPI CreateMRUListW(const struct MRUINFOW *info)
2370 return CreateMRUListLazyW(info, 0, 0, 0);
2373 /**************************************************************************
2374 * CreateMRUListA [COMCTL32.151]
2376 HANDLE WINAPI CreateMRUListA(const struct MRUINFOA *info)
2378 return CreateMRUListLazyA(info, 0, 0, 0);
2381 /**************************************************************************
2382 * EnumMRUListW [COMCTL32.403]
2384 * Enumerate item in a most-recently-used list
2386 * PARAMS
2387 * hList [I] list handle
2388 * nItemPos [I] item position to enumerate
2389 * lpBuffer [O] buffer to receive item
2390 * nBufferSize [I] size of buffer
2392 * RETURNS
2393 * For binary lists specifies how many bytes were copied to buffer, for
2394 * string lists specifies full length of string. Enumerating past the end
2395 * of list returns -1.
2396 * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
2397 * the list.
2399 INT WINAPI EnumMRUListW(HANDLE hList, INT nItemPos, void *buffer, DWORD nBufferSize)
2401 const WINEMRULIST *mp = hList;
2402 const WINEMRUITEM *witem;
2403 INT desired, datasize;
2405 if (!mp) return -1;
2406 if ((nItemPos < 0) || !buffer) return mp->cursize;
2407 if (nItemPos >= mp->cursize) return -1;
2408 desired = mp->realMRU[nItemPos];
2409 desired -= 'a';
2410 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
2411 witem = mp->array[desired];
2412 datasize = min(witem->size, nBufferSize);
2413 memcpy(buffer, &witem->datastart, datasize);
2414 TRACE("(%p, %d, %p, %d): returning len=%d\n", hList, nItemPos, buffer, nBufferSize, datasize);
2415 return datasize;
2418 /**************************************************************************
2419 * EnumMRUListA [COMCTL32.154]
2421 INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, void *buffer, DWORD nBufferSize)
2423 const WINEMRULIST *mp = hList;
2424 WINEMRUITEM *witem;
2425 INT desired, datasize;
2426 DWORD lenA;
2428 if (!mp) return -1;
2429 if ((nItemPos < 0) || !buffer) return mp->cursize;
2430 if (nItemPos >= mp->cursize) return -1;
2431 desired = mp->realMRU[nItemPos];
2432 desired -= 'a';
2433 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
2434 witem = mp->array[desired];
2435 if (mp->extview.fFlags & MRU_BINARY)
2437 datasize = min(witem->size, nBufferSize);
2438 memcpy(buffer, &witem->datastart, datasize);
2440 else
2442 lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, NULL, 0, NULL, NULL);
2443 datasize = min(lenA, nBufferSize);
2444 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, buffer, datasize, NULL, NULL);
2445 ((char *)buffer)[ datasize - 1 ] = '\0';
2446 datasize = lenA - 1;
2448 TRACE("(%p, %d, %p, %d): returning len=%d\n", hList, nItemPos, buffer, nBufferSize, datasize);
2449 return datasize;
2452 /**************************************************************************
2453 * Str_GetPtrWtoA [internal]
2455 * Converts a unicode string into a multi byte string
2459 INT Str_GetPtrWtoA(const WCHAR *src, char *dst, INT nMaxLen)
2461 INT len;
2463 TRACE("%s, %p, %d.\n", debugstr_w(src), dst, nMaxLen);
2465 if (!dst && src)
2466 return WideCharToMultiByte(CP_ACP, 0, src, -1, 0, 0, NULL, NULL);
2468 if (!nMaxLen)
2469 return 0;
2471 if (!src)
2473 dst[0] = 0;
2474 return 0;
2477 len = WideCharToMultiByte(CP_ACP, 0, src, -1, 0, 0, NULL, NULL);
2478 if (len >= nMaxLen)
2479 len = nMaxLen - 1;
2481 WideCharToMultiByte(CP_ACP, 0, src, -1, dst, len, NULL, NULL);
2482 dst[len] = '\0';
2484 return len;
2487 /**************************************************************************
2488 * Str_GetPtrAtoW [internal]
2490 * Converts a multibyte string into a unicode string
2493 INT Str_GetPtrAtoW(const char *src, WCHAR *dst, INT nMaxLen)
2495 INT len;
2497 TRACE("%s, %p, %d.\n", debugstr_a(src), dst, nMaxLen);
2499 if (!dst && src)
2500 return MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
2502 if (!nMaxLen)
2503 return 0;
2505 if (!src)
2507 *dst = 0;
2508 return 0;
2511 len = MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
2512 if (len >= nMaxLen)
2513 len = nMaxLen - 1;
2515 MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
2516 dst[len] = 0;
2518 return len;
2521 /**************************************************************************
2522 * Str_SetPtrAtoW [internal]
2524 * Converts a multi byte string to a unicode string.
2525 * If the pointer to the destination buffer is NULL a buffer is allocated.
2526 * If the destination buffer is too small to keep the converted multi byte
2527 * string the destination buffer is reallocated. If the source pointer is
2529 BOOL Str_SetPtrAtoW(WCHAR **dst, const char *src)
2531 TRACE("%p, %s.\n", dst, debugstr_a(src));
2533 if (src)
2535 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
2536 LPWSTR ptr = ReAlloc(*dst, len * sizeof(**dst));
2538 if (!ptr)
2539 return FALSE;
2540 MultiByteToWideChar(CP_ACP, 0, src, -1, ptr, len);
2541 *dst = ptr;
2543 else
2545 Free(*dst);
2546 *dst = NULL;
2549 return TRUE;
2552 /**************************************************************************
2553 * Str_SetPtrWtoA [internal]
2555 * Converts a unicode string to a multi byte string.
2556 * If the pointer to the destination buffer is NULL a buffer is allocated.
2557 * If the destination buffer is too small to keep the converted wide
2558 * string the destination buffer is reallocated. If the source pointer is
2559 * NULL, the destination buffer is freed.
2561 BOOL Str_SetPtrWtoA(char **dst, const WCHAR *src)
2563 TRACE("%p, %s.\n", dst, debugstr_w(src));
2565 if (src)
2567 INT len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, FALSE);
2568 LPSTR ptr = ReAlloc(*dst, len * sizeof(**dst));
2570 if (!ptr)
2571 return FALSE;
2572 WideCharToMultiByte(CP_ACP, 0, src, -1, ptr, len, NULL, FALSE);
2573 *dst = ptr;
2575 else
2577 Free(*dst);
2578 *dst = NULL;
2581 return TRUE;
2584 /**************************************************************************
2585 * Notification functions
2588 struct NOTIFYDATA
2590 HWND hwndFrom;
2591 HWND hwndTo;
2592 DWORD dwParam3;
2593 DWORD dwParam4;
2594 DWORD dwParam5;
2595 DWORD dwParam6;
2598 /**************************************************************************
2599 * DoNotify [Internal]
2602 static LRESULT DoNotify(const struct NOTIFYDATA *notify, UINT code, NMHDR *hdr)
2604 NMHDR nmhdr;
2605 NMHDR *lpNmh = NULL;
2606 UINT idFrom = 0;
2608 TRACE("%p, %p, %d, %p, %#x.\n", notify->hwndFrom, notify->hwndTo, code, hdr, notify->dwParam5);
2610 if (!notify->hwndTo)
2611 return 0;
2613 if (notify->hwndFrom == (HWND)-1)
2615 lpNmh = hdr;
2616 idFrom = hdr->idFrom;
2618 else
2620 if (notify->hwndFrom)
2621 idFrom = GetDlgCtrlID(notify->hwndFrom);
2623 lpNmh = hdr ? hdr : &nmhdr;
2624 lpNmh->hwndFrom = notify->hwndFrom;
2625 lpNmh->idFrom = idFrom;
2626 lpNmh->code = code;
2629 return SendMessageW(notify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
2632 /**************************************************************************
2633 * SendNotify [COMCTL32.341]
2635 * Sends a WM_NOTIFY message to the specified window.
2638 LRESULT WINAPI SendNotify(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr)
2640 struct NOTIFYDATA notify;
2642 TRACE("%p, %p, %d, %p.\n", hwndTo, hwndFrom, code, hdr);
2644 notify.hwndFrom = hwndFrom;
2645 notify.hwndTo = hwndTo;
2646 notify.dwParam5 = 0;
2647 notify.dwParam6 = 0;
2649 return DoNotify(&notify, code, hdr);
2652 /**************************************************************************
2653 * SendNotifyEx [COMCTL32.342]
2655 * Sends a WM_NOTIFY message to the specified window.
2657 * PARAMS
2658 * hwndFrom [I] Window to receive the message
2659 * hwndTo [I] Window that the message is from
2660 * code [I] Notification code
2661 * hdr [I] The NMHDR and any additional information to send or NULL
2662 * dwParam5 [I] Unknown
2664 * RETURNS
2665 * Success: return value from notification
2666 * Failure: 0
2668 * NOTES
2669 * If hwndFrom is -1 then the identifier of the control sending the
2670 * message is taken from the NMHDR structure.
2671 * If hwndFrom is not -1 then lpHdr can be NULL.
2673 LRESULT WINAPI SendNotifyEx(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr, DWORD dwParam5)
2675 struct NOTIFYDATA notify;
2676 HWND hwndNotify;
2678 TRACE("(%p %p %d %p %#x)\n", hwndFrom, hwndTo, code, hdr, dwParam5);
2680 hwndNotify = hwndTo;
2681 if (!hwndTo)
2683 if (IsWindow(hwndFrom))
2685 hwndNotify = GetParent(hwndFrom);
2686 if (!hwndNotify)
2687 return 0;
2691 notify.hwndFrom = hwndFrom;
2692 notify.hwndTo = hwndNotify;
2693 notify.dwParam5 = dwParam5;
2694 notify.dwParam6 = 0;
2696 return DoNotify(&notify, code, hdr);