1 /*
2 * Common controls functions
3 *
4 * Copyright 1997 Dimitrie O. Paun
5 * Copyright 1998,2000 Eric Kohl
6 * Copyright 2014-2015 Michael M�ller
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 *
22 * NOTES
23 *
24 * This code was audited for completeness against the documented features
25 * of Comctl32.dll version 6.0 on Oct. 21, 2002, by Christian Neumair.
26 *
27 * Unless otherwise noted, we believe this code to be complete, as per
28 * the specification mentioned above.
29 * If you discover missing features, or bugs, please note them below.
30 *
31 * TODO
32 * -- implement GetMUILanguage + InitMUILanguage
33 * -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW
34 * -- FIXMEs + BUGS (search for them)
35 *
36 * Control Classes
37 * -- ICC_ANIMATE_CLASS
38 * -- ICC_BAR_CLASSES
39 * -- ICC_COOL_CLASSES
40 * -- ICC_DATE_CLASSES
41 * -- ICC_HOTKEY_CLASS
42 * -- ICC_INTERNET_CLASSES
43 * -- ICC_LINK_CLASS
44 * -- ICC_LISTVIEW_CLASSES
45 * -- ICC_NATIVEFNTCTL_CLASS
46 * -- ICC_PAGESCROLLER_CLASS
47 * -- ICC_PROGRESS_CLASS
48 * -- ICC_STANDARD_CLASSES (not yet implemented)
49 * -- ICC_TAB_CLASSES
50 * -- ICC_TREEVIEW_CLASSES
51 * -- ICC_UPDOWN_CLASS
52 * -- ICC_USEREX_CLASSES
53 * -- ICC_WIN95_CLASSES
54 */
55
56 #include <stdarg.h>
57 #include <string.h>
58 #include <stdlib.h>
59
60 #include "windef.h"
61 #include "winbase.h"
62 #include "wingdi.h"
63 #include "winuser.h"
64 #include "winnls.h"
65 #include "commctrl.h"
66 #include "winerror.h"
67 #include "winreg.h"
68 #define NO_SHLWAPI_STREAM
69 #include "shlwapi.h"
70 #include "comctl32.h"
71 #include "wine/debug.h"
72
73 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
74
75
76 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
77
78 static LPWSTR COMCTL32_wSubclass = NULL;
79 HMODULE COMCTL32_hModule = 0;
80 static LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
81 HBRUSH COMCTL32_hPattern55AABrush = NULL;
82 COMCTL32_SysColor comctl32_color;
83
84 static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
85
86 static const WORD wPattern55AA[] =
87 {
88 0x5555, 0xaaaa, 0x5555, 0xaaaa,
89 0x5555, 0xaaaa, 0x5555, 0xaaaa
90 };
91
92 static const WCHAR strCC32SubclassInfo[] = {
93 'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
94 };
95
96 #ifdef __REACTOS__
97
98 #include <strsafe.h>
99
100 #define NAME L"microsoft.windows.common-controls"
101 #define VERSION_V5 L"5.82.2600.2982"
102 #define VERSION L"6.0.2600.2982"
103 #define PUBLIC_KEY L"6595b64144ccf1df"
104
105 #ifdef __i386__
106 #define ARCH L"x86"
107 #elif defined __x86_64__
108 #define ARCH L"amd64"
109 #else
110 #define ARCH L"none"
111 #endif
112
113 static const WCHAR manifest_filename[] = ARCH L"_" NAME L"_" PUBLIC_KEY L"_" VERSION L"_none_deadbeef.manifest";
114 static const WCHAR manifest_filename_v5[] = ARCH L"_" NAME L"_" PUBLIC_KEY L"_" VERSION_V5 L"_none_deadbeef.manifest";
115
GetManifestPath(BOOL create,BOOL bV6)116 static WCHAR* GetManifestPath(BOOL create, BOOL bV6)
117 {
118 WCHAR *pwszBuf;
119 HRESULT hres;
120
121 pwszBuf = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
122 if (!pwszBuf)
123 return NULL;
124
125 GetWindowsDirectoryW(pwszBuf, MAX_PATH);
126 hres = StringCchCatW(pwszBuf, MAX_PATH, L"\\winsxs");
127 if (FAILED(hres))
128 return NULL;
129 if (create)
130 CreateDirectoryW(pwszBuf, NULL);
131 hres = StringCchCatW(pwszBuf, MAX_PATH, L"\\manifests\\");
132 if (FAILED(hres))
133 return NULL;
134 if (create)
135 CreateDirectoryW(pwszBuf, NULL);
136
137 hres = StringCchCatW(pwszBuf, MAX_PATH, bV6 ? manifest_filename : manifest_filename_v5);
138 if (FAILED(hres))
139 return NULL;
140
141 return pwszBuf;
142 }
143
CreateComctl32ActCtx(BOOL bV6)144 static HANDLE CreateComctl32ActCtx(BOOL bV6)
145 {
146 HANDLE ret;
147 WCHAR* pwstrSource;
148 ACTCTXW ActCtx = {sizeof(ACTCTX)};
149
150 pwstrSource = GetManifestPath(FALSE, bV6);
151 if (!pwstrSource)
152 {
153 ERR("GetManifestPath failed! bV6=%d\n", bV6);
154 return INVALID_HANDLE_VALUE;
155 }
156 ActCtx.lpSource = pwstrSource;
157 ret = CreateActCtxW(&ActCtx);
158 HeapFree(GetProcessHeap(), 0, pwstrSource);
159 if (ret == INVALID_HANDLE_VALUE)
160 ERR("CreateActCtxW failed! bV6=%d\n", bV6);
161 return ret;
162 }
163
RegisterControls(BOOL bV6)164 static void RegisterControls(BOOL bV6)
165 {
166 ANIMATE_Register ();
167 COMBOEX_Register ();
168 DATETIME_Register ();
169 FLATSB_Register ();
170 HEADER_Register ();
171 HOTKEY_Register ();
172 IPADDRESS_Register ();
173 LISTVIEW_Register ();
174 MONTHCAL_Register ();
175 NATIVEFONT_Register ();
176 PAGER_Register ();
177 PROGRESS_Register ();
178 REBAR_Register ();
179 STATUS_Register ();
180 SYSLINK_Register ();
181 TAB_Register ();
182 TOOLTIPS_Register ();
183 TRACKBAR_Register ();
184 TREEVIEW_Register ();
185 UPDOWN_Register ();
186
187 if (!bV6)
188 {
189 TOOLBAR_Register ();
190 }
191 else
192 {
193 BUTTON_Register ();
194 COMBO_Register ();
195 COMBOLBOX_Register ();
196 EDIT_Register ();
197 LISTBOX_Register ();
198 STATIC_Register ();
199
200 TOOLBARv6_Register();
201 }
202 }
203
UnregisterControls(BOOL bV6)204 static void UnregisterControls(BOOL bV6)
205 {
206 ANIMATE_Unregister ();
207 COMBOEX_Unregister ();
208 DATETIME_Unregister ();
209 FLATSB_Unregister ();
210 HEADER_Unregister ();
211 HOTKEY_Unregister ();
212 IPADDRESS_Unregister ();
213 LISTVIEW_Unregister ();
214 MONTHCAL_Unregister ();
215 NATIVEFONT_Unregister ();
216 PAGER_Unregister ();
217 PROGRESS_Unregister ();
218 REBAR_Unregister ();
219 STATUS_Unregister ();
220 SYSLINK_Unregister ();
221 TAB_Unregister ();
222 TOOLTIPS_Unregister ();
223 TRACKBAR_Unregister ();
224 TREEVIEW_Unregister ();
225 UPDOWN_Unregister ();
226
227 if (!bV6)
228 {
229 TOOLBAR_Unregister ();
230 }
231 else
232 {
233 BUTTON_Unregister();
234 COMBO_Unregister ();
235 COMBOLBOX_Unregister ();
236 EDIT_Unregister ();
237 LISTBOX_Unregister ();
238 STATIC_Unregister ();
239
240 TOOLBARv6_Unregister ();
241 }
242
243 }
244
InitializeClasses()245 static void InitializeClasses()
246 {
247 HANDLE hActCtx5, hActCtx6;
248 BOOL activated;
249 ULONG_PTR ulCookie;
250
251 /* like comctl32 5.82+ register all the common control classes */
252 /* Register the classes once no matter what */
253 hActCtx5 = CreateComctl32ActCtx(FALSE);
254 activated = (hActCtx5 != INVALID_HANDLE_VALUE ? ActivateActCtx(hActCtx5, &ulCookie) : FALSE);
255 RegisterControls(FALSE); /* Register the classes pretending to be v5 */
256 if (activated) DeactivateActCtx(0, ulCookie);
257
258 hActCtx6 = CreateComctl32ActCtx(TRUE);
259 if (hActCtx6 != INVALID_HANDLE_VALUE)
260 {
261 activated = ActivateActCtx(hActCtx6, &ulCookie);
262 RegisterControls(TRUE); /* Register the classes pretending to be v6 */
263 if (activated) DeactivateActCtx(0, ulCookie);
264
265 /* Initialize the themed controls only when the v6 manifest is present */
266 THEMING_Initialize (hActCtx5, hActCtx6);
267 }
268 }
269
UninitializeClasses()270 static void UninitializeClasses()
271 {
272 HANDLE hActCtx5, hActCtx6;
273 BOOL activated;
274 ULONG_PTR ulCookie;
275
276 hActCtx5 = CreateComctl32ActCtx(FALSE);
277 activated = (hActCtx5 != INVALID_HANDLE_VALUE ? ActivateActCtx(hActCtx5, &ulCookie) : FALSE);
278 UnregisterControls(FALSE);
279 if (activated) DeactivateActCtx(0, ulCookie);
280
281 hActCtx6 = CreateComctl32ActCtx(TRUE);
282 if (hActCtx6 != INVALID_HANDLE_VALUE)
283 {
284 activated = ActivateActCtx(hActCtx6, &ulCookie);
285 THEMING_Uninitialize();
286 UnregisterControls(TRUE);
287 if (activated) DeactivateActCtx(0, ulCookie);
288 }
289 }
290
291 /***********************************************************************
292 * RegisterClassNameW [COMCTL32.@]
293 *
294 * Register window class again while using as SxS module.
295 */
RegisterClassNameW(LPCWSTR className)296 BOOLEAN WINAPI RegisterClassNameW(LPCWSTR className)
297 {
298 InitializeClasses();
299 return TRUE;
300 }
301
302 #endif /* __REACTOS__ */
303
304 #ifndef __REACTOS__
unregister_versioned_classes(void)305 static void unregister_versioned_classes(void)
306 {
307 #define VERSION "6.0.2600.2982!"
308 static const char *classes[] =
309 {
310 VERSION WC_BUTTONA,
311 VERSION WC_COMBOBOXA,
312 VERSION "ComboLBox",
313 VERSION WC_EDITA,
314 VERSION WC_LISTBOXA,
315 VERSION WC_STATICA,
316 };
317 int i;
318
319 for (i = 0; i < ARRAY_SIZE(classes); i++)
320 UnregisterClassA(classes[i], NULL);
321
322 #undef VERSION
323 }
324 #endif
325
326 /***********************************************************************
327 * DllMain [Internal]
328 *
329 * Initializes the internal 'COMCTL32.DLL'.
330 *
331 * PARAMS
332 * hinstDLL [I] handle to the 'dlls' instance
333 * fdwReason [I]
334 * lpvReserved [I] reserved, must be NULL
335 *
336 * RETURNS
337 * Success: TRUE
338 * Failure: FALSE
339 */
340
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)341 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
342 {
343 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
344
345 switch (fdwReason) {
346 case DLL_PROCESS_ATTACH:
347 DisableThreadLibraryCalls(hinstDLL);
348
349 COMCTL32_hModule = hinstDLL;
350
351 /* add global subclassing atom (used by 'tooltip' and 'updown') */
352 COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
353 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
354
355 /* create local pattern brush */
356 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
357 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
358
359 /* Get all the colors at DLL load */
360 COMCTL32_RefreshSysColors();
361
362 #ifndef __REACTOS__
363 /* like comctl32 5.82+ register all the common control classes */
364 ANIMATE_Register ();
365 COMBOEX_Register ();
366 DATETIME_Register ();
367 FLATSB_Register ();
368 HEADER_Register ();
369 HOTKEY_Register ();
370 IPADDRESS_Register ();
371 LISTVIEW_Register ();
372 MONTHCAL_Register ();
373 NATIVEFONT_Register ();
374 PAGER_Register ();
375 PROGRESS_Register ();
376 REBAR_Register ();
377 STATUS_Register ();
378 SYSLINK_Register ();
379 TAB_Register ();
380 TOOLBAR_Register ();
381 TOOLTIPS_Register ();
382 TRACKBAR_Register ();
383 TREEVIEW_Register ();
384 UPDOWN_Register ();
385
386 BUTTON_Register ();
387 COMBO_Register ();
388 COMBOLBOX_Register ();
389 EDIT_Register ();
390 LISTBOX_Register ();
391 STATIC_Register ();
392
393 /* subclass user32 controls */
394 THEMING_Initialize ();
395 #else
396 InitializeClasses();
397 #endif
398
399 break;
400
401 case DLL_PROCESS_DETACH:
402 if (lpvReserved) break;
403 #ifndef __REACTOS__
404 /* clean up subclassing */
405 THEMING_Uninitialize();
406
407 /* unregister all common control classes */
408 ANIMATE_Unregister ();
409 COMBOEX_Unregister ();
410 DATETIME_Unregister ();
411 FLATSB_Unregister ();
412 HEADER_Unregister ();
413 HOTKEY_Unregister ();
414 IPADDRESS_Unregister ();
415 LISTVIEW_Unregister ();
416 MONTHCAL_Unregister ();
417 NATIVEFONT_Unregister ();
418 PAGER_Unregister ();
419 PROGRESS_Unregister ();
420 REBAR_Unregister ();
421 STATUS_Unregister ();
422 SYSLINK_Unregister ();
423 TAB_Unregister ();
424 TOOLBAR_Unregister ();
425 TOOLTIPS_Unregister ();
426 TRACKBAR_Unregister ();
427 TREEVIEW_Unregister ();
428 UPDOWN_Unregister ();
429
430 unregister_versioned_classes ();
431
432 #else
433 UninitializeClasses();
434 #endif
435 /* delete local pattern brush */
436 DeleteObject (COMCTL32_hPattern55AABrush);
437 DeleteObject (COMCTL32_hPattern55AABitmap);
438
439 /* delete global subclassing atom */
440 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
441 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
442 break;
443 }
444
445 return TRUE;
446 }
447
448
449 /***********************************************************************
450 * MenuHelp [COMCTL32.2]
451 *
452 * Handles the setting of status bar help messages when the user
453 * selects menu items.
454 *
455 * PARAMS
456 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
457 * wParam [I] wParam of the message uMsg
458 * lParam [I] lParam of the message uMsg
459 * hMainMenu [I] handle to the application's main menu
460 * hInst [I] handle to the module that contains string resources
461 * hwndStatus [I] handle to the status bar window
462 * lpwIDs [I] pointer to an array of integers (see NOTES)
463 *
464 * RETURNS
465 * No return value
466 *
467 * NOTES
468 * The official documentation is incomplete!
469 * This is the correct documentation:
470 *
471 * uMsg:
472 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
473 * WM_MENUSELECT messages.
474 *
475 * lpwIDs:
476 * (will be written ...)
477 */
478
479 VOID WINAPI
MenuHelp(UINT uMsg,WPARAM wParam,LPARAM lParam,HMENU hMainMenu,HINSTANCE hInst,HWND hwndStatus,UINT * lpwIDs)480 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
481 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
482 {
483 UINT uMenuID = 0;
484
485 if (!IsWindow (hwndStatus))
486 return;
487
488 switch (uMsg) {
489 case WM_MENUSELECT:
490 TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
491 wParam, lParam);
492
493 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
494 /* menu was closed */
495 TRACE("menu was closed!\n");
496 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
497 }
498 else {
499 /* menu item was selected */
500 if (HIWORD(wParam) & MF_POPUP)
501 uMenuID = *(lpwIDs+1);
502 else
503 uMenuID = (UINT)LOWORD(wParam);
504 TRACE("uMenuID = %u\n", uMenuID);
505
506 if (uMenuID) {
507 WCHAR szText[256];
508
509 if (!LoadStringW (hInst, uMenuID, szText, ARRAY_SIZE(szText)))
510 szText[0] = '\0';
511
512 SendMessageW (hwndStatus, SB_SETTEXTW,
513 255 | SBT_NOBORDERS, (LPARAM)szText);
514 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
515 }
516 }
517 break;
518
519 case WM_COMMAND :
520 TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
521 wParam, lParam);
522 /* WM_COMMAND is not invalid since it is documented
523 * in the windows api reference. So don't output
524 * any FIXME for WM_COMMAND
525 */
526 WARN("We don't care about the WM_COMMAND\n");
527 break;
528
529 default:
530 FIXME("Invalid Message 0x%x!\n", uMsg);
531 break;
532 }
533 }
534
535
536 /***********************************************************************
537 * ShowHideMenuCtl [COMCTL32.3]
538 *
539 * Shows or hides controls and updates the corresponding menu item.
540 *
541 * PARAMS
542 * hwnd [I] handle to the client window.
543 * uFlags [I] menu command id.
544 * lpInfo [I] pointer to an array of integers. (See NOTES.)
545 *
546 * RETURNS
547 * Success: TRUE
548 * Failure: FALSE
549 *
550 * NOTES
551 * The official documentation is incomplete!
552 * This is the correct documentation:
553 *
554 * hwnd
555 * Handle to the window that contains the menu and controls.
556 *
557 * uFlags
558 * Identifier of the menu item to receive or lose a check mark.
559 *
560 * lpInfo
561 * The array of integers contains pairs of values. BOTH values of
562 * the first pair must be the handles to the application's main menu.
563 * Each subsequent pair consists of a menu id and control id.
564 */
565
566 BOOL WINAPI
ShowHideMenuCtl(HWND hwnd,UINT_PTR uFlags,LPINT lpInfo)567 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
568 {
569 LPINT lpMenuId;
570
571 TRACE("%p, %lx, %p\n", hwnd, uFlags, lpInfo);
572
573 if (lpInfo == NULL)
574 return FALSE;
575
576 if (!(lpInfo[0]) || !(lpInfo[1]))
577 return FALSE;
578
579 /* search for control */
580 lpMenuId = &lpInfo[2];
581 while (*lpMenuId != uFlags)
582 lpMenuId += 2;
583
584 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
585 /* uncheck menu item */
586 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
587
588 /* hide control */
589 lpMenuId++;
590 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
591 SWP_HIDEWINDOW);
592 }
593 else {
594 /* check menu item */
595 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
596
597 /* show control */
598 lpMenuId++;
599 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
600 SWP_SHOWWINDOW);
601 }
602
603 return TRUE;
604 }
605
606
607 /***********************************************************************
608 * GetEffectiveClientRect [COMCTL32.4]
609 *
610 * Calculates the coordinates of a rectangle in the client area.
611 *
612 * PARAMS
613 * hwnd [I] handle to the client window.
614 * lpRect [O] pointer to the rectangle of the client window
615 * lpInfo [I] pointer to an array of integers (see NOTES)
616 *
617 * RETURNS
618 * No return value.
619 *
620 * NOTES
621 * The official documentation is incomplete!
622 * This is the correct documentation:
623 *
624 * lpInfo
625 * (will be written ...)
626 */
627
628 VOID WINAPI
GetEffectiveClientRect(HWND hwnd,LPRECT lpRect,const INT * lpInfo)629 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
630 {
631 RECT rcCtrl;
632 const INT *lpRun;
633 HWND hwndCtrl;
634
635 TRACE("(%p %p %p)\n",
636 hwnd, lpRect, lpInfo);
637
638 GetClientRect (hwnd, lpRect);
639 lpRun = lpInfo;
640
641 do {
642 lpRun += 2;
643 if (*lpRun == 0)
644 return;
645 lpRun++;
646 hwndCtrl = GetDlgItem (hwnd, *lpRun);
647 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
648 TRACE("control id 0x%x\n", *lpRun);
649 GetWindowRect (hwndCtrl, &rcCtrl);
650 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
651 SubtractRect (lpRect, lpRect, &rcCtrl);
652 }
653 lpRun++;
654 } while (*lpRun);
655 }
656
657
658 /***********************************************************************
659 * DrawStatusTextW [COMCTL32.@]
660 *
661 * Draws text with borders, like in a status bar.
662 *
663 * PARAMS
664 * hdc [I] handle to the window's display context
665 * lprc [I] pointer to a rectangle
666 * text [I] pointer to the text
667 * style [I] drawing style
668 *
669 * RETURNS
670 * No return value.
671 *
672 * NOTES
673 * The style variable can have one of the following values:
674 * (will be written ...)
675 */
676
DrawStatusTextW(HDC hdc,LPCRECT lprc,LPCWSTR text,UINT style)677 void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
678 {
679 RECT r = *lprc;
680 UINT border = BDR_SUNKENOUTER;
681 COLORREF oldbkcolor;
682
683 if (style & SBT_POPOUT)
684 border = BDR_RAISEDOUTER;
685 else if (style & SBT_NOBORDERS)
686 border = 0;
687
688 oldbkcolor = SetBkColor (hdc, comctl32_color.clrBtnFace);
689 DrawEdge (hdc, &r, border, BF_MIDDLE|BF_RECT|BF_ADJUST);
690
691 /* now draw text */
692 if (text) {
693 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
694 COLORREF oldtextcolor;
695 UINT align = DT_LEFT;
696 int strCnt = 0;
697
698 oldtextcolor = SetTextColor (hdc, comctl32_color.clrBtnText);
699 if (style & SBT_RTLREADING)
700 FIXME("Unsupported RTL style!\n");
701 r.left += 3;
702 do {
703 if (*text == '\t') {
704 if (strCnt) {
705 DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
706 strCnt = 0;
707 }
708 if (align==DT_RIGHT) {
709 break;
710 }
711 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
712 } else {
713 strCnt++;
714 }
715 } while(*text++);
716
717 if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
718 SetBkMode (hdc, oldbkmode);
719 SetTextColor (hdc, oldtextcolor);
720 }
721
722 SetBkColor (hdc, oldbkcolor);
723 }
724
725
726 /***********************************************************************
727 * DrawStatusText [COMCTL32.@]
728 * DrawStatusTextA [COMCTL32.5]
729 *
730 * Draws text with borders, like in a status bar.
731 *
732 * PARAMS
733 * hdc [I] handle to the window's display context
734 * lprc [I] pointer to a rectangle
735 * text [I] pointer to the text
736 * style [I] drawing style
737 *
738 * RETURNS
739 * No return value.
740 */
741
DrawStatusTextA(HDC hdc,LPCRECT lprc,LPCSTR text,UINT style)742 void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
743 {
744 INT len;
745 LPWSTR textW = NULL;
746
747 if ( text ) {
748 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
749 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
750 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
751 }
752 }
753 DrawStatusTextW( hdc, lprc, textW, style );
754 Free( textW );
755 }
756
757
758 /***********************************************************************
759 * CreateStatusWindow [COMCTL32.@]
760 * CreateStatusWindowA [COMCTL32.6]
761 *
762 * Creates a status bar
763 *
764 * PARAMS
765 * style [I] window style
766 * text [I] pointer to the window text
767 * parent [I] handle to the parent window
768 * wid [I] control id of the status bar
769 *
770 * RETURNS
771 * Success: handle to the status window
772 * Failure: 0
773 */
774
775 HWND WINAPI
CreateStatusWindowA(LONG style,LPCSTR text,HWND parent,UINT wid)776 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
777 {
778 return CreateWindowA(STATUSCLASSNAMEA, text, style,
779 CW_USEDEFAULT, CW_USEDEFAULT,
780 CW_USEDEFAULT, CW_USEDEFAULT,
781 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
782 }
783
784
785 /***********************************************************************
786 * CreateStatusWindowW [COMCTL32.@]
787 *
788 * Creates a status bar control
789 *
790 * PARAMS
791 * style [I] window style
792 * text [I] pointer to the window text
793 * parent [I] handle to the parent window
794 * wid [I] control id of the status bar
795 *
796 * RETURNS
797 * Success: handle to the status window
798 * Failure: 0
799 */
800
801 HWND WINAPI
CreateStatusWindowW(LONG style,LPCWSTR text,HWND parent,UINT wid)802 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
803 {
804 return CreateWindowW(STATUSCLASSNAMEW, text, style,
805 CW_USEDEFAULT, CW_USEDEFAULT,
806 CW_USEDEFAULT, CW_USEDEFAULT,
807 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
808 }
809
810
811 /***********************************************************************
812 * CreateUpDownControl [COMCTL32.16]
813 *
814 * Creates an up-down control
815 *
816 * PARAMS
817 * style [I] window styles
818 * x [I] horizontal position of the control
819 * y [I] vertical position of the control
820 * cx [I] with of the control
821 * cy [I] height of the control
822 * parent [I] handle to the parent window
823 * id [I] the control's identifier
824 * inst [I] handle to the application's module instance
825 * buddy [I] handle to the buddy window, can be NULL
826 * maxVal [I] upper limit of the control
827 * minVal [I] lower limit of the control
828 * curVal [I] current value of the control
829 *
830 * RETURNS
831 * Success: handle to the updown control
832 * Failure: 0
833 */
834
835 HWND WINAPI
CreateUpDownControl(DWORD style,INT x,INT y,INT cx,INT cy,HWND parent,INT id,HINSTANCE inst,HWND buddy,INT maxVal,INT minVal,INT curVal)836 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
837 HWND parent, INT id, HINSTANCE inst,
838 HWND buddy, INT maxVal, INT minVal, INT curVal)
839 {
840 HWND hUD =
841 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
842 parent, (HMENU)(DWORD_PTR)id, inst, 0);
843 if (hUD) {
844 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
845 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
846 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
847 }
848
849 return hUD;
850 }
851
852
853 /***********************************************************************
854 * InitCommonControls [COMCTL32.17]
855 *
856 * Registers the common controls.
857 *
858 * PARAMS
859 * No parameters.
860 *
861 * RETURNS
862 * No return values.
863 *
864 * NOTES
865 * This function is just a dummy - all the controls are registered at
866 * the DLL initialization time. See InitCommonControlsEx for details.
867 */
868
869 VOID WINAPI
InitCommonControls(void)870 InitCommonControls (void)
871 {
872 }
873
874
875 /***********************************************************************
876 * InitCommonControlsEx [COMCTL32.@]
877 *
878 * Registers the common controls.
879 *
880 * PARAMS
881 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
882 *
883 * RETURNS
884 * Success: TRUE
885 * Failure: FALSE
886 *
887 * NOTES
888 * Probably all versions of comctl32 initializes the Win95 controls in DllMain
889 * during DLL initialization. Starting from comctl32 v5.82 all the controls
890 * are initialized there. We follow this behaviour and this function is just
891 * a dummy.
892 *
893 * Note: when writing programs under Windows, if you don't call any function
894 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
895 * was the only comctl32 function you were calling and you remove it you may
896 * have a false impression that InitCommonControlsEx actually did something.
897 */
898
899 BOOL WINAPI
InitCommonControlsEx(const INITCOMMONCONTROLSEX * lpInitCtrls)900 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
901 {
902 if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
903 return FALSE;
904
905 TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
906 return TRUE;
907 }
908
909
910 /***********************************************************************
911 * CreateToolbarEx [COMCTL32.@]
912 *
913 * Creates a toolbar window.
914 *
915 * PARAMS
916 * hwnd
917 * style
918 * wID
919 * nBitmaps
920 * hBMInst
921 * wBMID
922 * lpButtons
923 * iNumButtons
924 * dxButton
925 * dyButton
926 * dxBitmap
927 * dyBitmap
928 * uStructSize
929 *
930 * RETURNS
931 * Success: handle to the tool bar control
932 * Failure: 0
933 */
934
935 HWND WINAPI
CreateToolbarEx(HWND hwnd,DWORD style,UINT wID,INT nBitmaps,HINSTANCE hBMInst,UINT_PTR wBMID,LPCTBBUTTON lpButtons,INT iNumButtons,INT dxButton,INT dyButton,INT dxBitmap,INT dyBitmap,UINT uStructSize)936 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
937 HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
938 INT iNumButtons, INT dxButton, INT dyButton,
939 INT dxBitmap, INT dyBitmap, UINT uStructSize)
940 {
941 HWND hwndTB;
942
943 hwndTB =
944 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
945 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
946 if(hwndTB) {
947 TBADDBITMAP tbab;
948
949 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
950
951 /* set bitmap and button size */
952 /*If CreateToolbarEx receives 0, windows sets default values*/
953 if (dxBitmap < 0)
954 dxBitmap = 16;
955 if (dyBitmap < 0)
956 dyBitmap = 16;
957 if (dxBitmap == 0 || dyBitmap == 0)
958 dxBitmap = dyBitmap = 16;
959 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
960
961 if (dxButton < 0)
962 dxButton = dxBitmap;
963 if (dyButton < 0)
964 dyButton = dyBitmap;
965 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
966 if (dxButton != 0 && dyButton != 0)
967 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
968
969
970 /* add bitmaps */
971 if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
972 {
973 tbab.hInst = hBMInst;
974 tbab.nID = wBMID;
975
976 SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
977 }
978 /* add buttons */
979 if(iNumButtons > 0)
980 SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
981 }
982
983 return hwndTB;
984 }
985
986
987 /***********************************************************************
988 * CreateMappedBitmap [COMCTL32.8]
989 *
990 * Loads a bitmap resource using a colour map.
991 *
992 * PARAMS
993 * hInstance [I] Handle to the module containing the bitmap.
994 * idBitmap [I] The bitmap resource ID.
995 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
996 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
997 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
998 *
999 * RETURNS
1000 * Success: handle to the new bitmap
1001 * Failure: 0
1002 */
1003
1004 HBITMAP WINAPI
CreateMappedBitmap(HINSTANCE hInstance,INT_PTR idBitmap,UINT wFlags,LPCOLORMAP lpColorMap,INT iNumMaps)1005 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
1006 LPCOLORMAP lpColorMap, INT iNumMaps)
1007 {
1008 HGLOBAL hglb;
1009 HRSRC hRsrc;
1010 const BITMAPINFOHEADER *lpBitmap;
1011 LPBITMAPINFOHEADER lpBitmapInfo;
1012 UINT nSize, nColorTableSize, iColor;
1013 RGBQUAD *pColorTable;
1014 INT i, iMaps, nWidth, nHeight;
1015 HDC hdcScreen;
1016 HBITMAP hbm;
1017 LPCOLORMAP sysColorMap;
1018 COLORREF cRef;
1019 COLORMAP internalColorMap[4] =
1020 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
1021
1022 /* initialize pointer to colortable and default color table */
1023 if (lpColorMap) {
1024 iMaps = iNumMaps;
1025 sysColorMap = lpColorMap;
1026 }
1027 else {
1028 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
1029 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
1030 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
1031 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
1032 iMaps = 4;
1033 sysColorMap = internalColorMap;
1034 }
1035
1036 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
1037 if (hRsrc == 0)
1038 return 0;
1039 hglb = LoadResource (hInstance, hRsrc);
1040 if (hglb == 0)
1041 return 0;
1042 lpBitmap = LockResource (hglb);
1043 if (lpBitmap == NULL)
1044 return 0;
1045
1046 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
1047 nColorTableSize = lpBitmap->biClrUsed;
1048 else if (lpBitmap->biBitCount <= 8)
1049 nColorTableSize = (1 << lpBitmap->biBitCount);
1050 else
1051 nColorTableSize = 0;
1052 nSize = lpBitmap->biSize;
1053 if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
1054 nSize += 3 * sizeof(DWORD);
1055 nSize += nColorTableSize * sizeof(RGBQUAD);
1056 lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
1057 if (lpBitmapInfo == NULL)
1058 return 0;
1059 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
1060
1061 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
1062
1063 for (iColor = 0; iColor < nColorTableSize; iColor++) {
1064 for (i = 0; i < iMaps; i++) {
1065 cRef = RGB(pColorTable[iColor].rgbRed,
1066 pColorTable[iColor].rgbGreen,
1067 pColorTable[iColor].rgbBlue);
1068 if ( cRef == sysColorMap[i].from) {
1069 #if 0
1070 if (wFlags & CBS_MASKED) {
1071 if (sysColorMap[i].to != COLOR_BTNTEXT)
1072 pColorTable[iColor] = RGB(255, 255, 255);
1073 }
1074 else
1075 #endif
1076 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
1077 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
1078 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
1079 break;
1080 }
1081 }
1082 }
1083 nWidth = lpBitmapInfo->biWidth;
1084 nHeight = lpBitmapInfo->biHeight;
1085 hdcScreen = GetDC (NULL);
1086 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
1087 if (hbm) {
1088 HDC hdcDst = CreateCompatibleDC (hdcScreen);
1089 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
1090 const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
1091 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
1092 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
1093 SRCCOPY);
1094 SelectObject (hdcDst, hbmOld);
1095 DeleteDC (hdcDst);
1096 }
1097 ReleaseDC (NULL, hdcScreen);
1098 GlobalFree (lpBitmapInfo);
1099 FreeResource (hglb);
1100
1101 return hbm;
1102 }
1103
1104
1105 /***********************************************************************
1106 * CreateToolbar [COMCTL32.7]
1107 *
1108 * Creates a toolbar control.
1109 *
1110 * PARAMS
1111 * hwnd
1112 * style
1113 * wID
1114 * nBitmaps
1115 * hBMInst
1116 * wBMID
1117 * lpButtons
1118 * iNumButtons
1119 *
1120 * RETURNS
1121 * Success: handle to the tool bar control
1122 * Failure: 0
1123 *
1124 * NOTES
1125 * Do not use this function anymore. Use CreateToolbarEx instead.
1126 */
1127
1128 HWND WINAPI
CreateToolbar(HWND hwnd,DWORD style,UINT wID,INT nBitmaps,HINSTANCE hBMInst,UINT wBMID,LPCTBBUTTON lpButtons,INT iNumButtons)1129 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
1130 HINSTANCE hBMInst, UINT wBMID,
1131 LPCTBBUTTON lpButtons,INT iNumButtons)
1132 {
1133 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
1134 hBMInst, wBMID, lpButtons,
1135 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
1136 }
1137
1138
1139 /***********************************************************************
1140 * DllGetVersion [COMCTL32.@]
1141 *
1142 * Retrieves version information of the 'COMCTL32.DLL'
1143 *
1144 * PARAMS
1145 * pdvi [O] pointer to version information structure.
1146 *
1147 * RETURNS
1148 * Success: S_OK
1149 * Failure: E_INVALIDARG
1150 *
1151 * NOTES
1152 * Returns version of a comctl32.dll from IE4.01 SP1.
1153 */
1154
DllGetVersion(DLLVERSIONINFO * pdvi)1155 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
1156 {
1157 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
1158 WARN("wrong DLLVERSIONINFO size from app\n");
1159 return E_INVALIDARG;
1160 }
1161
1162 pdvi->dwMajorVersion = COMCTL32_VERSION;
1163 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
1164 pdvi->dwBuildNumber = 2919;
1165 pdvi->dwPlatformID = 6304;
1166
1167 TRACE("%u.%u.%u.%u\n",
1168 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
1169 pdvi->dwBuildNumber, pdvi->dwPlatformID);
1170
1171 return S_OK;
1172 }
1173
1174 /***********************************************************************
1175 * DllInstall (COMCTL32.@)
1176 *
1177 * Installs the ComCtl32 DLL.
1178 *
1179 * RETURNS
1180 * Success: S_OK
1181 * Failure: A HRESULT error
1182 */
DllInstall(BOOL bInstall,LPCWSTR cmdline)1183 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
1184 {
1185 TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
1186 return S_OK;
1187 }
1188
1189 /***********************************************************************
1190 * _TrackMouseEvent [COMCTL32.@]
1191 *
1192 * Requests notification of mouse events
1193 *
1194 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1195 * to the hwnd specified in the ptme structure. After the event message
1196 * is posted to the hwnd, the entry in the queue is removed.
1197 *
1198 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1199 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1200 * immediately and the TME_LEAVE flag being ignored.
1201 *
1202 * PARAMS
1203 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1204 *
1205 * RETURNS
1206 * Success: non-zero
1207 * Failure: zero
1208 *
1209 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1210 *
1211 */
1212
1213 BOOL WINAPI
_TrackMouseEvent(TRACKMOUSEEVENT * ptme)1214 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1215 {
1216 return TrackMouseEvent (ptme);
1217 }
1218
1219 /*************************************************************************
1220 * GetMUILanguage [COMCTL32.@]
1221 *
1222 * Returns the user interface language in use by the current process.
1223 *
1224 * RETURNS
1225 * Language ID in use by the current process.
1226 */
GetMUILanguage(VOID)1227 LANGID WINAPI GetMUILanguage (VOID)
1228 {
1229 return COMCTL32_uiLang;
1230 }
1231
1232
1233 /*************************************************************************
1234 * InitMUILanguage [COMCTL32.@]
1235 *
1236 * Sets the user interface language to be used by the current process.
1237 *
1238 * RETURNS
1239 * Nothing.
1240 */
InitMUILanguage(LANGID uiLang)1241 VOID WINAPI InitMUILanguage (LANGID uiLang)
1242 {
1243 COMCTL32_uiLang = uiLang;
1244 }
1245
1246
1247 /***********************************************************************
1248 * SetWindowSubclass [COMCTL32.410]
1249 *
1250 * Starts a window subclass
1251 *
1252 * PARAMS
1253 * hWnd [in] handle to window subclass.
1254 * pfnSubclass [in] Pointer to new window procedure.
1255 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1256 * dwRef [in] Reference data to pass to window procedure.
1257 *
1258 * RETURNS
1259 * Success: non-zero
1260 * Failure: zero
1261 *
1262 * BUGS
1263 * If an application manually subclasses a window after subclassing it with
1264 * this API and then with this API again, then none of the previous
1265 * subclasses get called or the original window procedure.
1266 */
1267
SetWindowSubclass(HWND hWnd,SUBCLASSPROC pfnSubclass,UINT_PTR uIDSubclass,DWORD_PTR dwRef)1268 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1269 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1270 {
1271 LPSUBCLASS_INFO stack;
1272 LPSUBCLASSPROCS proc;
1273
1274 TRACE ("(%p, %p, %lx, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1275
1276 if (!hWnd || !pfnSubclass)
1277 return FALSE;
1278
1279 /* Since the window procedure that we set here has two additional arguments,
1280 * we can't simply set it as the new window procedure of the window. So we
1281 * set our own window procedure and then calculate the other two arguments
1282 * from there. */
1283
1284 /* See if we have been called for this window */
1285 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1286 if (!stack) {
1287 /* allocate stack */
1288 stack = Alloc (sizeof(SUBCLASS_INFO));
1289 if (!stack) {
1290 ERR ("Failed to allocate our Subclassing stack\n");
1291 return FALSE;
1292 }
1293 SetPropW (hWnd, COMCTL32_wSubclass, stack);
1294
1295 /* set window procedure to our own and save the current one */
1296 if (IsWindowUnicode (hWnd))
1297 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1298 (DWORD_PTR)COMCTL32_SubclassProc);
1299 else
1300 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1301 (DWORD_PTR)COMCTL32_SubclassProc);
1302 }
1303 else {
1304 /* Check to see if we have called this function with the same uIDSubClass
1305 * and pfnSubclass */
1306 proc = stack->SubclassProcs;
1307 while (proc) {
1308 if ((proc->id == uIDSubclass) &&
1309 (proc->subproc == pfnSubclass)) {
1310 proc->ref = dwRef;
1311 return TRUE;
1312 }
1313 proc = proc->next;
1314 }
1315 }
1316
1317 proc = Alloc(sizeof(SUBCLASSPROCS));
1318 if (!proc) {
1319 ERR ("Failed to allocate subclass entry in stack\n");
1320 if (IsWindowUnicode (hWnd))
1321 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1322 else
1323 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1324 Free (stack);
1325 RemovePropW( hWnd, COMCTL32_wSubclass );
1326 return FALSE;
1327 }
1328
1329 proc->subproc = pfnSubclass;
1330 proc->ref = dwRef;
1331 proc->id = uIDSubclass;
1332 proc->next = stack->SubclassProcs;
1333 stack->SubclassProcs = proc;
1334
1335 return TRUE;
1336 }
1337
1338
1339 /***********************************************************************
1340 * GetWindowSubclass [COMCTL32.411]
1341 *
1342 * Gets the Reference data from a subclass.
1343 *
1344 * PARAMS
1345 * hWnd [in] Handle to the window which we are subclassing
1346 * pfnSubclass [in] Pointer to the subclass procedure
1347 * uID [in] Unique identifier of the subclassing procedure
1348 * pdwRef [out] Pointer to the reference data
1349 *
1350 * RETURNS
1351 * Success: Non-zero
1352 * Failure: 0
1353 */
1354
GetWindowSubclass(HWND hWnd,SUBCLASSPROC pfnSubclass,UINT_PTR uID,DWORD_PTR * pdwRef)1355 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1356 UINT_PTR uID, DWORD_PTR *pdwRef)
1357 {
1358 const SUBCLASS_INFO *stack;
1359 const SUBCLASSPROCS *proc;
1360
1361 TRACE ("(%p, %p, %lx, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1362
1363 /* See if we have been called for this window */
1364 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1365 if (!stack)
1366 return FALSE;
1367
1368 proc = stack->SubclassProcs;
1369 while (proc) {
1370 if ((proc->id == uID) &&
1371 (proc->subproc == pfnSubclass)) {
1372 *pdwRef = proc->ref;
1373 return TRUE;
1374 }
1375 proc = proc->next;
1376 }
1377
1378 return FALSE;
1379 }
1380
1381
1382 /***********************************************************************
1383 * RemoveWindowSubclass [COMCTL32.412]
1384 *
1385 * Removes a window subclass.
1386 *
1387 * PARAMS
1388 * hWnd [in] Handle to the window which we are subclassing
1389 * pfnSubclass [in] Pointer to the subclass procedure
1390 * uID [in] Unique identifier of this subclass
1391 *
1392 * RETURNS
1393 * Success: non-zero
1394 * Failure: zero
1395 */
1396
RemoveWindowSubclass(HWND hWnd,SUBCLASSPROC pfnSubclass,UINT_PTR uID)1397 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1398 {
1399 LPSUBCLASS_INFO stack;
1400 LPSUBCLASSPROCS prevproc = NULL;
1401 LPSUBCLASSPROCS proc;
1402 BOOL ret = FALSE;
1403
1404 TRACE ("(%p, %p, %lx)\n", hWnd, pfnSubclass, uID);
1405
1406 /* Find the Subclass to remove */
1407 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1408 if (!stack)
1409 return FALSE;
1410
1411 proc = stack->SubclassProcs;
1412 while (proc) {
1413 if ((proc->id == uID) &&
1414 (proc->subproc == pfnSubclass)) {
1415
1416 if (!prevproc)
1417 stack->SubclassProcs = proc->next;
1418 else
1419 prevproc->next = proc->next;
1420
1421 if (stack->stackpos == proc)
1422 stack->stackpos = stack->stackpos->next;
1423
1424 Free (proc);
1425 ret = TRUE;
1426 break;
1427 }
1428 prevproc = proc;
1429 proc = proc->next;
1430 }
1431
1432 if (!stack->SubclassProcs && !stack->running) {
1433 TRACE("Last Subclass removed, cleaning up\n");
1434 /* clean up our heap and reset the original window procedure */
1435 if (IsWindowUnicode (hWnd))
1436 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1437 else
1438 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1439 Free (stack);
1440 RemovePropW( hWnd, COMCTL32_wSubclass );
1441 }
1442
1443 return ret;
1444 }
1445
1446 /***********************************************************************
1447 * COMCTL32_SubclassProc (internal)
1448 *
1449 * Window procedure for all subclassed windows.
1450 * Saves the current subclassing stack position to support nested messages
1451 */
COMCTL32_SubclassProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1452 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1453 {
1454 LPSUBCLASS_INFO stack;
1455 LPSUBCLASSPROCS proc;
1456 LRESULT ret;
1457
1458 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1459
1460 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1461 if (!stack) {
1462 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1463 return 0;
1464 }
1465
1466 /* Save our old stackpos to properly handle nested messages */
1467 proc = stack->stackpos;
1468 stack->stackpos = stack->SubclassProcs;
1469 stack->running++;
1470 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1471 stack->running--;
1472 stack->stackpos = proc;
1473
1474 if (!stack->SubclassProcs && !stack->running) {
1475 TRACE("Last Subclass removed, cleaning up\n");
1476 /* clean up our heap and reset the original window procedure */
1477 if (IsWindowUnicode (hWnd))
1478 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1479 else
1480 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1481 Free (stack);
1482 RemovePropW( hWnd, COMCTL32_wSubclass );
1483 }
1484 return ret;
1485 }
1486
1487 /***********************************************************************
1488 * DefSubclassProc [COMCTL32.413]
1489 *
1490 * Calls the next window procedure (i.e. the one before this subclass)
1491 *
1492 * PARAMS
1493 * hWnd [in] The window that we're subclassing
1494 * uMsg [in] Message
1495 * wParam [in] WPARAM
1496 * lParam [in] LPARAM
1497 *
1498 * RETURNS
1499 * Success: non-zero
1500 * Failure: zero
1501 */
1502
DefSubclassProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1503 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1504 {
1505 LPSUBCLASS_INFO stack;
1506 LRESULT ret;
1507
1508 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1509
1510 /* retrieve our little stack from the Properties */
1511 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1512 if (!stack) {
1513 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1514 return 0;
1515 }
1516
1517 /* If we are at the end of stack then we have to call the original
1518 * window procedure */
1519 if (!stack->stackpos) {
1520 if (IsWindowUnicode (hWnd))
1521 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1522 else
1523 ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1524 } else {
1525 const SUBCLASSPROCS *proc = stack->stackpos;
1526 stack->stackpos = stack->stackpos->next;
1527 /* call the Subclass procedure from the stack */
1528 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1529 proc->id, proc->ref);
1530 }
1531
1532 return ret;
1533 }
1534
1535
1536 /***********************************************************************
1537 * COMCTL32_CreateToolTip [NOT AN API]
1538 *
1539 * Creates a tooltip for the control specified in hwnd and does all
1540 * necessary setup and notifications.
1541 *
1542 * PARAMS
1543 * hwndOwner [I] Handle to the window that will own the tool tip.
1544 *
1545 * RETURNS
1546 * Success: Handle of tool tip window.
1547 * Failure: NULL
1548 */
1549
1550 HWND
COMCTL32_CreateToolTip(HWND hwndOwner)1551 COMCTL32_CreateToolTip(HWND hwndOwner)
1552 {
1553 HWND hwndToolTip;
1554
1555 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1556 CW_USEDEFAULT, CW_USEDEFAULT,
1557 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1558 0, 0, 0);
1559
1560 /* Send NM_TOOLTIPSCREATED notification */
1561 if (hwndToolTip)
1562 {
1563 NMTOOLTIPSCREATED nmttc;
1564 /* true owner can be different if hwndOwner is a child window */
1565 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1566 nmttc.hdr.hwndFrom = hwndTrueOwner;
1567 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1568 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1569 nmttc.hwndToolTips = hwndToolTip;
1570
1571 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1572 GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
1573 }
1574
1575 return hwndToolTip;
1576 }
1577
1578
1579 /***********************************************************************
1580 * COMCTL32_RefreshSysColors [NOT AN API]
1581 *
1582 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1583 * refresh the color values in the color structure
1584 *
1585 * PARAMS
1586 * none
1587 *
1588 * RETURNS
1589 * none
1590 */
1591
1592 VOID
COMCTL32_RefreshSysColors(void)1593 COMCTL32_RefreshSysColors(void)
1594 {
1595 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1596 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1597 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1598 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1599 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1600 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1601 comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1602 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1603 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1604 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1605 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1606 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1607 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1608 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1609 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1610 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1611 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1612 }
1613
1614 /***********************************************************************
1615 * COMCTL32_DrawInsertMark [NOT AN API]
1616 *
1617 * Draws an insertion mark (which looks similar to an 'I').
1618 *
1619 * PARAMS
1620 * hDC [I] Device context to draw onto.
1621 * lpRect [I] Co-ordinates of insertion mark.
1622 * clrInsertMark [I] Colour of the insertion mark.
1623 * bHorizontal [I] True if insert mark should be drawn horizontally,
1624 * vertical otherwise.
1625 *
1626 * RETURNS
1627 * none
1628 *
1629 * NOTES
1630 * Draws up to but not including the bottom co-ordinate when drawing
1631 * vertically or the right co-ordinate when horizontal.
1632 */
COMCTL32_DrawInsertMark(HDC hDC,const RECT * lpRect,COLORREF clrInsertMark,BOOL bHorizontal)1633 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1634 {
1635 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1636 HPEN hOldPen;
1637 static const DWORD adwPolyPoints[] = {4,4,4};
1638 LONG lCentre = (bHorizontal ?
1639 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1640 lpRect->left + (lpRect->right - lpRect->left)/2);
1641 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1642 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1643 const POINT aptInsertMark[] =
1644 {
1645 /* top (V) or left (H) arrow */
1646 {lCentre , l1 + 2},
1647 {lCentre - 2, l1 },
1648 {lCentre + 3, l1 },
1649 {lCentre + 1, l1 + 2},
1650 /* middle line */
1651 {lCentre , l2 - 2},
1652 {lCentre , l1 - 1},
1653 {lCentre + 1, l1 - 1},
1654 {lCentre + 1, l2 - 2},
1655 /* bottom (V) or right (H) arrow */
1656 {lCentre , l2 - 3},
1657 {lCentre - 2, l2 - 1},
1658 {lCentre + 3, l2 - 1},
1659 {lCentre + 1, l2 - 3},
1660 };
1661 hOldPen = SelectObject(hDC, hPen);
1662 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, ARRAY_SIZE(adwPolyPoints));
1663 SelectObject(hDC, hOldPen);
1664 DeleteObject(hPen);
1665 }
1666
1667 /***********************************************************************
1668 * COMCTL32_EnsureBitmapSize [internal]
1669 *
1670 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1671 * the height is at least cyMinHeight. If the bitmap already has these
1672 * dimensions nothing changes.
1673 *
1674 * PARAMS
1675 * hBitmap [I/O] Bitmap to modify. The handle may change
1676 * cxMinWidth [I] If the width of the bitmap is smaller, then it will
1677 * be enlarged to this value
1678 * cyMinHeight [I] If the height of the bitmap is smaller, then it will
1679 * be enlarged to this value
1680 * cyBackground [I] The color with which the new area will be filled
1681 *
1682 * RETURNS
1683 * none
1684 */
COMCTL32_EnsureBitmapSize(HBITMAP * pBitmap,int cxMinWidth,int cyMinHeight,COLORREF crBackground)1685 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1686 {
1687 int cxNew, cyNew;
1688 BITMAP bmp;
1689 HBITMAP hNewBitmap;
1690 HBITMAP hNewDCBitmap, hOldDCBitmap;
1691 HBRUSH hNewDCBrush;
1692 HDC hdcNew, hdcOld;
1693
1694 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1695 return;
1696 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1697 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1698 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1699 return;
1700
1701 hdcNew = CreateCompatibleDC(NULL);
1702 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1703 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1704 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1705
1706 hdcOld = CreateCompatibleDC(NULL);
1707 hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1708
1709 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1710 if (bmp.bmWidth < cxMinWidth)
1711 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1712 if (bmp.bmHeight < cyMinHeight)
1713 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1714 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1715 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1716
1717 SelectObject(hdcNew, hNewDCBitmap);
1718 DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1719 DeleteDC(hdcNew);
1720 SelectObject(hdcOld, hOldDCBitmap);
1721 DeleteDC(hdcOld);
1722
1723 DeleteObject(*pBitmap);
1724 *pBitmap = hNewBitmap;
1725 return;
1726 }
1727
COMCTL32_GetFontMetrics(HFONT hFont,TEXTMETRICW * ptm)1728 void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
1729 {
1730 HDC hdc = GetDC(NULL);
1731 HFONT hOldFont;
1732
1733 hOldFont = SelectObject(hdc, hFont);
1734 GetTextMetricsW(hdc, ptm);
1735 SelectObject(hdc, hOldFont);
1736 ReleaseDC(NULL, hdc);
1737 }
1738
1739 #ifndef OCM__BASE /* avoid including olectl.h */
1740 #define OCM__BASE (WM_USER+0x1c00)
1741 #endif
1742
1743 /***********************************************************************
1744 * COMCTL32_IsReflectedMessage [internal]
1745 *
1746 * Some parents reflect notify messages - for some messages sent by the child,
1747 * they send it back with the message code increased by OCM__BASE (0x2000).
1748 * This allows better subclassing of controls. We don't need to handle such
1749 * messages but we don't want to print ERRs for them, so this helper function
1750 * identifies them.
1751 *
1752 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1753 * collision with defined CCM_ codes.
1754 */
COMCTL32_IsReflectedMessage(UINT uMsg)1755 BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
1756 {
1757 switch (uMsg)
1758 {
1759 case OCM__BASE + WM_COMMAND:
1760 case OCM__BASE + WM_CTLCOLORBTN:
1761 case OCM__BASE + WM_CTLCOLOREDIT:
1762 case OCM__BASE + WM_CTLCOLORDLG:
1763 case OCM__BASE + WM_CTLCOLORLISTBOX:
1764 case OCM__BASE + WM_CTLCOLORMSGBOX:
1765 case OCM__BASE + WM_CTLCOLORSCROLLBAR:
1766 case OCM__BASE + WM_CTLCOLORSTATIC:
1767 case OCM__BASE + WM_DRAWITEM:
1768 case OCM__BASE + WM_MEASUREITEM:
1769 case OCM__BASE + WM_DELETEITEM:
1770 case OCM__BASE + WM_VKEYTOITEM:
1771 case OCM__BASE + WM_CHARTOITEM:
1772 case OCM__BASE + WM_COMPAREITEM:
1773 case OCM__BASE + WM_HSCROLL:
1774 case OCM__BASE + WM_VSCROLL:
1775 case OCM__BASE + WM_PARENTNOTIFY:
1776 case OCM__BASE + WM_NOTIFY:
1777 return TRUE;
1778 default:
1779 return FALSE;
1780 }
1781 }
1782
1783 /***********************************************************************
1784 * MirrorIcon [COMCTL32.414]
1785 *
1786 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1787 *
1788 * PARAMS
1789 * phicon1 [I/O] Icon.
1790 * phicon2 [I/O] Icon.
1791 *
1792 * RETURNS
1793 * Success: TRUE.
1794 * Failure: FALSE.
1795 */
MirrorIcon(HICON * phicon1,HICON * phicon2)1796 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1797 {
1798 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1799 return FALSE;
1800 }
1801
IsDelimiter(WCHAR c)1802 static inline BOOL IsDelimiter(WCHAR c)
1803 {
1804 switch(c)
1805 {
1806 case '/':
1807 case '\\':
1808 case '.':
1809 case ' ':
1810 return TRUE;
1811 }
1812 return FALSE;
1813 }
1814
PathWordBreakProc(LPCWSTR lpch,int ichCurrent,int cch,int code)1815 static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1816 {
1817 if (code == WB_ISDELIMITER)
1818 return IsDelimiter(lpch[ichCurrent]);
1819 else
1820 {
1821 int dir = (code == WB_LEFT) ? -1 : 1;
1822 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1823 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1824 }
1825 return ichCurrent;
1826 }
1827
1828 /***********************************************************************
1829 * SetPathWordBreakProc [COMCTL32.384]
1830 *
1831 * Sets the word break procedure for an edit control to one that understands
1832 * paths so that the user can jump over directories.
1833 *
1834 * PARAMS
1835 * hwnd [I] Handle to edit control.
1836 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1837 *
1838 * RETURNS
1839 * Result from EM_SETWORDBREAKPROC message.
1840 */
SetPathWordBreakProc(HWND hwnd,BOOL bSet)1841 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1842 {
1843 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1844 (LPARAM)(bSet ? PathWordBreakProc : NULL));
1845 }
1846
1847 /***********************************************************************
1848 * DrawShadowText [COMCTL32.@]
1849 *
1850 * Draw text with shadow.
1851 */
DrawShadowText(HDC hdc,LPCWSTR pszText,UINT cch,RECT * prc,DWORD dwFlags,COLORREF crText,COLORREF crShadow,int ixOffset,int iyOffset)1852 int WINAPI DrawShadowText(HDC hdc, LPCWSTR pszText, UINT cch, RECT *prc, DWORD dwFlags,
1853 COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset)
1854 {
1855 COLORREF crOldText;
1856 RECT rcText;
1857 INT iRet, x, y, x2, y2;
1858 BYTE *pBits;
1859 HBITMAP hbm, hbmOld;
1860 BITMAPINFO bi;
1861 HDC hdcMem;
1862 HFONT hOldFont;
1863 BLENDFUNCTION bf;
1864
1865 /* Create 32 bit DIB section for the shadow */
1866 ZeroMemory(&bi, sizeof(bi));
1867 bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
1868 bi.bmiHeader.biWidth = prc->right - prc->left + 4;
1869 bi.bmiHeader.biHeight = prc->bottom - prc->top + 5; // bottom-up DIB
1870 bi.bmiHeader.biPlanes = 1;
1871 bi.bmiHeader.biBitCount = 32;
1872 bi.bmiHeader.biCompression = BI_RGB;
1873 hbm = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, (PVOID*)&pBits, NULL, 0);
1874 if(!hbm)
1875 {
1876 ERR("CreateDIBSection failed\n");
1877 return 0;
1878 }
1879
1880 /* Create memory device context for new DIB section and select it */
1881 hdcMem = CreateCompatibleDC(hdc);
1882 if(!hdcMem)
1883 {
1884 ERR("CreateCompatibleDC failed\n");
1885 DeleteObject(hbm);
1886 return 0;
1887 }
1888
1889 hbmOld = (HBITMAP)SelectObject(hdcMem, hbm);
1890
1891 /* Draw text on our helper bitmap */
1892 hOldFont = (HFONT)SelectObject(hdcMem, GetCurrentObject(hdc, OBJ_FONT));
1893 SetTextColor(hdcMem, RGB(16, 16, 16));
1894 SetBkColor(hdcMem, RGB(0, 0, 0));
1895 SetBkMode(hdcMem, TRANSPARENT);
1896 SetRect(&rcText, 0, 0, prc->right - prc->left, prc->bottom - prc->top);
1897 DrawTextW(hdcMem, pszText, cch, &rcText, dwFlags);
1898 SelectObject(hdcMem, hOldFont);
1899
1900 /* Flush GDI so data pointed by pBits is valid */
1901 GdiFlush();
1902
1903 /* Set alpha of pixels (forget about colors for now. They will be changed in next loop).
1904 We copy text image 4*5 times and each time alpha is added */
1905 for (x = 0; x < bi.bmiHeader.biWidth; ++x)
1906 for (y = 0; y < bi.bmiHeader.biHeight; ++y)
1907 {
1908 BYTE *pDest = &pBits[(y * bi.bmiHeader.biWidth + x) * 4];
1909 UINT Alpha = 0;
1910
1911 for (x2 = x - 4 + 1; x2 <= x; ++x2)
1912 for (y2 = y; y2 < y + 5; ++y2)
1913 {
1914 if (x2 >= 0 && x2 < bi.bmiHeader.biWidth && y2 >= 0 && y2 < bi.bmiHeader.biHeight)
1915 {
1916 BYTE *pSrc = &pBits[(y2 * bi.bmiHeader.biWidth + x2) * 4];
1917 Alpha += pSrc[0];
1918 }
1919 }
1920
1921 if (Alpha > 255)
1922 Alpha = 255;
1923 pDest[3] = Alpha;
1924 }
1925
1926 /* Now set the color of each pixel to shadow color * alpha (see GdiAlphaBlend) */
1927 for (x = 0; x < bi.bmiHeader.biWidth; ++x)
1928 for (y = 0; y < bi.bmiHeader.biHeight; ++y)
1929 {
1930 BYTE *pDest = &pBits[(y * bi.bmiHeader.biWidth + x) * 4];
1931 pDest[0] = GetBValue(crShadow) * pDest[3] / 255;
1932 pDest[1] = GetGValue(crShadow) * pDest[3] / 255;
1933 pDest[2] = GetRValue(crShadow) * pDest[3] / 255;
1934 }
1935
1936 /* Fix ixOffset of the shadow (tested on Win) */
1937 ixOffset -= 3;
1938 iyOffset -= 3;
1939
1940 /* Alpha blend helper image to destination DC */
1941 bf.BlendOp = AC_SRC_OVER;
1942 bf.BlendFlags = 0;
1943 bf.SourceConstantAlpha = 255;
1944 bf.AlphaFormat = AC_SRC_ALPHA;
1945 GdiAlphaBlend(hdc, prc->left + ixOffset, prc->top + iyOffset, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, hdcMem, 0, 0, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, bf);
1946
1947 /* Delete the helper bitmap */
1948 SelectObject(hdcMem, hbmOld);
1949 DeleteObject(hbm);
1950 DeleteDC(hdcMem);
1951
1952 /* Finally draw the text over shadow */
1953 crOldText = SetTextColor(hdc, crText);
1954 SetBkMode(hdc, TRANSPARENT);
1955 iRet = DrawTextW(hdc, pszText, cch, prc, dwFlags);
1956 SetTextColor(hdc, crOldText);
1957
1958 return iRet;
1959 }
1960
1961 /***********************************************************************
1962 * LoadIconWithScaleDown [COMCTL32.@]
1963 */
LoadIconWithScaleDown(HINSTANCE hinst,const WCHAR * name,int cx,int cy,HICON * icon)1964 HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
1965 {
1966 TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
1967
1968 *icon = NULL;
1969
1970 if (!name)
1971 return E_INVALIDARG;
1972
1973 *icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
1974 (hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
1975 if (!*icon)
1976 return HRESULT_FROM_WIN32(GetLastError());
1977
1978 return S_OK;
1979 }
1980
1981 /***********************************************************************
1982 * LoadIconMetric [COMCTL32.@]
1983 */
LoadIconMetric(HINSTANCE hinst,const WCHAR * name,int size,HICON * icon)1984 HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
1985 {
1986 int cx, cy;
1987
1988 TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
1989
1990 if (size == LIM_SMALL)
1991 {
1992 cx = GetSystemMetrics(SM_CXSMICON);
1993 cy = GetSystemMetrics(SM_CYSMICON);
1994 }
1995 else if (size == LIM_LARGE)
1996 {
1997 cx = GetSystemMetrics(SM_CXICON);
1998 cy = GetSystemMetrics(SM_CYICON);
1999 }
2000 else
2001 {
2002 *icon = NULL;
2003 return E_INVALIDARG;
2004 }
2005
2006 return LoadIconWithScaleDown(hinst, name, cx, cy, icon);
2007 }
2008