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