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 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 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 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 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 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 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 */ 296 BOOLEAN WINAPI RegisterClassNameW(LPCWSTR className) 297 { 298 InitializeClasses(); 299 return TRUE; 300 } 301 302 #endif /* __REACTOS__ */ 303 304 #ifndef __REACTOS__ 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 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 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 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 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 677 void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style) 678 { 679 RECT r = *lprc; 680 UINT border = BDR_SUNKENOUTER; 681 682 if (style & SBT_POPOUT) 683 border = BDR_RAISEDOUTER; 684 else if (style & SBT_NOBORDERS) 685 border = 0; 686 687 DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST); 688 689 /* now draw text */ 690 if (text) { 691 int oldbkmode = SetBkMode (hdc, TRANSPARENT); 692 UINT align = DT_LEFT; 693 int strCnt = 0; 694 695 if (style & SBT_RTLREADING) 696 FIXME("Unsupported RTL style!\n"); 697 r.left += 3; 698 do { 699 if (*text == '\t') { 700 if (strCnt) { 701 DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX); 702 strCnt = 0; 703 } 704 if (align==DT_RIGHT) { 705 break; 706 } 707 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT); 708 } else { 709 strCnt++; 710 } 711 } while(*text++); 712 713 if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX); 714 SetBkMode(hdc, oldbkmode); 715 } 716 } 717 718 719 /*********************************************************************** 720 * DrawStatusText [COMCTL32.@] 721 * DrawStatusTextA [COMCTL32.5] 722 * 723 * Draws text with borders, like in a status bar. 724 * 725 * PARAMS 726 * hdc [I] handle to the window's display context 727 * lprc [I] pointer to a rectangle 728 * text [I] pointer to the text 729 * style [I] drawing style 730 * 731 * RETURNS 732 * No return value. 733 */ 734 735 void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style) 736 { 737 INT len; 738 LPWSTR textW = NULL; 739 740 if ( text ) { 741 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) { 742 if ( (textW = Alloc( len * sizeof(WCHAR) )) ) 743 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len ); 744 } 745 } 746 DrawStatusTextW( hdc, lprc, textW, style ); 747 Free( textW ); 748 } 749 750 751 /*********************************************************************** 752 * CreateStatusWindow [COMCTL32.@] 753 * CreateStatusWindowA [COMCTL32.6] 754 * 755 * Creates a status bar 756 * 757 * PARAMS 758 * style [I] window style 759 * text [I] pointer to the window text 760 * parent [I] handle to the parent window 761 * wid [I] control id of the status bar 762 * 763 * RETURNS 764 * Success: handle to the status window 765 * Failure: 0 766 */ 767 768 HWND WINAPI 769 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid) 770 { 771 return CreateWindowA(STATUSCLASSNAMEA, text, style, 772 CW_USEDEFAULT, CW_USEDEFAULT, 773 CW_USEDEFAULT, CW_USEDEFAULT, 774 parent, (HMENU)(DWORD_PTR)wid, 0, 0); 775 } 776 777 778 /*********************************************************************** 779 * CreateStatusWindowW [COMCTL32.@] 780 * 781 * Creates a status bar control 782 * 783 * PARAMS 784 * style [I] window style 785 * text [I] pointer to the window text 786 * parent [I] handle to the parent window 787 * wid [I] control id of the status bar 788 * 789 * RETURNS 790 * Success: handle to the status window 791 * Failure: 0 792 */ 793 794 HWND WINAPI 795 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid) 796 { 797 return CreateWindowW(STATUSCLASSNAMEW, text, style, 798 CW_USEDEFAULT, CW_USEDEFAULT, 799 CW_USEDEFAULT, CW_USEDEFAULT, 800 parent, (HMENU)(DWORD_PTR)wid, 0, 0); 801 } 802 803 804 /*********************************************************************** 805 * CreateUpDownControl [COMCTL32.16] 806 * 807 * Creates an up-down control 808 * 809 * PARAMS 810 * style [I] window styles 811 * x [I] horizontal position of the control 812 * y [I] vertical position of the control 813 * cx [I] with of the control 814 * cy [I] height of the control 815 * parent [I] handle to the parent window 816 * id [I] the control's identifier 817 * inst [I] handle to the application's module instance 818 * buddy [I] handle to the buddy window, can be NULL 819 * maxVal [I] upper limit of the control 820 * minVal [I] lower limit of the control 821 * curVal [I] current value of the control 822 * 823 * RETURNS 824 * Success: handle to the updown control 825 * Failure: 0 826 */ 827 828 HWND WINAPI 829 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy, 830 HWND parent, INT id, HINSTANCE inst, 831 HWND buddy, INT maxVal, INT minVal, INT curVal) 832 { 833 HWND hUD = 834 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy, 835 parent, (HMENU)(DWORD_PTR)id, inst, 0); 836 if (hUD) { 837 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0); 838 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal)); 839 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0)); 840 } 841 842 return hUD; 843 } 844 845 846 /*********************************************************************** 847 * InitCommonControls [COMCTL32.17] 848 * 849 * Registers the common controls. 850 * 851 * PARAMS 852 * No parameters. 853 * 854 * RETURNS 855 * No return values. 856 * 857 * NOTES 858 * This function is just a dummy - all the controls are registered at 859 * the DLL initialization time. See InitCommonContolsEx for details. 860 */ 861 862 VOID WINAPI 863 InitCommonControls (void) 864 { 865 } 866 867 868 /*********************************************************************** 869 * InitCommonControlsEx [COMCTL32.@] 870 * 871 * Registers the common controls. 872 * 873 * PARAMS 874 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure. 875 * 876 * RETURNS 877 * Success: TRUE 878 * Failure: FALSE 879 * 880 * NOTES 881 * Probably all versions of comctl32 initializes the Win95 controls in DllMain 882 * during DLL initialization. Starting from comctl32 v5.82 all the controls 883 * are initialized there. We follow this behaviour and this function is just 884 * a dummy. 885 * 886 * Note: when writing programs under Windows, if you don't call any function 887 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx 888 * was the only comctl32 function you were calling and you remove it you may 889 * have a false impression that InitCommonControlsEx actually did something. 890 */ 891 892 BOOL WINAPI 893 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls) 894 { 895 if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX)) 896 return FALSE; 897 898 TRACE("(0x%08x)\n", lpInitCtrls->dwICC); 899 return TRUE; 900 } 901 902 903 /*********************************************************************** 904 * CreateToolbarEx [COMCTL32.@] 905 * 906 * Creates a toolbar window. 907 * 908 * PARAMS 909 * hwnd 910 * style 911 * wID 912 * nBitmaps 913 * hBMInst 914 * wBMID 915 * lpButtons 916 * iNumButtons 917 * dxButton 918 * dyButton 919 * dxBitmap 920 * dyBitmap 921 * uStructSize 922 * 923 * RETURNS 924 * Success: handle to the tool bar control 925 * Failure: 0 926 */ 927 928 HWND WINAPI 929 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps, 930 HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons, 931 INT iNumButtons, INT dxButton, INT dyButton, 932 INT dxBitmap, INT dyBitmap, UINT uStructSize) 933 { 934 HWND hwndTB; 935 936 hwndTB = 937 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30, 938 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL); 939 if(hwndTB) { 940 TBADDBITMAP tbab; 941 942 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0); 943 944 /* set bitmap and button size */ 945 /*If CreateToolbarEx receives 0, windows sets default values*/ 946 if (dxBitmap < 0) 947 dxBitmap = 16; 948 if (dyBitmap < 0) 949 dyBitmap = 16; 950 if (dxBitmap == 0 || dyBitmap == 0) 951 dxBitmap = dyBitmap = 16; 952 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap)); 953 954 if (dxButton < 0) 955 dxButton = dxBitmap; 956 if (dyButton < 0) 957 dyButton = dyBitmap; 958 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */ 959 if (dxButton != 0 && dyButton != 0) 960 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton)); 961 962 963 /* add bitmaps */ 964 if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL) 965 { 966 tbab.hInst = hBMInst; 967 tbab.nID = wBMID; 968 969 SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab); 970 } 971 /* add buttons */ 972 if(iNumButtons > 0) 973 SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons); 974 } 975 976 return hwndTB; 977 } 978 979 980 /*********************************************************************** 981 * CreateMappedBitmap [COMCTL32.8] 982 * 983 * Loads a bitmap resource using a colour map. 984 * 985 * PARAMS 986 * hInstance [I] Handle to the module containing the bitmap. 987 * idBitmap [I] The bitmap resource ID. 988 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal. 989 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours). 990 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap. 991 * 992 * RETURNS 993 * Success: handle to the new bitmap 994 * Failure: 0 995 */ 996 997 HBITMAP WINAPI 998 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags, 999 LPCOLORMAP lpColorMap, INT iNumMaps) 1000 { 1001 HGLOBAL hglb; 1002 HRSRC hRsrc; 1003 const BITMAPINFOHEADER *lpBitmap; 1004 LPBITMAPINFOHEADER lpBitmapInfo; 1005 UINT nSize, nColorTableSize, iColor; 1006 RGBQUAD *pColorTable; 1007 INT i, iMaps, nWidth, nHeight; 1008 HDC hdcScreen; 1009 HBITMAP hbm; 1010 LPCOLORMAP sysColorMap; 1011 COLORREF cRef; 1012 COLORMAP internalColorMap[4] = 1013 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}}; 1014 1015 /* initialize pointer to colortable and default color table */ 1016 if (lpColorMap) { 1017 iMaps = iNumMaps; 1018 sysColorMap = lpColorMap; 1019 } 1020 else { 1021 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT); 1022 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW); 1023 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE); 1024 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT); 1025 iMaps = 4; 1026 sysColorMap = internalColorMap; 1027 } 1028 1029 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP); 1030 if (hRsrc == 0) 1031 return 0; 1032 hglb = LoadResource (hInstance, hRsrc); 1033 if (hglb == 0) 1034 return 0; 1035 lpBitmap = LockResource (hglb); 1036 if (lpBitmap == NULL) 1037 return 0; 1038 1039 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed) 1040 nColorTableSize = lpBitmap->biClrUsed; 1041 else if (lpBitmap->biBitCount <= 8) 1042 nColorTableSize = (1 << lpBitmap->biBitCount); 1043 else 1044 nColorTableSize = 0; 1045 nSize = lpBitmap->biSize; 1046 if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS) 1047 nSize += 3 * sizeof(DWORD); 1048 nSize += nColorTableSize * sizeof(RGBQUAD); 1049 lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize); 1050 if (lpBitmapInfo == NULL) 1051 return 0; 1052 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize); 1053 1054 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize); 1055 1056 for (iColor = 0; iColor < nColorTableSize; iColor++) { 1057 for (i = 0; i < iMaps; i++) { 1058 cRef = RGB(pColorTable[iColor].rgbRed, 1059 pColorTable[iColor].rgbGreen, 1060 pColorTable[iColor].rgbBlue); 1061 if ( cRef == sysColorMap[i].from) { 1062 #if 0 1063 if (wFlags & CBS_MASKED) { 1064 if (sysColorMap[i].to != COLOR_BTNTEXT) 1065 pColorTable[iColor] = RGB(255, 255, 255); 1066 } 1067 else 1068 #endif 1069 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to); 1070 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to); 1071 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to); 1072 break; 1073 } 1074 } 1075 } 1076 nWidth = lpBitmapInfo->biWidth; 1077 nHeight = lpBitmapInfo->biHeight; 1078 hdcScreen = GetDC (NULL); 1079 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight); 1080 if (hbm) { 1081 HDC hdcDst = CreateCompatibleDC (hdcScreen); 1082 HBITMAP hbmOld = SelectObject (hdcDst, hbm); 1083 const BYTE *lpBits = (const BYTE *)lpBitmap + nSize; 1084 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight, 1085 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS, 1086 SRCCOPY); 1087 SelectObject (hdcDst, hbmOld); 1088 DeleteDC (hdcDst); 1089 } 1090 ReleaseDC (NULL, hdcScreen); 1091 GlobalFree (lpBitmapInfo); 1092 FreeResource (hglb); 1093 1094 return hbm; 1095 } 1096 1097 1098 /*********************************************************************** 1099 * CreateToolbar [COMCTL32.7] 1100 * 1101 * Creates a toolbar control. 1102 * 1103 * PARAMS 1104 * hwnd 1105 * style 1106 * wID 1107 * nBitmaps 1108 * hBMInst 1109 * wBMID 1110 * lpButtons 1111 * iNumButtons 1112 * 1113 * RETURNS 1114 * Success: handle to the tool bar control 1115 * Failure: 0 1116 * 1117 * NOTES 1118 * Do not use this function anymore. Use CreateToolbarEx instead. 1119 */ 1120 1121 HWND WINAPI 1122 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps, 1123 HINSTANCE hBMInst, UINT wBMID, 1124 LPCTBBUTTON lpButtons,INT iNumButtons) 1125 { 1126 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps, 1127 hBMInst, wBMID, lpButtons, 1128 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData)); 1129 } 1130 1131 1132 /*********************************************************************** 1133 * DllGetVersion [COMCTL32.@] 1134 * 1135 * Retrieves version information of the 'COMCTL32.DLL' 1136 * 1137 * PARAMS 1138 * pdvi [O] pointer to version information structure. 1139 * 1140 * RETURNS 1141 * Success: S_OK 1142 * Failure: E_INVALIDARG 1143 * 1144 * NOTES 1145 * Returns version of a comctl32.dll from IE4.01 SP1. 1146 */ 1147 1148 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi) 1149 { 1150 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) { 1151 WARN("wrong DLLVERSIONINFO size from app\n"); 1152 return E_INVALIDARG; 1153 } 1154 1155 pdvi->dwMajorVersion = COMCTL32_VERSION; 1156 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR; 1157 pdvi->dwBuildNumber = 2919; 1158 pdvi->dwPlatformID = 6304; 1159 1160 TRACE("%u.%u.%u.%u\n", 1161 pdvi->dwMajorVersion, pdvi->dwMinorVersion, 1162 pdvi->dwBuildNumber, pdvi->dwPlatformID); 1163 1164 return S_OK; 1165 } 1166 1167 /*********************************************************************** 1168 * DllInstall (COMCTL32.@) 1169 * 1170 * Installs the ComCtl32 DLL. 1171 * 1172 * RETURNS 1173 * Success: S_OK 1174 * Failure: A HRESULT error 1175 */ 1176 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline) 1177 { 1178 TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline)); 1179 return S_OK; 1180 } 1181 1182 /*********************************************************************** 1183 * _TrackMouseEvent [COMCTL32.@] 1184 * 1185 * Requests notification of mouse events 1186 * 1187 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted 1188 * to the hwnd specified in the ptme structure. After the event message 1189 * is posted to the hwnd, the entry in the queue is removed. 1190 * 1191 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely 1192 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted 1193 * immediately and the TME_LEAVE flag being ignored. 1194 * 1195 * PARAMS 1196 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure. 1197 * 1198 * RETURNS 1199 * Success: non-zero 1200 * Failure: zero 1201 * 1202 * IMPLEMENTATION moved to USER32.TrackMouseEvent 1203 * 1204 */ 1205 1206 BOOL WINAPI 1207 _TrackMouseEvent (TRACKMOUSEEVENT *ptme) 1208 { 1209 return TrackMouseEvent (ptme); 1210 } 1211 1212 /************************************************************************* 1213 * GetMUILanguage [COMCTL32.@] 1214 * 1215 * Returns the user interface language in use by the current process. 1216 * 1217 * RETURNS 1218 * Language ID in use by the current process. 1219 */ 1220 LANGID WINAPI GetMUILanguage (VOID) 1221 { 1222 return COMCTL32_uiLang; 1223 } 1224 1225 1226 /************************************************************************* 1227 * InitMUILanguage [COMCTL32.@] 1228 * 1229 * Sets the user interface language to be used by the current process. 1230 * 1231 * RETURNS 1232 * Nothing. 1233 */ 1234 VOID WINAPI InitMUILanguage (LANGID uiLang) 1235 { 1236 COMCTL32_uiLang = uiLang; 1237 } 1238 1239 1240 /*********************************************************************** 1241 * SetWindowSubclass [COMCTL32.410] 1242 * 1243 * Starts a window subclass 1244 * 1245 * PARAMS 1246 * hWnd [in] handle to window subclass. 1247 * pfnSubclass [in] Pointer to new window procedure. 1248 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass. 1249 * dwRef [in] Reference data to pass to window procedure. 1250 * 1251 * RETURNS 1252 * Success: non-zero 1253 * Failure: zero 1254 * 1255 * BUGS 1256 * If an application manually subclasses a window after subclassing it with 1257 * this API and then with this API again, then none of the previous 1258 * subclasses get called or the original window procedure. 1259 */ 1260 1261 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass, 1262 UINT_PTR uIDSubclass, DWORD_PTR dwRef) 1263 { 1264 LPSUBCLASS_INFO stack; 1265 LPSUBCLASSPROCS proc; 1266 1267 TRACE ("(%p, %p, %lx, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef); 1268 1269 if (!hWnd || !pfnSubclass) 1270 return FALSE; 1271 1272 /* Since the window procedure that we set here has two additional arguments, 1273 * we can't simply set it as the new window procedure of the window. So we 1274 * set our own window procedure and then calculate the other two arguments 1275 * from there. */ 1276 1277 /* See if we have been called for this window */ 1278 stack = GetPropW (hWnd, COMCTL32_wSubclass); 1279 if (!stack) { 1280 /* allocate stack */ 1281 stack = Alloc (sizeof(SUBCLASS_INFO)); 1282 if (!stack) { 1283 ERR ("Failed to allocate our Subclassing stack\n"); 1284 return FALSE; 1285 } 1286 SetPropW (hWnd, COMCTL32_wSubclass, stack); 1287 1288 /* set window procedure to our own and save the current one */ 1289 if (IsWindowUnicode (hWnd)) 1290 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC, 1291 (DWORD_PTR)COMCTL32_SubclassProc); 1292 else 1293 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC, 1294 (DWORD_PTR)COMCTL32_SubclassProc); 1295 } 1296 else { 1297 /* Check to see if we have called this function with the same uIDSubClass 1298 * and pfnSubclass */ 1299 proc = stack->SubclassProcs; 1300 while (proc) { 1301 if ((proc->id == uIDSubclass) && 1302 (proc->subproc == pfnSubclass)) { 1303 proc->ref = dwRef; 1304 return TRUE; 1305 } 1306 proc = proc->next; 1307 } 1308 } 1309 1310 proc = Alloc(sizeof(SUBCLASSPROCS)); 1311 if (!proc) { 1312 ERR ("Failed to allocate subclass entry in stack\n"); 1313 if (IsWindowUnicode (hWnd)) 1314 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); 1315 else 1316 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); 1317 Free (stack); 1318 RemovePropW( hWnd, COMCTL32_wSubclass ); 1319 return FALSE; 1320 } 1321 1322 proc->subproc = pfnSubclass; 1323 proc->ref = dwRef; 1324 proc->id = uIDSubclass; 1325 proc->next = stack->SubclassProcs; 1326 stack->SubclassProcs = proc; 1327 1328 return TRUE; 1329 } 1330 1331 1332 /*********************************************************************** 1333 * GetWindowSubclass [COMCTL32.411] 1334 * 1335 * Gets the Reference data from a subclass. 1336 * 1337 * PARAMS 1338 * hWnd [in] Handle to the window which we are subclassing 1339 * pfnSubclass [in] Pointer to the subclass procedure 1340 * uID [in] Unique identifier of the subclassing procedure 1341 * pdwRef [out] Pointer to the reference data 1342 * 1343 * RETURNS 1344 * Success: Non-zero 1345 * Failure: 0 1346 */ 1347 1348 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass, 1349 UINT_PTR uID, DWORD_PTR *pdwRef) 1350 { 1351 const SUBCLASS_INFO *stack; 1352 const SUBCLASSPROCS *proc; 1353 1354 TRACE ("(%p, %p, %lx, %p)\n", hWnd, pfnSubclass, uID, pdwRef); 1355 1356 /* See if we have been called for this window */ 1357 stack = GetPropW (hWnd, COMCTL32_wSubclass); 1358 if (!stack) 1359 return FALSE; 1360 1361 proc = stack->SubclassProcs; 1362 while (proc) { 1363 if ((proc->id == uID) && 1364 (proc->subproc == pfnSubclass)) { 1365 *pdwRef = proc->ref; 1366 return TRUE; 1367 } 1368 proc = proc->next; 1369 } 1370 1371 return FALSE; 1372 } 1373 1374 1375 /*********************************************************************** 1376 * RemoveWindowSubclass [COMCTL32.412] 1377 * 1378 * Removes a window subclass. 1379 * 1380 * PARAMS 1381 * hWnd [in] Handle to the window which we are subclassing 1382 * pfnSubclass [in] Pointer to the subclass procedure 1383 * uID [in] Unique identifier of this subclass 1384 * 1385 * RETURNS 1386 * Success: non-zero 1387 * Failure: zero 1388 */ 1389 1390 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID) 1391 { 1392 LPSUBCLASS_INFO stack; 1393 LPSUBCLASSPROCS prevproc = NULL; 1394 LPSUBCLASSPROCS proc; 1395 BOOL ret = FALSE; 1396 1397 TRACE ("(%p, %p, %lx)\n", hWnd, pfnSubclass, uID); 1398 1399 /* Find the Subclass to remove */ 1400 stack = GetPropW (hWnd, COMCTL32_wSubclass); 1401 if (!stack) 1402 return FALSE; 1403 1404 proc = stack->SubclassProcs; 1405 while (proc) { 1406 if ((proc->id == uID) && 1407 (proc->subproc == pfnSubclass)) { 1408 1409 if (!prevproc) 1410 stack->SubclassProcs = proc->next; 1411 else 1412 prevproc->next = proc->next; 1413 1414 if (stack->stackpos == proc) 1415 stack->stackpos = stack->stackpos->next; 1416 1417 Free (proc); 1418 ret = TRUE; 1419 break; 1420 } 1421 prevproc = proc; 1422 proc = proc->next; 1423 } 1424 1425 if (!stack->SubclassProcs && !stack->running) { 1426 TRACE("Last Subclass removed, cleaning up\n"); 1427 /* clean up our heap and reset the original window procedure */ 1428 if (IsWindowUnicode (hWnd)) 1429 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); 1430 else 1431 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); 1432 Free (stack); 1433 RemovePropW( hWnd, COMCTL32_wSubclass ); 1434 } 1435 1436 return ret; 1437 } 1438 1439 /*********************************************************************** 1440 * COMCTL32_SubclassProc (internal) 1441 * 1442 * Window procedure for all subclassed windows. 1443 * Saves the current subclassing stack position to support nested messages 1444 */ 1445 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 1446 { 1447 LPSUBCLASS_INFO stack; 1448 LPSUBCLASSPROCS proc; 1449 LRESULT ret; 1450 1451 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam); 1452 1453 stack = GetPropW (hWnd, COMCTL32_wSubclass); 1454 if (!stack) { 1455 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd); 1456 return 0; 1457 } 1458 1459 /* Save our old stackpos to properly handle nested messages */ 1460 proc = stack->stackpos; 1461 stack->stackpos = stack->SubclassProcs; 1462 stack->running++; 1463 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam); 1464 stack->running--; 1465 stack->stackpos = proc; 1466 1467 if (!stack->SubclassProcs && !stack->running) { 1468 TRACE("Last Subclass removed, cleaning up\n"); 1469 /* clean up our heap and reset the original window procedure */ 1470 if (IsWindowUnicode (hWnd)) 1471 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); 1472 else 1473 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); 1474 Free (stack); 1475 RemovePropW( hWnd, COMCTL32_wSubclass ); 1476 } 1477 return ret; 1478 } 1479 1480 /*********************************************************************** 1481 * DefSubclassProc [COMCTL32.413] 1482 * 1483 * Calls the next window procedure (i.e. the one before this subclass) 1484 * 1485 * PARAMS 1486 * hWnd [in] The window that we're subclassing 1487 * uMsg [in] Message 1488 * wParam [in] WPARAM 1489 * lParam [in] LPARAM 1490 * 1491 * RETURNS 1492 * Success: non-zero 1493 * Failure: zero 1494 */ 1495 1496 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 1497 { 1498 LPSUBCLASS_INFO stack; 1499 LRESULT ret; 1500 1501 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam); 1502 1503 /* retrieve our little stack from the Properties */ 1504 stack = GetPropW (hWnd, COMCTL32_wSubclass); 1505 if (!stack) { 1506 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd); 1507 return 0; 1508 } 1509 1510 /* If we are at the end of stack then we have to call the original 1511 * window procedure */ 1512 if (!stack->stackpos) { 1513 if (IsWindowUnicode (hWnd)) 1514 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam); 1515 else 1516 ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam); 1517 } else { 1518 const SUBCLASSPROCS *proc = stack->stackpos; 1519 stack->stackpos = stack->stackpos->next; 1520 /* call the Subclass procedure from the stack */ 1521 ret = proc->subproc (hWnd, uMsg, wParam, lParam, 1522 proc->id, proc->ref); 1523 } 1524 1525 return ret; 1526 } 1527 1528 1529 /*********************************************************************** 1530 * COMCTL32_CreateToolTip [NOT AN API] 1531 * 1532 * Creates a tooltip for the control specified in hwnd and does all 1533 * necessary setup and notifications. 1534 * 1535 * PARAMS 1536 * hwndOwner [I] Handle to the window that will own the tool tip. 1537 * 1538 * RETURNS 1539 * Success: Handle of tool tip window. 1540 * Failure: NULL 1541 */ 1542 1543 HWND 1544 COMCTL32_CreateToolTip(HWND hwndOwner) 1545 { 1546 HWND hwndToolTip; 1547 1548 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP, 1549 CW_USEDEFAULT, CW_USEDEFAULT, 1550 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner, 1551 0, 0, 0); 1552 1553 /* Send NM_TOOLTIPSCREATED notification */ 1554 if (hwndToolTip) 1555 { 1556 NMTOOLTIPSCREATED nmttc; 1557 /* true owner can be different if hwndOwner is a child window */ 1558 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER); 1559 nmttc.hdr.hwndFrom = hwndTrueOwner; 1560 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID); 1561 nmttc.hdr.code = NM_TOOLTIPSCREATED; 1562 nmttc.hwndToolTips = hwndToolTip; 1563 1564 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY, 1565 GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc); 1566 } 1567 1568 return hwndToolTip; 1569 } 1570 1571 1572 /*********************************************************************** 1573 * COMCTL32_RefreshSysColors [NOT AN API] 1574 * 1575 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to 1576 * refresh the color values in the color structure 1577 * 1578 * PARAMS 1579 * none 1580 * 1581 * RETURNS 1582 * none 1583 */ 1584 1585 VOID 1586 COMCTL32_RefreshSysColors(void) 1587 { 1588 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT); 1589 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW); 1590 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT); 1591 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE); 1592 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT); 1593 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT); 1594 comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT); 1595 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT); 1596 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW); 1597 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW); 1598 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE); 1599 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW); 1600 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT); 1601 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT); 1602 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION); 1603 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK); 1604 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT); 1605 } 1606 1607 /*********************************************************************** 1608 * COMCTL32_DrawInsertMark [NOT AN API] 1609 * 1610 * Draws an insertion mark (which looks similar to an 'I'). 1611 * 1612 * PARAMS 1613 * hDC [I] Device context to draw onto. 1614 * lpRect [I] Co-ordinates of insertion mark. 1615 * clrInsertMark [I] Colour of the insertion mark. 1616 * bHorizontal [I] True if insert mark should be drawn horizontally, 1617 * vertical otherwise. 1618 * 1619 * RETURNS 1620 * none 1621 * 1622 * NOTES 1623 * Draws up to but not including the bottom co-ordinate when drawing 1624 * vertically or the right co-ordinate when horizontal. 1625 */ 1626 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal) 1627 { 1628 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark); 1629 HPEN hOldPen; 1630 static const DWORD adwPolyPoints[] = {4,4,4}; 1631 LONG lCentre = (bHorizontal ? 1632 lpRect->top + (lpRect->bottom - lpRect->top)/2 : 1633 lpRect->left + (lpRect->right - lpRect->left)/2); 1634 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top); 1635 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom); 1636 const POINT aptInsertMark[] = 1637 { 1638 /* top (V) or left (H) arrow */ 1639 {lCentre , l1 + 2}, 1640 {lCentre - 2, l1 }, 1641 {lCentre + 3, l1 }, 1642 {lCentre + 1, l1 + 2}, 1643 /* middle line */ 1644 {lCentre , l2 - 2}, 1645 {lCentre , l1 - 1}, 1646 {lCentre + 1, l1 - 1}, 1647 {lCentre + 1, l2 - 2}, 1648 /* bottom (V) or right (H) arrow */ 1649 {lCentre , l2 - 3}, 1650 {lCentre - 2, l2 - 1}, 1651 {lCentre + 3, l2 - 1}, 1652 {lCentre + 1, l2 - 3}, 1653 }; 1654 hOldPen = SelectObject(hDC, hPen); 1655 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, ARRAY_SIZE(adwPolyPoints)); 1656 SelectObject(hDC, hOldPen); 1657 DeleteObject(hPen); 1658 } 1659 1660 /*********************************************************************** 1661 * COMCTL32_EnsureBitmapSize [internal] 1662 * 1663 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and 1664 * the height is at least cyMinHeight. If the bitmap already has these 1665 * dimensions nothing changes. 1666 * 1667 * PARAMS 1668 * hBitmap [I/O] Bitmap to modify. The handle may change 1669 * cxMinWidth [I] If the width of the bitmap is smaller, then it will 1670 * be enlarged to this value 1671 * cyMinHeight [I] If the height of the bitmap is smaller, then it will 1672 * be enlarged to this value 1673 * cyBackground [I] The color with which the new area will be filled 1674 * 1675 * RETURNS 1676 * none 1677 */ 1678 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground) 1679 { 1680 int cxNew, cyNew; 1681 BITMAP bmp; 1682 HBITMAP hNewBitmap; 1683 HBITMAP hNewDCBitmap, hOldDCBitmap; 1684 HBRUSH hNewDCBrush; 1685 HDC hdcNew, hdcOld; 1686 1687 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp)) 1688 return; 1689 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth); 1690 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight); 1691 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight) 1692 return; 1693 1694 hdcNew = CreateCompatibleDC(NULL); 1695 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL); 1696 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap); 1697 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground)); 1698 1699 hdcOld = CreateCompatibleDC(NULL); 1700 hOldDCBitmap = SelectObject(hdcOld, *pBitmap); 1701 1702 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY); 1703 if (bmp.bmWidth < cxMinWidth) 1704 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY); 1705 if (bmp.bmHeight < cyMinHeight) 1706 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY); 1707 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight) 1708 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY); 1709 1710 SelectObject(hdcNew, hNewDCBitmap); 1711 DeleteObject(SelectObject(hdcNew, hNewDCBrush)); 1712 DeleteDC(hdcNew); 1713 SelectObject(hdcOld, hOldDCBitmap); 1714 DeleteDC(hdcOld); 1715 1716 DeleteObject(*pBitmap); 1717 *pBitmap = hNewBitmap; 1718 return; 1719 } 1720 1721 void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm) 1722 { 1723 HDC hdc = GetDC(NULL); 1724 HFONT hOldFont; 1725 1726 hOldFont = SelectObject(hdc, hFont); 1727 GetTextMetricsW(hdc, ptm); 1728 SelectObject(hdc, hOldFont); 1729 ReleaseDC(NULL, hdc); 1730 } 1731 1732 #ifndef OCM__BASE /* avoid including olectl.h */ 1733 #define OCM__BASE (WM_USER+0x1c00) 1734 #endif 1735 1736 /*********************************************************************** 1737 * COMCTL32_IsReflectedMessage [internal] 1738 * 1739 * Some parents reflect notify messages - for some messages sent by the child, 1740 * they send it back with the message code increased by OCM__BASE (0x2000). 1741 * This allows better subclassing of controls. We don't need to handle such 1742 * messages but we don't want to print ERRs for them, so this helper function 1743 * identifies them. 1744 * 1745 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no 1746 * collision with defined CCM_ codes. 1747 */ 1748 BOOL COMCTL32_IsReflectedMessage(UINT uMsg) 1749 { 1750 switch (uMsg) 1751 { 1752 case OCM__BASE + WM_COMMAND: 1753 case OCM__BASE + WM_CTLCOLORBTN: 1754 case OCM__BASE + WM_CTLCOLOREDIT: 1755 case OCM__BASE + WM_CTLCOLORDLG: 1756 case OCM__BASE + WM_CTLCOLORLISTBOX: 1757 case OCM__BASE + WM_CTLCOLORMSGBOX: 1758 case OCM__BASE + WM_CTLCOLORSCROLLBAR: 1759 case OCM__BASE + WM_CTLCOLORSTATIC: 1760 case OCM__BASE + WM_DRAWITEM: 1761 case OCM__BASE + WM_MEASUREITEM: 1762 case OCM__BASE + WM_DELETEITEM: 1763 case OCM__BASE + WM_VKEYTOITEM: 1764 case OCM__BASE + WM_CHARTOITEM: 1765 case OCM__BASE + WM_COMPAREITEM: 1766 case OCM__BASE + WM_HSCROLL: 1767 case OCM__BASE + WM_VSCROLL: 1768 case OCM__BASE + WM_PARENTNOTIFY: 1769 case OCM__BASE + WM_NOTIFY: 1770 return TRUE; 1771 default: 1772 return FALSE; 1773 } 1774 } 1775 1776 /*********************************************************************** 1777 * MirrorIcon [COMCTL32.414] 1778 * 1779 * Mirrors an icon so that it will appear correctly on a mirrored DC. 1780 * 1781 * PARAMS 1782 * phicon1 [I/O] Icon. 1783 * phicon2 [I/O] Icon. 1784 * 1785 * RETURNS 1786 * Success: TRUE. 1787 * Failure: FALSE. 1788 */ 1789 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2) 1790 { 1791 FIXME("(%p, %p): stub\n", phicon1, phicon2); 1792 return FALSE; 1793 } 1794 1795 static inline BOOL IsDelimiter(WCHAR c) 1796 { 1797 switch(c) 1798 { 1799 case '/': 1800 case '\\': 1801 case '.': 1802 case ' ': 1803 return TRUE; 1804 } 1805 return FALSE; 1806 } 1807 1808 static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code) 1809 { 1810 if (code == WB_ISDELIMITER) 1811 return IsDelimiter(lpch[ichCurrent]); 1812 else 1813 { 1814 int dir = (code == WB_LEFT) ? -1 : 1; 1815 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir) 1816 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent; 1817 } 1818 return ichCurrent; 1819 } 1820 1821 /*********************************************************************** 1822 * SetPathWordBreakProc [COMCTL32.384] 1823 * 1824 * Sets the word break procedure for an edit control to one that understands 1825 * paths so that the user can jump over directories. 1826 * 1827 * PARAMS 1828 * hwnd [I] Handle to edit control. 1829 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed. 1830 * 1831 * RETURNS 1832 * Result from EM_SETWORDBREAKPROC message. 1833 */ 1834 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet) 1835 { 1836 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0, 1837 (LPARAM)(bSet ? PathWordBreakProc : NULL)); 1838 } 1839 1840 /*********************************************************************** 1841 * DrawShadowText [COMCTL32.@] 1842 * 1843 * Draw text with shadow. 1844 */ 1845 int WINAPI DrawShadowText(HDC hdc, LPCWSTR pszText, UINT cch, RECT *prc, DWORD dwFlags, 1846 COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset) 1847 { 1848 COLORREF crOldText; 1849 RECT rcText; 1850 INT iRet, x, y, x2, y2; 1851 BYTE *pBits; 1852 HBITMAP hbm, hbmOld; 1853 BITMAPINFO bi; 1854 HDC hdcMem; 1855 HFONT hOldFont; 1856 BLENDFUNCTION bf; 1857 1858 /* Create 32 bit DIB section for the shadow */ 1859 ZeroMemory(&bi, sizeof(bi)); 1860 bi.bmiHeader.biSize = sizeof(bi.bmiHeader); 1861 bi.bmiHeader.biWidth = prc->right - prc->left + 4; 1862 bi.bmiHeader.biHeight = prc->bottom - prc->top + 5; // bottom-up DIB 1863 bi.bmiHeader.biPlanes = 1; 1864 bi.bmiHeader.biBitCount = 32; 1865 bi.bmiHeader.biCompression = BI_RGB; 1866 hbm = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, (PVOID*)&pBits, NULL, 0); 1867 if(!hbm) 1868 { 1869 ERR("CreateDIBSection failed\n"); 1870 return 0; 1871 } 1872 1873 /* Create memory device context for new DIB section and select it */ 1874 hdcMem = CreateCompatibleDC(hdc); 1875 if(!hdcMem) 1876 { 1877 ERR("CreateCompatibleDC failed\n"); 1878 DeleteObject(hbm); 1879 return 0; 1880 } 1881 1882 hbmOld = (HBITMAP)SelectObject(hdcMem, hbm); 1883 1884 /* Draw text on our helper bitmap */ 1885 hOldFont = (HFONT)SelectObject(hdcMem, GetCurrentObject(hdc, OBJ_FONT)); 1886 SetTextColor(hdcMem, RGB(16, 16, 16)); 1887 SetBkColor(hdcMem, RGB(0, 0, 0)); 1888 SetBkMode(hdcMem, TRANSPARENT); 1889 SetRect(&rcText, 0, 0, prc->right - prc->left, prc->bottom - prc->top); 1890 DrawTextW(hdcMem, pszText, cch, &rcText, dwFlags); 1891 SelectObject(hdcMem, hOldFont); 1892 1893 /* Flush GDI so data pointed by pBits is valid */ 1894 GdiFlush(); 1895 1896 /* Set alpha of pixels (forget about colors for now. They will be changed in next loop). 1897 We copy text image 4*5 times and each time alpha is added */ 1898 for (x = 0; x < bi.bmiHeader.biWidth; ++x) 1899 for (y = 0; y < bi.bmiHeader.biHeight; ++y) 1900 { 1901 BYTE *pDest = &pBits[(y * bi.bmiHeader.biWidth + x) * 4]; 1902 UINT Alpha = 0; 1903 1904 for (x2 = x - 4 + 1; x2 <= x; ++x2) 1905 for (y2 = y; y2 < y + 5; ++y2) 1906 { 1907 if (x2 >= 0 && x2 < bi.bmiHeader.biWidth && y2 >= 0 && y2 < bi.bmiHeader.biHeight) 1908 { 1909 BYTE *pSrc = &pBits[(y2 * bi.bmiHeader.biWidth + x2) * 4]; 1910 Alpha += pSrc[0]; 1911 } 1912 } 1913 1914 if (Alpha > 255) 1915 Alpha = 255; 1916 pDest[3] = Alpha; 1917 } 1918 1919 /* Now set the color of each pixel to shadow color * alpha (see GdiAlphaBlend) */ 1920 for (x = 0; x < bi.bmiHeader.biWidth; ++x) 1921 for (y = 0; y < bi.bmiHeader.biHeight; ++y) 1922 { 1923 BYTE *pDest = &pBits[(y * bi.bmiHeader.biWidth + x) * 4]; 1924 pDest[0] = GetBValue(crShadow) * pDest[3] / 255; 1925 pDest[1] = GetGValue(crShadow) * pDest[3] / 255; 1926 pDest[2] = GetRValue(crShadow) * pDest[3] / 255; 1927 } 1928 1929 /* Fix ixOffset of the shadow (tested on Win) */ 1930 ixOffset -= 3; 1931 iyOffset -= 3; 1932 1933 /* Alpha blend helper image to destination DC */ 1934 bf.BlendOp = AC_SRC_OVER; 1935 bf.BlendFlags = 0; 1936 bf.SourceConstantAlpha = 255; 1937 bf.AlphaFormat = AC_SRC_ALPHA; 1938 GdiAlphaBlend(hdc, prc->left + ixOffset, prc->top + iyOffset, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, hdcMem, 0, 0, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, bf); 1939 1940 /* Delete the helper bitmap */ 1941 SelectObject(hdcMem, hbmOld); 1942 DeleteObject(hbm); 1943 DeleteDC(hdcMem); 1944 1945 /* Finally draw the text over shadow */ 1946 crOldText = SetTextColor(hdc, crText); 1947 SetBkMode(hdc, TRANSPARENT); 1948 iRet = DrawTextW(hdc, pszText, cch, prc, dwFlags); 1949 SetTextColor(hdc, crOldText); 1950 1951 return iRet; 1952 } 1953 1954 /*********************************************************************** 1955 * LoadIconWithScaleDown [COMCTL32.@] 1956 */ 1957 HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon) 1958 { 1959 TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon); 1960 1961 *icon = NULL; 1962 1963 if (!name) 1964 return E_INVALIDARG; 1965 1966 *icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy, 1967 (hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE); 1968 if (!*icon) 1969 return HRESULT_FROM_WIN32(GetLastError()); 1970 1971 return S_OK; 1972 } 1973 1974 /*********************************************************************** 1975 * LoadIconMetric [COMCTL32.@] 1976 */ 1977 HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon) 1978 { 1979 int cx, cy; 1980 1981 TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon); 1982 1983 if (size == LIM_SMALL) 1984 { 1985 cx = GetSystemMetrics(SM_CXSMICON); 1986 cy = GetSystemMetrics(SM_CYSMICON); 1987 } 1988 else if (size == LIM_LARGE) 1989 { 1990 cx = GetSystemMetrics(SM_CXICON); 1991 cy = GetSystemMetrics(SM_CYICON); 1992 } 1993 else 1994 { 1995 *icon = NULL; 1996 return E_INVALIDARG; 1997 } 1998 1999 return LoadIconWithScaleDown(hinst, name, cx, cy, icon); 2000 } 2001