1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Cursor and icon functions 5 * FILE: win32ss/user/ntuser/cursoricon.c 6 * PROGRAMER: ReactOS Team 7 */ 8 /* 9 * We handle two types of cursors/icons: 10 * - Private 11 * Loaded without LR_SHARED flag 12 * Private to a process 13 * Can be deleted by calling NtDestroyCursorIcon() 14 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL 15 * - Shared 16 * Loaded with LR_SHARED flag 17 * Possibly shared by multiple processes 18 * Immune to NtDestroyCursorIcon() 19 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid 20 */ 21 22 #include <win32k.h> 23 DBG_DEFAULT_CHANNEL(UserIcon); 24 25 SYSTEM_CURSORINFO gSysCursorInfo; 26 27 PCURICON_OBJECT gcurFirst = NULL; // After all is done, this should be WINLOGO! 28 29 // 30 // System Cursors 31 // 32 SYSTEMCURICO gasyscur[] = { 33 {OCR_NORMAL, NULL}, 34 {OCR_IBEAM, NULL}, 35 {OCR_WAIT, NULL}, 36 {OCR_CROSS, NULL}, 37 {OCR_UP, NULL}, 38 {OCR_ICON, NULL}, 39 {OCR_SIZE, NULL}, 40 {OCR_SIZENWSE, NULL}, 41 {OCR_SIZENESW, NULL}, 42 {OCR_SIZEWE, NULL}, 43 {OCR_SIZENS, NULL}, 44 {OCR_SIZEALL, NULL}, 45 {OCR_NO, NULL}, 46 {OCR_HAND, NULL}, 47 {OCR_APPSTARTING,NULL}, 48 {OCR_HELP, NULL}, 49 }; 50 51 // 52 // System Icons 53 // 54 SYSTEMCURICO gasysico[] = { 55 {OIC_SAMPLE, NULL}, 56 {OIC_HAND, NULL}, 57 {OIC_QUES, NULL}, 58 {OIC_BANG, NULL}, 59 {OIC_NOTE, NULL}, 60 {OIC_WINLOGO,NULL}, 61 }; 62 63 BOOL 64 InitCursorImpl(VOID) 65 { 66 gSysCursorInfo.Enabled = FALSE; 67 gSysCursorInfo.ButtonsDown = 0; 68 gSysCursorInfo.bClipped = FALSE; 69 gSysCursorInfo.LastBtnDown = 0; 70 gSysCursorInfo.CurrentCursorObject = NULL; 71 gSysCursorInfo.ShowingCursor = -1; 72 gSysCursorInfo.ClickLockActive = FALSE; 73 gSysCursorInfo.ClickLockTime = 0; 74 75 return TRUE; 76 } 77 78 static 79 VOID 80 IntInsertCursorIntoList( 81 _Inout_ PCURICON_OBJECT pcur) 82 { 83 PPROCESSINFO ppi = pcur->head.ppi; 84 PCURICON_OBJECT *ppcurHead; 85 NT_ASSERT((pcur->CURSORF_flags & (CURSORF_GLOBAL|CURSORF_LRSHARED)) != 0); 86 NT_ASSERT((pcur->CURSORF_flags & CURSORF_LINKED) == 0); 87 88 /* Get the right list head */ 89 ppcurHead = (pcur->CURSORF_flags & CURSORF_GLOBAL) ? 90 &gcurFirst : &ppi->pCursorCache; 91 92 UserReferenceObject(pcur); 93 pcur->pcurNext = *ppcurHead; 94 *ppcurHead = pcur; 95 pcur->CURSORF_flags |= CURSORF_LINKED; 96 } 97 98 // FIXME: should think about using a LIST_ENTRY! 99 static 100 VOID 101 IntRemoveCursorFromList( 102 _Inout_ PCURICON_OBJECT pcur) 103 { 104 PPROCESSINFO ppi = pcur->head.ppi; 105 PCURICON_OBJECT *ppcurHead; 106 PCURICON_OBJECT *ppcur; 107 NT_ASSERT((pcur->CURSORF_flags & (CURSORF_GLOBAL|CURSORF_LRSHARED)) != 0); 108 NT_ASSERT((pcur->CURSORF_flags & CURSORF_LINKED) != 0); 109 110 /* Get the right list head */ 111 ppcurHead = (pcur->CURSORF_flags & CURSORF_GLOBAL) ? 112 &gcurFirst : &ppi->pCursorCache; 113 114 /* Loop all cursors in the cache */ 115 for (ppcur = ppcurHead; 116 (*ppcur) != NULL; 117 ppcur = &(*ppcur)->pcurNext) 118 { 119 /* Check if this is the one we are looking for */ 120 if ((*ppcur) == pcur) 121 { 122 /* Remove it from the list */ 123 (*ppcur) = pcur->pcurNext; 124 125 /* Dereference it */ 126 UserDereferenceObject(pcur); 127 pcur->CURSORF_flags &= ~CURSORF_LINKED; 128 return; 129 } 130 } 131 132 /* We did not find it, this must not happen */ 133 NT_ASSERT(FALSE); 134 } 135 136 VOID 137 IntLoadSystenIcons(HICON hcur, DWORD id) 138 { 139 PCURICON_OBJECT pcur; 140 int i; 141 PPROCESSINFO ppi; 142 143 if (hcur) 144 { 145 pcur = UserGetCurIconObject(hcur); 146 if (!pcur) 147 { 148 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); 149 return; 150 } 151 152 ppi = PsGetCurrentProcessWin32Process(); 153 154 if (!(ppi->W32PF_flags & W32PF_CREATEDWINORDC)) 155 return; 156 157 // Set Small Window Icon and do not link. 158 if ( id == OIC_WINLOGO+1 ) 159 { 160 pcur->CURSORF_flags |= CURSORF_GLOBAL; 161 UserReferenceObject(pcur); 162 pcur->head.ppi = NULL; 163 return; 164 } 165 166 for (i = 0 ; i < 6; i++) 167 { 168 if (gasysico[i].type == id) 169 { 170 gasysico[i].handle = pcur; 171 pcur->CURSORF_flags |= CURSORF_GLOBAL; 172 173 // 174 // The active switch between LR shared and Global public. 175 // This is hacked around to support this while at the initial system start up. 176 // 177 pcur->head.ppi = NULL; 178 179 IntInsertCursorIntoList(pcur); 180 return; 181 } 182 } 183 } 184 } 185 186 PSYSTEM_CURSORINFO 187 IntGetSysCursorInfo(VOID) 188 { 189 return &gSysCursorInfo; 190 } 191 192 FORCEINLINE 193 BOOL 194 is_icon(PCURICON_OBJECT object) 195 { 196 return MAKEINTRESOURCE(object->rt) == RT_ICON; 197 } 198 199 /* This function creates a reference for the object! */ 200 PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon) 201 { 202 PCURICON_OBJECT CurIcon; 203 204 if (!hCurIcon) 205 { 206 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); 207 return NULL; 208 } 209 210 if (UserObjectInDestroy(hCurIcon)) 211 { 212 WARN("Requesting invalid/destroyed cursor.\n"); 213 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); 214 return NULL; 215 } 216 217 CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR); 218 if (!CurIcon) 219 { 220 /* We never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */ 221 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); 222 return NULL; 223 } 224 225 ASSERT(CurIcon->head.cLockObj >= 1); 226 return CurIcon; 227 } 228 229 PCURICON_OBJECT 230 IntSystemSetCursor(PCURICON_OBJECT pcurNew) 231 { 232 PCURICON_OBJECT pcurOld = UserSetCursor(pcurNew, FALSE); 233 if (pcurNew) UserReferenceObject(pcurNew); 234 if (pcurOld) UserDereferenceObject(pcurOld); 235 return pcurOld; 236 } 237 238 BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook) 239 { 240 PWND DesktopWindow; 241 PSYSTEM_CURSORINFO CurInfo; 242 MSG Msg; 243 RECTL rcClip; 244 POINT pt; 245 246 if (!(DesktopWindow = UserGetDesktopWindow())) 247 { 248 return FALSE; 249 } 250 251 CurInfo = IntGetSysCursorInfo(); 252 253 /* Clip cursor position */ 254 if (!CurInfo->bClipped) 255 rcClip = DesktopWindow->rcClient; 256 else 257 rcClip = CurInfo->rcClip; 258 259 if (x >= rcClip.right) x = rcClip.right - 1; 260 if (x < rcClip.left) x = rcClip.left; 261 if (y >= rcClip.bottom) y = rcClip.bottom - 1; 262 if (y < rcClip.top) y = rcClip.top; 263 264 /* Nothing to do if position did not actually change */ 265 if (x == gpsi->ptCursor.x && y == gpsi->ptCursor.y) 266 return TRUE; 267 268 pt.x = x; 269 pt.y = y; 270 271 /* 1. Generate a mouse move message, this sets the htEx and Track Window too */ 272 Msg.message = WM_MOUSEMOVE; 273 Msg.wParam = UserGetMouseButtonsState(); 274 Msg.lParam = MAKELPARAM(x, y); 275 Msg.pt = pt; 276 co_MsqInsertMouseMessage(&Msg, flags, dwExtraInfo, Hook); 277 278 /* 2. Store the new cursor position */ 279 gpsi->ptCursor = pt; 280 281 return TRUE; 282 } 283 284 HANDLE 285 IntCreateCurIconHandle(BOOLEAN Animated) 286 { 287 PCURICON_OBJECT CurIcon; 288 HANDLE hCurIcon; 289 290 CurIcon = UserCreateObject( 291 gHandleTable, 292 NULL, 293 GetW32ThreadInfo(), 294 &hCurIcon, 295 TYPE_CURSOR, 296 Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT)); 297 298 if (!CurIcon) 299 { 300 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 301 return FALSE; 302 } 303 304 if (Animated) 305 { 306 /* We MUST set this flag, to track whether this is an ACON! */ 307 CurIcon->CURSORF_flags |= CURSORF_ACON; 308 } 309 310 NT_ASSERT(CurIcon->pcurNext == NULL); 311 UserDereferenceObject(CurIcon); 312 313 return hCurIcon; 314 } 315 316 BOOLEAN 317 IntDestroyCurIconObject( 318 _In_ PVOID Object) 319 { 320 PCURICON_OBJECT CurIcon = Object; 321 322 /* Check if the cursor is in a list */ 323 if (CurIcon->CURSORF_flags & CURSORF_LINKED) 324 { 325 /* Remove the cursor from it's list */ 326 IntRemoveCursorFromList(CurIcon); 327 } 328 329 /* We just mark the handle as being destroyed. 330 * Deleting all the stuff will be deferred to the actual struct free. */ 331 UserDeleteObject(UserHMGetHandle(CurIcon), TYPE_CURSOR); 332 return TRUE; 333 } 334 335 VOID 336 FreeCurIconObject( 337 _In_ PVOID Object) 338 { 339 PCURICON_OBJECT CurIcon = Object; 340 341 if (!(CurIcon->CURSORF_flags & CURSORF_ACON)) 342 { 343 HBITMAP bmpMask = CurIcon->hbmMask; 344 HBITMAP bmpColor = CurIcon->hbmColor; 345 HBITMAP bmpAlpha = CurIcon->hbmAlpha; 346 347 /* Delete bitmaps */ 348 if (bmpMask) 349 { 350 GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED); 351 NT_VERIFY(GreDeleteObject(bmpMask) == TRUE); 352 CurIcon->hbmMask = NULL; 353 } 354 if (bmpColor) 355 { 356 GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED); 357 NT_VERIFY(GreDeleteObject(bmpColor) == TRUE); 358 CurIcon->hbmColor = NULL; 359 } 360 if (bmpAlpha) 361 { 362 GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED); 363 NT_VERIFY(GreDeleteObject(bmpAlpha) == TRUE); 364 CurIcon->hbmAlpha = NULL; 365 } 366 } 367 else 368 { 369 PACON AniCurIcon = (PACON)CurIcon; 370 UINT i; 371 372 for (i = 0; i < AniCurIcon->cpcur; i++) 373 { 374 UserDereferenceObject(AniCurIcon->aspcur[i]); 375 NT_VERIFY(IntDestroyCurIconObject(AniCurIcon->aspcur[i]) == TRUE); 376 } 377 ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR); 378 } 379 380 if (CurIcon->CURSORF_flags & CURSORF_LRSHARED) 381 { 382 if (!IS_INTRESOURCE(CurIcon->strName.Buffer)) 383 ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING); 384 if (CurIcon->atomModName) 385 RtlDeleteAtomFromAtomTable(gAtomTable, CurIcon->atomModName); 386 CurIcon->strName.Buffer = NULL; 387 CurIcon->atomModName = 0; 388 } 389 390 /* Finally free the thing */ 391 FreeProcMarkObject(CurIcon); 392 } 393 394 VOID FASTCALL 395 IntCleanupCurIconCache(PPROCESSINFO Win32Process) 396 { 397 PCURICON_OBJECT CurIcon; 398 399 /* Run through the list of icon objects */ 400 while (Win32Process->pCursorCache) 401 { 402 CurIcon = Win32Process->pCursorCache; 403 Win32Process->pCursorCache = CurIcon->pcurNext; 404 UserDereferenceObject(CurIcon); 405 } 406 } 407 408 /* 409 * @implemented 410 */ 411 _Success_(return != FALSE) 412 BOOL 413 NTAPI 414 NtUserGetIconInfo( 415 _In_ HANDLE hCurIcon, 416 _Out_opt_ PICONINFO IconInfo, 417 _Inout_opt_ PUNICODE_STRING lpModule, 418 _Inout_opt_ PUNICODE_STRING lpResName, 419 _Out_opt_ LPDWORD pbpp, 420 _In_ BOOL bInternal) 421 { 422 ICONINFO ii; 423 PCURICON_OBJECT CurIcon; 424 NTSTATUS Status = STATUS_SUCCESS; 425 BOOL Ret = FALSE; 426 DWORD colorBpp = 0; 427 428 TRACE("Enter NtUserGetIconInfo\n"); 429 430 /* Check if something was actually asked */ 431 if (!IconInfo && !lpModule && !lpResName) 432 { 433 WARN("Nothing to fill.\n"); 434 EngSetLastError(ERROR_INVALID_PARAMETER); 435 return FALSE; 436 } 437 438 UserEnterExclusive(); 439 440 if (!(CurIcon = UserGetCurIconObject(hCurIcon))) 441 { 442 WARN("UserGetIconObject(0x%p) Failed.\n", hCurIcon); 443 UserLeave(); 444 return FALSE; 445 } 446 447 /* Give back the icon information */ 448 if (IconInfo) 449 { 450 PCURICON_OBJECT FrameCurIcon = CurIcon; 451 if (CurIcon->CURSORF_flags & CURSORF_ACON) 452 { 453 /* Get information from first frame. */ 454 FrameCurIcon = ((PACON)CurIcon)->aspcur[0]; 455 } 456 457 /* Fill data */ 458 ii.fIcon = is_icon(FrameCurIcon); 459 ii.xHotspot = FrameCurIcon->xHotspot; 460 ii.yHotspot = FrameCurIcon->yHotspot; 461 462 /* Copy bitmaps */ 463 ii.hbmMask = BITMAP_CopyBitmap(FrameCurIcon->hbmMask); 464 GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED); 465 ii.hbmColor = BITMAP_CopyBitmap(FrameCurIcon->hbmColor); 466 GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED); 467 colorBpp = FrameCurIcon->bpp; 468 469 /* Copy fields */ 470 _SEH2_TRY 471 { 472 ProbeForWrite(IconInfo, sizeof(ICONINFO), 1); 473 RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO)); 474 475 if (pbpp) 476 { 477 ProbeForWrite(pbpp, sizeof(DWORD), 1); 478 *pbpp = colorBpp; 479 } 480 } 481 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 482 { 483 Status = _SEH2_GetExceptionCode(); 484 } 485 _SEH2_END 486 487 if (!NT_SUCCESS(Status)) 488 { 489 WARN("Status: 0x%08lx\n", Status); 490 SetLastNtError(Status); 491 goto leave; 492 } 493 } 494 495 /* Give back the module name */ 496 if (lpModule) 497 { 498 ULONG BufLen = 0; 499 if (!CurIcon->atomModName) 500 goto leave; 501 502 RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, NULL, &BufLen); 503 /* Get the module name from the atom table */ 504 _SEH2_TRY 505 { 506 BufLen += sizeof(WCHAR); 507 if (BufLen > (lpModule->MaximumLength)) 508 { 509 lpModule->Length = 0; 510 lpModule->MaximumLength = BufLen; 511 } 512 else 513 { 514 ProbeForWrite(lpModule->Buffer, lpModule->MaximumLength, 1); 515 BufLen = lpModule->MaximumLength; 516 RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, lpModule->Buffer, &BufLen); 517 lpModule->Length = BufLen; 518 } 519 } 520 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 521 { 522 Status = _SEH2_GetExceptionCode(); 523 } 524 _SEH2_END 525 526 if (!NT_SUCCESS(Status)) 527 { 528 SetLastNtError(Status); 529 goto leave; 530 } 531 } 532 533 if (lpResName) 534 { 535 if (!CurIcon->strName.Buffer) 536 goto leave; 537 538 /* Copy it */ 539 _SEH2_TRY 540 { 541 ProbeForWrite(lpResName, sizeof(UNICODE_STRING), 1); 542 if (IS_INTRESOURCE(CurIcon->strName.Buffer)) 543 { 544 lpResName->Buffer = CurIcon->strName.Buffer; 545 lpResName->Length = 0; 546 lpResName->MaximumLength = 0; 547 } 548 else if (lpResName->MaximumLength < CurIcon->strName.MaximumLength) 549 { 550 lpResName->Length = 0; 551 lpResName->MaximumLength = CurIcon->strName.MaximumLength; 552 } 553 else 554 { 555 ProbeForWrite(lpResName->Buffer, lpResName->MaximumLength, 1); 556 RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, CurIcon->strName.Length); 557 lpResName->Length = CurIcon->strName.Length; 558 } 559 } 560 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 561 { 562 Status = _SEH2_GetExceptionCode(); 563 } 564 _SEH2_END 565 } 566 567 if (!NT_SUCCESS(Status)) 568 { 569 SetLastNtError(Status); 570 goto leave; 571 } 572 573 Ret = TRUE; 574 575 leave: 576 UserDereferenceObject(CurIcon); 577 578 TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret); 579 UserLeave(); 580 581 return Ret; 582 } 583 584 585 /* 586 * @implemented 587 */ 588 BOOL 589 APIENTRY 590 NtUserGetIconSize( 591 HANDLE hCurIcon, 592 UINT istepIfAniCur, 593 PLONG plcx, // &size.cx 594 PLONG plcy) // &size.cy 595 { 596 PCURICON_OBJECT CurIcon; 597 NTSTATUS Status = STATUS_SUCCESS; 598 BOOL bRet = FALSE; 599 600 TRACE("Enter NtUserGetIconSize\n"); 601 UserEnterShared(); 602 603 if (!(CurIcon = UserGetCurIconObject(hCurIcon))) 604 { 605 goto cleanup; 606 } 607 608 if (CurIcon->CURSORF_flags & CURSORF_ACON) 609 { 610 /* Use first frame for animated cursors */ 611 PACON AniCurIcon = (PACON)CurIcon; 612 CurIcon = AniCurIcon->aspcur[0]; 613 UserDereferenceObject(AniCurIcon); 614 UserReferenceObject(CurIcon); 615 } 616 617 _SEH2_TRY 618 { 619 ProbeForWrite(plcx, sizeof(LONG), 1); 620 *plcx = CurIcon->cx; 621 ProbeForWrite(plcy, sizeof(LONG), 1); 622 *plcy = CurIcon->cy; 623 } 624 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 625 { 626 Status = _SEH2_GetExceptionCode(); 627 } 628 _SEH2_END 629 630 if (NT_SUCCESS(Status)) 631 bRet = TRUE; 632 else 633 SetLastNtError(Status); // Maybe not, test this 634 635 UserDereferenceObject(CurIcon); 636 637 cleanup: 638 TRACE("Leave NtUserGetIconSize, ret=%i\n", bRet); 639 UserLeave(); 640 return bRet; 641 } 642 643 644 /* 645 * @implemented 646 */ 647 BOOL 648 APIENTRY 649 NtUserGetCursorInfo( 650 PCURSORINFO pci) 651 { 652 CURSORINFO SafeCi; 653 PSYSTEM_CURSORINFO CurInfo; 654 NTSTATUS Status = STATUS_SUCCESS; 655 PCURICON_OBJECT CurIcon; 656 BOOL Ret = FALSE; 657 658 TRACE("Enter NtUserGetCursorInfo\n"); 659 UserEnterShared(); 660 661 CurInfo = IntGetSysCursorInfo(); 662 CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject; 663 664 SafeCi.cbSize = sizeof(CURSORINFO); 665 SafeCi.flags = ((CurIcon && CurInfo->ShowingCursor >= 0) ? CURSOR_SHOWING : 0); 666 SafeCi.hCursor = (CurIcon ? UserHMGetHandle(CurIcon) : NULL); 667 668 SafeCi.ptScreenPos = gpsi->ptCursor; 669 670 _SEH2_TRY 671 { 672 if (pci->cbSize == sizeof(CURSORINFO)) 673 { 674 ProbeForWrite(pci, sizeof(CURSORINFO), 1); 675 RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO)); 676 Ret = TRUE; 677 } 678 else 679 { 680 EngSetLastError(ERROR_INVALID_PARAMETER); 681 } 682 } 683 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 684 { 685 Status = _SEH2_GetExceptionCode(); 686 } 687 _SEH2_END; 688 if (!NT_SUCCESS(Status)) 689 { 690 SetLastNtError(Status); 691 } 692 693 TRACE("Leave NtUserGetCursorInfo, ret=%i\n", Ret); 694 UserLeave(); 695 return Ret; 696 } 697 698 BOOL 699 APIENTRY 700 UserClipCursor( 701 RECTL *prcl) 702 { 703 PSYSTEM_CURSORINFO CurInfo; 704 PWND DesktopWindow = NULL; 705 706 if (!CheckWinstaAttributeAccess(WINSTA_WRITEATTRIBUTES)) 707 { 708 return FALSE; 709 } 710 711 CurInfo = IntGetSysCursorInfo(); 712 713 DesktopWindow = UserGetDesktopWindow(); 714 715 if (prcl != NULL && DesktopWindow != NULL) 716 { 717 if (prcl->right < prcl->left || prcl->bottom < prcl->top) 718 { 719 EngSetLastError(ERROR_INVALID_PARAMETER); 720 return FALSE; 721 } 722 723 CurInfo->bClipped = TRUE; 724 725 /* Set nw cliping region. Note: we can't use RECTL_bIntersectRect because 726 it sets rect to 0 0 0 0 when it's empty. For more info see monitor winetest */ 727 CurInfo->rcClip.left = max(prcl->left, DesktopWindow->rcWindow.left); 728 CurInfo->rcClip.right = min(prcl->right, DesktopWindow->rcWindow.right); 729 if (CurInfo->rcClip.right < CurInfo->rcClip.left) 730 CurInfo->rcClip.right = CurInfo->rcClip.left; 731 732 CurInfo->rcClip.top = max(prcl->top, DesktopWindow->rcWindow.top); 733 CurInfo->rcClip.bottom = min(prcl->bottom, DesktopWindow->rcWindow.bottom); 734 if (CurInfo->rcClip.bottom < CurInfo->rcClip.top) 735 CurInfo->rcClip.bottom = CurInfo->rcClip.top; 736 737 /* Make sure cursor is in clipping region */ 738 UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, 0, 0, FALSE); 739 } 740 else 741 { 742 CurInfo->bClipped = FALSE; 743 } 744 745 return TRUE; 746 } 747 748 /* 749 * @implemented 750 */ 751 BOOL 752 APIENTRY 753 NtUserClipCursor( 754 RECTL *prcl) 755 { 756 RECTL rclLocal; 757 BOOL bResult; 758 759 if (prcl) 760 { 761 _SEH2_TRY 762 { 763 /* Probe and copy rect */ 764 ProbeForRead(prcl, sizeof(RECTL), 1); 765 rclLocal = *prcl; 766 } 767 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 768 { 769 EngSetLastError(ERROR_INVALID_PARAMETER); 770 _SEH2_YIELD(return FALSE;) 771 } 772 _SEH2_END 773 774 prcl = &rclLocal; 775 } 776 777 UserEnterExclusive(); 778 779 /* Call the internal function */ 780 bResult = UserClipCursor(prcl); 781 782 UserLeave(); 783 784 return bResult; 785 } 786 787 788 /* 789 * @implemented 790 */ 791 BOOL 792 APIENTRY 793 NtUserDestroyCursor( 794 _In_ HANDLE hCurIcon, 795 _In_ BOOL bForce) 796 { 797 BOOL ret; 798 PCURICON_OBJECT CurIcon = NULL; 799 800 TRACE("Enter NtUserDestroyCursorIcon (%p, %i)\n", hCurIcon, bForce); 801 UserEnterExclusive(); 802 803 CurIcon = UserGetCurIconObject(hCurIcon); 804 if (!CurIcon) 805 { 806 ret = FALSE; 807 goto leave; 808 } 809 810 if (!bForce) 811 { 812 /* Can not destroy global objects */ 813 if (CurIcon->head.ppi == NULL) 814 { 815 ERR("Trying to delete global cursor!\n"); 816 ret = TRUE; 817 goto leave; 818 } 819 820 /* Maybe we have good reasons not to destroy this object */ 821 if (CurIcon->head.ppi != PsGetCurrentProcessWin32Process()) 822 { 823 /* No way, you're not touching my cursor */ 824 ret = FALSE; 825 goto leave; 826 } 827 828 if (CurIcon->CURSORF_flags & CURSORF_CURRENT) 829 { 830 WARN("Trying to delete current cursor!\n"); 831 ret = FALSE; 832 goto leave; 833 } 834 835 if (CurIcon->CURSORF_flags & CURSORF_LRSHARED) 836 { 837 WARN("Trying to delete shared cursor.\n"); 838 /* This one is not an error */ 839 ret = TRUE; 840 goto leave; 841 } 842 } 843 844 /* Destroy the handle */ 845 ret = IntDestroyCurIconObject(CurIcon); 846 847 leave: 848 if (CurIcon) 849 UserDereferenceObject(CurIcon); 850 TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n", ret); 851 UserLeave(); 852 return ret; 853 } 854 855 856 /* 857 * @implemented 858 */ 859 HICON 860 NTAPI 861 NtUserFindExistingCursorIcon( 862 _In_ PUNICODE_STRING pustrModule, 863 _In_ PUNICODE_STRING pustrRsrc, 864 _In_ FINDEXISTINGCURICONPARAM* param) 865 { 866 PCURICON_OBJECT CurIcon; 867 HICON Ret = NULL; 868 UNICODE_STRING ustrModuleSafe, ustrRsrcSafe; 869 FINDEXISTINGCURICONPARAM paramSafe; 870 NTSTATUS Status; 871 PPROCESSINFO pProcInfo = PsGetCurrentProcessWin32Process(); 872 RTL_ATOM atomModName; 873 874 TRACE("Enter NtUserFindExistingCursorIcon\n"); 875 876 _SEH2_TRY 877 { 878 ProbeForRead(param, sizeof(*param), 1); 879 RtlCopyMemory(¶mSafe, param, sizeof(paramSafe)); 880 } 881 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 882 { 883 Status = _SEH2_GetExceptionCode(); 884 } 885 _SEH2_END 886 887 /* Capture resource name (it can be an INTRESOURCE == ATOM) */ 888 Status = ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrcSafe, pustrRsrc); 889 if (!NT_SUCCESS(Status)) 890 return NULL; 891 Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule); 892 if (!NT_SUCCESS(Status)) 893 goto done; 894 Status = RtlLookupAtomInAtomTable(gAtomTable, ustrModuleSafe.Buffer, &atomModName); 895 ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode); 896 if (!NT_SUCCESS(Status)) 897 { 898 /* The module is not in the atom table. No chance to find the cursor */ 899 goto done; 900 } 901 902 UserEnterShared(); 903 CurIcon = pProcInfo->pCursorCache; 904 while (CurIcon) 905 { 906 /* Icon/cursor */ 907 if (paramSafe.bIcon != is_icon(CurIcon)) 908 { 909 CurIcon = CurIcon->pcurNext; 910 continue; 911 } 912 /* See if module names match */ 913 if (atomModName == CurIcon->atomModName) 914 { 915 /* They do. Now see if this is the same resource */ 916 if (IS_INTRESOURCE(CurIcon->strName.Buffer) != IS_INTRESOURCE(ustrRsrcSafe.Buffer)) 917 { 918 /* One is an INT resource and the other is not -> no match */ 919 CurIcon = CurIcon->pcurNext; 920 continue; 921 } 922 923 if (IS_INTRESOURCE(CurIcon->strName.Buffer)) 924 { 925 if (CurIcon->strName.Buffer == ustrRsrcSafe.Buffer) 926 { 927 /* INT resources match */ 928 break; 929 } 930 } 931 else if (RtlCompareUnicodeString(&ustrRsrcSafe, &CurIcon->strName, TRUE) == 0) 932 { 933 /* Resource name strings match */ 934 break; 935 } 936 } 937 CurIcon = CurIcon->pcurNext; 938 } 939 940 /* Now search Global Cursors or Icons. */ 941 if (CurIcon == NULL) 942 { 943 CurIcon = gcurFirst; 944 while (CurIcon) 945 { 946 /* Icon/cursor */ 947 if (paramSafe.bIcon != is_icon(CurIcon)) 948 { 949 CurIcon = CurIcon->pcurNext; 950 continue; 951 } 952 /* See if module names match */ 953 if (atomModName == CurIcon->atomModName) 954 { 955 /* They do. Now see if this is the same resource */ 956 if (IS_INTRESOURCE(CurIcon->strName.Buffer) != IS_INTRESOURCE(ustrRsrcSafe.Buffer)) 957 { 958 /* One is an INT resource and the other is not -> no match */ 959 CurIcon = CurIcon->pcurNext; 960 continue; 961 } 962 if (IS_INTRESOURCE(CurIcon->strName.Buffer)) 963 { 964 if (CurIcon->strName.Buffer == ustrRsrcSafe.Buffer) 965 { 966 /* INT resources match */ 967 break; 968 } 969 } 970 else if (RtlCompareUnicodeString(&ustrRsrcSafe, &CurIcon->strName, TRUE) == 0) 971 { 972 /* Resource name strings match */ 973 break; 974 } 975 } 976 CurIcon = CurIcon->pcurNext; 977 } 978 } 979 if (CurIcon) 980 Ret = UserHMGetHandle(CurIcon); 981 UserLeave(); 982 983 done: 984 if (!IS_INTRESOURCE(ustrRsrcSafe.Buffer)) 985 ExFreePoolWithTag(ustrRsrcSafe.Buffer, TAG_STRING); 986 987 return Ret; 988 } 989 990 991 /* 992 * @implemented 993 */ 994 BOOL 995 APIENTRY 996 NtUserGetClipCursor( 997 RECTL *lpRect) 998 { 999 PSYSTEM_CURSORINFO CurInfo; 1000 RECTL Rect; 1001 NTSTATUS Status; 1002 BOOL Ret = FALSE; 1003 1004 TRACE("Enter NtUserGetClipCursor\n"); 1005 UserEnterShared(); 1006 1007 if (!CheckWinstaAttributeAccess(WINSTA_READATTRIBUTES)) 1008 { 1009 goto Exit; // Return FALSE 1010 } 1011 1012 if (!lpRect) 1013 goto Exit; // Return FALSE 1014 1015 CurInfo = IntGetSysCursorInfo(); 1016 if (CurInfo->bClipped) 1017 { 1018 Rect = CurInfo->rcClip; 1019 } 1020 else 1021 { 1022 Rect.left = 0; 1023 Rect.top = 0; 1024 Rect.right = UserGetSystemMetrics(SM_CXSCREEN); 1025 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN); 1026 } 1027 1028 Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT)); 1029 if (!NT_SUCCESS(Status)) 1030 { 1031 SetLastNtError(Status); 1032 goto Exit; // Return FALSE 1033 } 1034 1035 Ret = TRUE; 1036 1037 Exit: 1038 TRACE("Leave NtUserGetClipCursor, ret=%i\n", Ret); 1039 UserLeave(); 1040 return Ret; 1041 } 1042 1043 1044 /* 1045 * @implemented 1046 */ 1047 HCURSOR 1048 APIENTRY 1049 NtUserSetCursor( 1050 HCURSOR hCursor) 1051 { 1052 PCURICON_OBJECT pcurOld, pcurNew; 1053 HCURSOR hOldCursor = NULL; 1054 1055 TRACE("Enter NtUserSetCursor: %p\n", hCursor); 1056 UserEnterExclusive(); 1057 1058 if (hCursor) 1059 { 1060 pcurNew = UserGetCurIconObject(hCursor); 1061 if (!pcurNew) 1062 { 1063 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); 1064 goto leave; 1065 } 1066 pcurNew->CURSORF_flags |= CURSORF_CURRENT; 1067 } 1068 else 1069 { 1070 pcurNew = NULL; 1071 } 1072 1073 pcurOld = UserSetCursor(pcurNew, FALSE); 1074 1075 // If returning an old cursor than validate it, Justin Case! 1076 if ( pcurOld && 1077 (pcurOld = UserGetObjectNoErr(gHandleTable, UserHMGetHandle(pcurOld), TYPE_CURSOR))) 1078 { 1079 hOldCursor = UserHMGetHandle(pcurOld); 1080 /* 1081 Problem: 1082 1083 System Global Cursors start out having at least 2 lock counts. If a system 1084 cursor is the default cursor and is returned to the caller twice in its 1085 life, the count will reach zero. Causing an assert to occur in objects. 1086 1087 This fixes a SeaMonkey crash while the mouse crosses a boundary. 1088 */ 1089 if (pcurOld->CURSORF_flags & CURSORF_GLOBAL) 1090 { 1091 TRACE("Returning Global Cursor hcur %p\n",hOldCursor); 1092 1093 /*if (pcurOld->head.cLockObj > 2) // Throttle down to 2. 1094 { 1095 UserDereferenceObject(pcurOld); 1096 } 1097 1098 goto leave;*/ 1099 } 1100 1101 /* See if it was destroyed in the meantime */ 1102 if (UserObjectInDestroy(hOldCursor)) 1103 hOldCursor = NULL; 1104 pcurOld->CURSORF_flags &= ~CURSORF_CURRENT; 1105 UserDereferenceObject(pcurOld); 1106 } 1107 1108 leave: 1109 UserLeave(); 1110 return hOldCursor; 1111 } 1112 1113 1114 /* 1115 * @unimplemented 1116 */ 1117 BOOL 1118 APIENTRY 1119 NtUserSetCursorContents( 1120 HANDLE hCurIcon, 1121 PICONINFO UnsafeIconInfo) 1122 { 1123 FIXME(" is UNIMPLEMENTED.\n"); 1124 return FALSE; 1125 } 1126 1127 1128 static 1129 BOOL 1130 IntSetCursorData( 1131 _Inout_ PCURICON_OBJECT pcur, 1132 _In_opt_ PUNICODE_STRING pustrName, 1133 _In_ ATOM atomModName, 1134 _In_ const CURSORDATA* pcursordata) 1135 { 1136 /* Check if the CURSORF_ACON is also set in the cursor data */ 1137 if (pcursordata->CURSORF_flags & CURSORF_ACON) 1138 { 1139 ERR("Mismatch in CURSORF_flags! cursor: 0x%08lx, data: 0x%08lx\n", 1140 pcur->CURSORF_flags, pcursordata->CURSORF_flags); 1141 return FALSE; 1142 } 1143 1144 /* Check if this cursor was already set */ 1145 if (pcur->hbmMask != NULL) 1146 { 1147 ERR("Cursor data already set!\n"); 1148 return FALSE; 1149 } 1150 1151 /* We need a mask */ 1152 if (pcursordata->hbmMask == NULL) 1153 { 1154 ERR("NtUserSetCursorIconData was got no hbmMask.\n"); 1155 EngSetLastError(ERROR_INVALID_PARAMETER); 1156 return FALSE; 1157 } 1158 1159 /* Take ownership of the mask bitmap */ 1160 if (!GreSetBitmapOwner(pcursordata->hbmMask, GDI_OBJ_HMGR_PUBLIC)) 1161 { 1162 ERR("Failed to set ownership of hbmMask %p.\n", pcursordata->hbmMask); 1163 return FALSE; 1164 } 1165 1166 /* Check if we have a color bitmap */ 1167 if (pcursordata->hbmColor) 1168 { 1169 /* Take ownership of the color bitmap */ 1170 if (!GreSetBitmapOwner(pcursordata->hbmColor, GDI_OBJ_HMGR_PUBLIC)) 1171 { 1172 ERR("Failed to set ownership of hbmColor %p.\n", pcursordata->hbmColor); 1173 GreSetBitmapOwner(pcursordata->hbmMask, GDI_OBJ_HMGR_POWNED); 1174 return FALSE; 1175 } 1176 } 1177 1178 /* Check if we have an alpha bitmap */ 1179 if (pcursordata->hbmAlpha) 1180 { 1181 /* Take ownership of the alpha bitmap */ 1182 if (!GreSetBitmapOwner(pcursordata->hbmAlpha, GDI_OBJ_HMGR_PUBLIC)) 1183 { 1184 ERR("Failed to set ownership of hbmAlpha %p.\n", pcursordata->hbmAlpha); 1185 GreSetBitmapOwner(pcursordata->hbmMask, GDI_OBJ_HMGR_POWNED); 1186 if (pcursordata->hbmColor) 1187 { 1188 GreSetBitmapOwner(pcursordata->hbmColor, GDI_OBJ_HMGR_POWNED); 1189 } 1190 return FALSE; 1191 } 1192 } 1193 1194 /* Free the old name (Must be NULL atm, but later we might allow this) */ 1195 NT_ASSERT(pcur->strName.Buffer == NULL); 1196 if (pcur->strName.Buffer != NULL) 1197 { 1198 if (!IS_INTRESOURCE(pcur->strName.Buffer)) 1199 { 1200 ExFreePoolWithTag(pcur->strName.Buffer, TAG_STRING); 1201 } 1202 RtlInitEmptyUnicodeString(&pcur->strName, NULL, 0); 1203 } 1204 1205 /* Free the module atom */ 1206 if (pcur->atomModName != 0) 1207 { 1208 NT_VERIFY(NT_SUCCESS(RtlDeleteAtomFromAtomTable(gAtomTable, pcur->atomModName))); 1209 } 1210 1211 /* Now set the new cursor data */ 1212 pcur->atomModName = atomModName; 1213 pcur->rt = pcursordata->rt; 1214 pcur->CURSORF_flags = pcursordata->CURSORF_flags & CURSORF_USER_MASK; 1215 pcur->xHotspot = pcursordata->xHotspot; 1216 pcur->yHotspot = pcursordata->yHotspot; 1217 pcur->hbmMask = pcursordata->hbmMask; 1218 pcur->hbmColor = pcursordata->hbmColor; 1219 pcur->hbmAlpha = pcursordata->hbmAlpha; 1220 pcur->rcBounds.left = 0; 1221 pcur->rcBounds.top = 0; 1222 pcur->rcBounds.right = pcursordata->cx; 1223 pcur->rcBounds.bottom = pcursordata->cy; 1224 pcur->hbmUserAlpha = pcursordata->hbmUserAlpha; 1225 pcur->bpp = pcursordata->bpp; 1226 pcur->cx = pcursordata->cx; 1227 pcur->cy = pcursordata->cy; 1228 if (pustrName != NULL) 1229 { 1230 pcur->strName = *pustrName; 1231 } 1232 1233 return TRUE; 1234 } 1235 1236 static 1237 BOOL 1238 IntSetAconData( 1239 _Inout_ PACON pacon, 1240 _In_opt_ PUNICODE_STRING pustrName, 1241 _In_ ATOM atomModName, 1242 _In_ const CURSORDATA *pcursordata) 1243 { 1244 PCURICON_OBJECT *aspcur; 1245 DWORD *aicur; 1246 INT *ajifRate; 1247 PCURSORDATA pcdFrame; 1248 HCURSOR hcurFrame; 1249 UINT cjSize, i; 1250 1251 NT_ASSERT((pacon->CURSORF_flags & CURSORF_ACON) != 0); 1252 NT_ASSERT((pacon->CURSORF_flags & CURSORF_ACONFRAME) == 0); 1253 NT_ASSERT((ULONG_PTR)pcursordata->aspcur > MmUserProbeAddress); 1254 NT_ASSERT((ULONG_PTR)pcursordata->aicur > MmUserProbeAddress); 1255 NT_ASSERT((ULONG_PTR)pcursordata->ajifRate > MmUserProbeAddress); 1256 NT_ASSERT((pcursordata->CURSORF_flags & ~CURSORF_USER_MASK) == 0); 1257 NT_ASSERT(pcursordata->cpcur > 0); 1258 NT_ASSERT(pcursordata->cicur > 0); 1259 1260 /* Check if the CURSORF_ACON is also set in the cursor data */ 1261 if (!(pcursordata->CURSORF_flags & CURSORF_ACON)) 1262 { 1263 ERR("Mismatch in CURSORF_flags! acon: 0x%08lx, data: 0x%08lx\n", 1264 pacon->CURSORF_flags, pcursordata->CURSORF_flags); 1265 return FALSE; 1266 } 1267 1268 /* Check if this acon was already set */ 1269 if (pacon->aspcur != NULL) 1270 { 1271 ERR("Acon data already set!\n"); 1272 return FALSE; 1273 } 1274 1275 /* Loop all frames indexes */ 1276 for (i = 0; i < pcursordata->cicur; i++) 1277 { 1278 /* Check if the index is within the range of the frames */ 1279 if (pcursordata->aicur[i] >= pcursordata->cpcur) 1280 { 1281 ERR("aicur[%lu] is out or range. Got %lu, cpcur = %u\n", 1282 i, pcursordata->aicur[i], pcursordata->cpcur); 1283 return FALSE; 1284 } 1285 1286 /* FIXME: check the JIF rates? */ 1287 } 1288 1289 /* Calculate size: one cursor object for each frame, and a frame 1290 index and jiffies for each "step" */ 1291 cjSize = (pcursordata->cpcur * sizeof(CURICON_OBJECT*)) + 1292 (pcursordata->cicur * sizeof(DWORD)) + 1293 (pcursordata->cicur * sizeof(INT)); 1294 1295 /* Allocate a buffer */ 1296 aspcur = ExAllocatePoolWithTag(PagedPool, cjSize, USERTAG_CURSOR); 1297 if (aspcur == NULL) 1298 { 1299 ERR("Failed to allocate memory (cpcur = %u, cicur = %u)\n", 1300 pcursordata->cpcur, pcursordata->cicur); 1301 return FALSE; 1302 } 1303 1304 /* Set the pointers */ 1305 aicur = (DWORD*)&aspcur[pcursordata->cpcur]; 1306 ajifRate = (INT*)&aicur[pcursordata->cicur]; 1307 1308 /* Copy the values */ 1309 RtlCopyMemory(aicur, pcursordata->aicur, pcursordata->cicur * sizeof(DWORD)); 1310 RtlCopyMemory(ajifRate, pcursordata->ajifRate, pcursordata->cicur * sizeof(INT)); 1311 1312 /* Zero out the array, so we can handle cleanup */ 1313 RtlZeroMemory(aspcur, pcursordata->cpcur * sizeof(PCURICON_OBJECT)); 1314 1315 /* Get a pointer to the cursor data for each frame */ 1316 pcdFrame = pcursordata->aspcur; 1317 1318 /* Create the cursors */ 1319 for (i = 0; i < pcursordata->cpcur; i++) 1320 { 1321 /* Create a cursor for this frame */ 1322 hcurFrame = IntCreateCurIconHandle(FALSE); 1323 if (hcurFrame == NULL) 1324 { 1325 ERR("Failed to create a cursor for frame %u\n", i); 1326 goto Cleanup; 1327 } 1328 1329 /* Get a pointer to the frame cursor */ 1330 aspcur[i] = UserGetCurIconObject(hcurFrame); 1331 _PRAGMA_WARNING_SUPPRESS(__WARNING_READ_OVERRUN); 1332 NT_ASSERT(aspcur[i] != NULL); 1333 1334 /* Check if the flags are valid */ 1335 if (pcdFrame->CURSORF_flags & ~(CURSORF_USER_MASK|CURSORF_ACONFRAME)) 1336 { 1337 ERR("Invalid flags for acon frame %u: 0x%08lx\n", 1338 i, pcdFrame->CURSORF_flags); 1339 goto Cleanup; 1340 } 1341 1342 /* Set the cursor data for this frame */ 1343 if (!IntSetCursorData(aspcur[i], NULL, 0, &pcdFrame[i])) 1344 { 1345 ERR("Failed to set cursor data for frame %u\n", i); 1346 goto Cleanup; 1347 } 1348 1349 /* Mark this cursor as an acon frame */ 1350 aspcur[i]->CURSORF_flags |= CURSORF_ACONFRAME; 1351 } 1352 1353 /* Free the old name (Must be NULL atm.) */ 1354 NT_ASSERT(pacon->strName.Buffer == NULL); 1355 if (pacon->strName.Buffer != NULL) 1356 { 1357 if (!IS_INTRESOURCE(pacon->strName.Buffer)) 1358 { 1359 ExFreePoolWithTag(pacon->strName.Buffer, TAG_STRING); 1360 } 1361 RtlInitEmptyUnicodeString(&pacon->strName, NULL, 0); 1362 } 1363 1364 /* Free the module atom */ 1365 if (pacon->atomModName != 0) 1366 { 1367 NT_VERIFY(NT_SUCCESS(RtlDeleteAtomFromAtomTable(gAtomTable, pacon->atomModName))); 1368 } 1369 1370 /* Free the previous frames */ 1371 if (pacon->aspcur != NULL) 1372 { 1373 for (i = 0; i < pacon->cpcur; i++) 1374 { 1375 UserDereferenceObject(pacon->aspcur[i]); 1376 NT_VERIFY(IntDestroyCurIconObject(pacon->aspcur[i]) == TRUE); 1377 } 1378 ExFreePoolWithTag(pacon->aspcur, USERTAG_CURSOR); 1379 } 1380 1381 /* Finally set the data in the acon */ 1382 pacon->atomModName = atomModName; 1383 pacon->rt = pcursordata->rt; 1384 pacon->CURSORF_flags = pcursordata->CURSORF_flags & CURSORF_USER_MASK; 1385 pacon->cpcur = pcursordata->cpcur; 1386 pacon->cicur = pcursordata->cicur; 1387 pacon->aspcur = aspcur; 1388 pacon->aicur = aicur; 1389 pacon->ajifRate = ajifRate; 1390 pacon->iicur = 0; 1391 if (pustrName != NULL) 1392 { 1393 pacon->strName = *pustrName; 1394 } 1395 1396 return TRUE; 1397 1398 Cleanup: 1399 1400 /* Clean up the cursors we created */ 1401 for (i = 0; i < pcursordata->cpcur; i++) 1402 { 1403 if (aspcur[i] == NULL) 1404 break; 1405 1406 /* Destroy this cursor */ 1407 UserDereferenceObject(aspcur[i]); 1408 NT_VERIFY(IntDestroyCurIconObject(aspcur[i]) == TRUE); 1409 } 1410 1411 /* Delete the allocated structure */ 1412 ExFreePoolWithTag(aspcur, USERTAG_CURSOR); 1413 1414 return FALSE; 1415 } 1416 1417 BOOL 1418 APIENTRY 1419 UserSetCursorIconData( 1420 _In_ HCURSOR hcursor, 1421 _In_opt_ PUNICODE_STRING pustrModule, 1422 _In_opt_ PUNICODE_STRING pustrRsrc, 1423 _In_ PCURSORDATA pcursordata) 1424 { 1425 PCURICON_OBJECT pcur; 1426 ATOM atomModName; 1427 NTSTATUS status; 1428 BOOL bResult; 1429 1430 /* Do we have a module name? */ 1431 if (pustrModule != NULL) 1432 { 1433 /* Create an atom for the module name */ 1434 status = RtlAddAtomToAtomTable(gAtomTable, 1435 pustrModule->Buffer, 1436 &atomModName); 1437 if (!NT_SUCCESS(status)) 1438 { 1439 ERR("Failed to create atom from module name '%wZ': 0x%08lx\n", 1440 pustrModule, status); 1441 return FALSE; 1442 } 1443 } 1444 else 1445 { 1446 /* No module name atom */ 1447 atomModName = 0; 1448 } 1449 1450 /* Reference the cursor */ 1451 pcur = UserGetCurIconObject(hcursor); 1452 if (pcur == NULL) 1453 { 1454 ERR("Failed to reference cursor %p\n", hcursor); 1455 bResult = FALSE; 1456 goto Exit; 1457 } 1458 1459 /* Check if this is an acon */ 1460 if (pcur->CURSORF_flags & CURSORF_ACON) 1461 { 1462 bResult = IntSetAconData((PACON)pcur, 1463 pustrRsrc, 1464 atomModName, 1465 pcursordata); 1466 } 1467 else 1468 { 1469 bResult = IntSetCursorData(pcur, 1470 pustrRsrc, 1471 atomModName, 1472 pcursordata); 1473 } 1474 1475 Exit: 1476 1477 /* Check if we had success */ 1478 if (bResult != FALSE) 1479 { 1480 /* Check if this is an LRSHARED cursor now */ 1481 if (pcur->CURSORF_flags & CURSORF_LRSHARED) 1482 { 1483 /* Insert the cursor into the list. */ 1484 IntInsertCursorIntoList(pcur); 1485 } 1486 } 1487 else 1488 { 1489 /* Cleanup on failure */ 1490 if (atomModName != 0) 1491 { 1492 NT_VERIFY(NT_SUCCESS(RtlDeleteAtomFromAtomTable(gAtomTable, atomModName))); 1493 } 1494 } 1495 1496 /* Dereference the cursor and return the result */ 1497 if (pcur) 1498 UserDereferenceObject(pcur); 1499 1500 return bResult; 1501 } 1502 1503 1504 /* 1505 * @implemented 1506 */ 1507 __kernel_entry 1508 BOOL 1509 APIENTRY 1510 NtUserSetCursorIconData( 1511 _In_ HCURSOR hcursor, 1512 _In_opt_ PUNICODE_STRING pustrModule, 1513 _In_opt_ PUNICODE_STRING pustrRsrc, 1514 _In_ const CURSORDATA* pCursorData) 1515 { 1516 CURSORDATA cursordata; 1517 UNICODE_STRING ustrModule, ustrRsrc; 1518 _SEH2_VOLATILE PVOID pvBuffer; 1519 CURSORDATA* aspcur; 1520 DWORD* aicur; 1521 PINT ajifRate; 1522 UINT cjSize; 1523 NTSTATUS status; 1524 BOOL bResult = FALSE; 1525 1526 TRACE("Enter NtUserSetCursorIconData\n"); 1527 1528 /* Initialize buffer, so we can handle cleanup */ 1529 ustrRsrc.Buffer = NULL; 1530 ustrModule.Buffer = NULL; 1531 pvBuffer = NULL; 1532 1533 _SEH2_TRY 1534 { 1535 /* Probe and capture the cursor data structure */ 1536 ProbeForRead(pCursorData, sizeof(*pCursorData), 1); 1537 cursordata = *pCursorData; 1538 1539 /* Check if this is an animated cursor */ 1540 if (cursordata.CURSORF_flags & CURSORF_ACON) 1541 { 1542 /* Check of the range is ok */ 1543 if ((cursordata.cpcur == 0) || (cursordata.cicur == 0) || 1544 (cursordata.cpcur > 1000) || (cursordata.cicur > 1000)) 1545 { 1546 ERR("Range error (cpcur = %u, cicur = %u)\n", 1547 cursordata.cpcur, cursordata.cicur); 1548 goto Exit; 1549 } 1550 1551 /* Calculate size: one cursor data structure for each frame, 1552 and a frame index and jiffies for each "step" */ 1553 cjSize = (cursordata.cpcur * sizeof(CURSORDATA)) + 1554 (cursordata.cicur * sizeof(DWORD)) + 1555 (cursordata.cicur * sizeof(INT)); 1556 1557 /* Allocate a buffer */ 1558 pvBuffer = ExAllocatePoolWithTag(PagedPool, cjSize, USERTAG_CURSOR); 1559 if (pvBuffer == NULL) 1560 { 1561 ERR("Failed to allocate memory (cpcur = %u, cicur = %u)\n", 1562 cursordata.cpcur, cursordata.cicur); 1563 goto Exit; 1564 } 1565 1566 /* Calculate the kernel mode pointers */ 1567 aspcur = (CURSORDATA*)pvBuffer; 1568 aicur = (DWORD*)&aspcur[cursordata.cpcur]; 1569 ajifRate = (INT*)&aicur[cursordata.cicur]; 1570 1571 /* Probe and copy aspcur */ 1572 ProbeForRead(cursordata.aspcur, cursordata.cpcur * sizeof(CURSORDATA), 1); 1573 RtlCopyMemory(aspcur, 1574 cursordata.aspcur, 1575 cursordata.cpcur * sizeof(CURSORDATA)); 1576 1577 /* Probe and copy aicur */ 1578 ProbeForRead(cursordata.aicur, cursordata.cicur * sizeof(DWORD), 1); 1579 RtlCopyMemory(aicur, 1580 cursordata.aicur, 1581 cursordata.cicur * sizeof(DWORD)); 1582 1583 /* Probe and copy ajifRate */ 1584 ProbeForRead(cursordata.ajifRate, cursordata.cicur * sizeof(INT), 1); 1585 RtlCopyMemory(ajifRate, 1586 cursordata.ajifRate, 1587 cursordata.cicur * sizeof(INT)); 1588 1589 /* Set the new pointers */ 1590 cursordata.aspcur = aspcur; 1591 cursordata.aicur = aicur; 1592 cursordata.ajifRate = ajifRate; 1593 } 1594 else 1595 { 1596 /* This is a standard cursor, we don't use the pointers */ 1597 cursordata.aspcur = NULL; 1598 cursordata.aicur = NULL; 1599 cursordata.ajifRate = NULL; 1600 } 1601 } 1602 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1603 { 1604 SetLastNtError(_SEH2_GetExceptionCode()); 1605 goto Exit; 1606 } 1607 _SEH2_END 1608 1609 /* Check if we got a module name */ 1610 if (pustrModule != NULL) 1611 { 1612 /* Capture the name */ 1613 status = ProbeAndCaptureUnicodeString(&ustrModule, UserMode, pustrModule); 1614 if (!NT_SUCCESS(status)) 1615 { 1616 ERR("Failed to copy pustrModule: status 0x%08lx\n", status); 1617 goto Exit; 1618 } 1619 } 1620 1621 /* Check if we got a resource name */ 1622 if (pustrRsrc != NULL) 1623 { 1624 /* We use this function, because INTRESOURCEs and ATOMs are the same */ 1625 status = ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrc, pustrRsrc); 1626 if (!NT_SUCCESS(status)) 1627 { 1628 ERR("Failed to copy pustrRsrc: status 0x%08lx\n", status); 1629 goto Exit; 1630 } 1631 } 1632 1633 /* Make sure the caller doesn't give us invalid flags */ 1634 if (cursordata.CURSORF_flags & ~CURSORF_USER_MASK) 1635 { 1636 ERR("Invalid cursor flags: 0x%08lx\n", cursordata.CURSORF_flags); 1637 goto Exit; 1638 } 1639 1640 /* Acquire the global user lock */ 1641 UserEnterExclusive(); 1642 1643 /* Call the internal function */ 1644 bResult = UserSetCursorIconData(hcursor, 1645 pustrModule ? &ustrModule : NULL, 1646 pustrRsrc ? &ustrRsrc : NULL, 1647 &cursordata); 1648 1649 /* Release the global user lock */ 1650 UserLeave(); 1651 1652 Exit: 1653 1654 /* Free the captured module name */ 1655 if ((ustrModule.Buffer != NULL) && !IS_INTRESOURCE(ustrModule.Buffer)) 1656 { 1657 ReleaseCapturedUnicodeString(&ustrModule, UserMode); 1658 } 1659 1660 if (pvBuffer != NULL) 1661 { 1662 ExFreePoolWithTag(pvBuffer, USERTAG_CURSOR); 1663 } 1664 1665 /* Additional cleanup on failure */ 1666 if (bResult == FALSE) 1667 { 1668 if ((ustrRsrc.Buffer != NULL) && 1669 !IS_INTRESOURCE(ustrRsrc.Buffer)) 1670 { 1671 ExFreePoolWithTag(ustrRsrc.Buffer, TAG_STRING); 1672 } 1673 } 1674 1675 TRACE("Leave NtUserSetCursorIconData, bResult = %i\n", bResult); 1676 1677 return bResult; 1678 } 1679 1680 /* Mostly inspired from wine code. 1681 * We use low level functions because: 1682 * - at this point, the icon bitmap could have a different bit depth than the DC, 1683 * making it thus impossible to use NtCreateCompatibleDC and selecting the bitmap. 1684 * This happens after a mode setting change. 1685 * - it avoids massive GDI objects locking when only the destination surface needs it. 1686 * - It makes (small) performance gains. 1687 */ 1688 BOOL 1689 UserDrawIconEx( 1690 HDC hDc, 1691 INT xLeft, 1692 INT yTop, 1693 PCURICON_OBJECT pIcon, 1694 INT cxWidth, 1695 INT cyHeight, 1696 UINT istepIfAniCur, 1697 HBRUSH hbrFlickerFreeDraw, 1698 UINT diFlags) 1699 { 1700 PSURFACE psurfDest, psurfMask, psurfColor; //, psurfOffScreen = NULL; 1701 PDC pdc = NULL; 1702 BOOL Ret = FALSE; 1703 HBITMAP hbmMask, hbmColor, hbmAlpha; 1704 BOOL bOffScreen; 1705 RECTL rcDest, rcSrc; 1706 CLIPOBJ* pdcClipObj = NULL; 1707 EXLATEOBJ exlo; 1708 1709 /* Stupid case */ 1710 if ((diFlags & DI_NORMAL) == 0) 1711 { 1712 ERR("DrawIconEx called without mask or color bitmap to draw.\n"); 1713 return FALSE; 1714 } 1715 1716 if (pIcon->CURSORF_flags & CURSORF_ACON) 1717 { 1718 ACON* pAcon = (ACON*)pIcon; 1719 if (istepIfAniCur >= pAcon->cicur) 1720 { 1721 ERR("NtUserDrawIconEx: istepIfAniCur too big!\n"); 1722 return FALSE; 1723 } 1724 pIcon = pAcon->aspcur[pAcon->aicur[istepIfAniCur]]; 1725 } 1726 1727 hbmMask = pIcon->hbmMask; 1728 hbmColor = pIcon->hbmColor; 1729 hbmAlpha = pIcon->hbmAlpha; 1730 1731 /* 1732 * Get our objects. 1733 * Shared locks are enough, we are only reading those bitmaps 1734 */ 1735 psurfMask = SURFACE_ShareLockSurface(hbmMask); 1736 if (psurfMask == NULL) 1737 { 1738 ERR("Unable to lock the mask surface.\n"); 1739 return FALSE; 1740 } 1741 1742 /* Color bitmap is not mandatory */ 1743 if (hbmColor == NULL) 1744 { 1745 /* But then the mask bitmap must have the information in it's bottom half */ 1746 ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->cy); 1747 psurfColor = NULL; 1748 } 1749 else if ((psurfColor = SURFACE_ShareLockSurface(hbmColor)) == NULL) 1750 { 1751 ERR("Unable to lock the color bitmap.\n"); 1752 SURFACE_ShareUnlockSurface(psurfMask); 1753 return FALSE; 1754 } 1755 1756 pdc = DC_LockDc(hDc); 1757 if (!pdc) 1758 { 1759 ERR("Could not lock the destination DC.\n"); 1760 SURFACE_ShareUnlockSurface(psurfMask); 1761 if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor); 1762 return FALSE; 1763 } 1764 1765 /* Fix width parameter, if needed */ 1766 if (!cxWidth) 1767 { 1768 if (diFlags & DI_DEFAULTSIZE) 1769 cxWidth = is_icon(pIcon) ? 1770 UserGetSystemMetrics(SM_CXICON) : UserGetSystemMetrics(SM_CXCURSOR); 1771 else 1772 cxWidth = pIcon->cx; 1773 } 1774 1775 /* Fix height parameter, if needed */ 1776 if (!cyHeight) 1777 { 1778 if (diFlags & DI_DEFAULTSIZE) 1779 cyHeight = is_icon(pIcon) ? 1780 UserGetSystemMetrics(SM_CYICON) : UserGetSystemMetrics(SM_CYCURSOR); 1781 else 1782 cyHeight = pIcon->cy; 1783 } 1784 1785 /* Calculate destination rectangle */ 1786 RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight); 1787 IntLPtoDP(pdc, (LPPOINT)&rcDest, 2); 1788 RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); 1789 1790 /* Prepare the underlying surface */ 1791 DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL); 1792 1793 /* We now have our destination surface and rectangle */ 1794 psurfDest = pdc->dclevel.pSurface; 1795 1796 if (psurfDest == NULL) 1797 { 1798 /* Empty DC */ 1799 DC_vFinishBlit(pdc, NULL); 1800 DC_UnlockDc(pdc); 1801 SURFACE_ShareUnlockSurface(psurfMask); 1802 if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor); 1803 return FALSE; 1804 } 1805 1806 /* Set source rect */ 1807 RECTL_vSetRect(&rcSrc, 0, 0, pIcon->cx, pIcon->cy); 1808 1809 /* Should we render off-screen? */ 1810 bOffScreen = hbrFlickerFreeDraw && 1811 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH); 1812 1813 if (bOffScreen) 1814 { 1815 /* Yes: Allocate and paint the offscreen surface */ 1816 EBRUSHOBJ eboFill; 1817 PBRUSH pbrush = BRUSH_ShareLockBrush(hbrFlickerFreeDraw); 1818 1819 TRACE("Performing off-screen rendering.\n"); 1820 1821 if (!pbrush) 1822 { 1823 ERR("Failed to get brush object.\n"); 1824 goto Cleanup; 1825 } 1826 1827 #if 0 //We lock the hdc surface during the whole function it makes no sense to use an offscreen surface for "flicker free" drawing 1828 psurfOffScreen = SURFACE_AllocSurface(STYPE_BITMAP, 1829 cxWidth, cyHeight, psurfDest->SurfObj.iBitmapFormat, 1830 0, 0, NULL); 1831 if (!psurfOffScreen) 1832 { 1833 ERR("Failed to allocate the off-screen surface.\n"); 1834 BRUSH_ShareUnlockBrush(pbrush); 1835 goto Cleanup; 1836 } 1837 1838 /* Paint the brush */ 1839 EBRUSHOBJ_vInit(&eboFill, pbrush, psurfOffScreen, 0x00FFFFFF, 0, NULL); 1840 RECTL_vSetRect(&rcDest, 0, 0, cxWidth, cyHeight); 1841 1842 Ret = IntEngBitBlt(&psurfOffScreen->SurfObj, 1843 NULL, 1844 NULL, 1845 NULL, 1846 NULL, 1847 &rcDest, 1848 NULL, 1849 NULL, 1850 &eboFill.BrushObject, 1851 &pbrush->ptOrigin, 1852 ROP4_PATCOPY); 1853 1854 /* Clean up everything */ 1855 EBRUSHOBJ_vCleanup(&eboFill); 1856 BRUSH_ShareUnlockBrush(pbrush); 1857 1858 if (!Ret) 1859 { 1860 ERR("Failed to paint the off-screen surface.\n"); 1861 goto Cleanup; 1862 } 1863 1864 /* We now have our destination surface */ 1865 psurfDest = psurfOffScreen; 1866 #else 1867 pdcClipObj = (CLIPOBJ *)&pdc->co; 1868 /* Paint the brush */ 1869 EBRUSHOBJ_vInit(&eboFill, pbrush, psurfDest, 0x00FFFFFF, 0, NULL); 1870 1871 Ret = IntEngBitBlt(&psurfDest->SurfObj, 1872 NULL, 1873 NULL, 1874 pdcClipObj, 1875 NULL, 1876 &rcDest, 1877 NULL, 1878 NULL, 1879 &eboFill.BrushObject, 1880 &pbrush->ptOrigin, 1881 ROP4_PATCOPY); 1882 1883 /* Clean up everything */ 1884 EBRUSHOBJ_vCleanup(&eboFill); 1885 BRUSH_ShareUnlockBrush(pbrush); 1886 1887 if (!Ret) 1888 { 1889 ERR("Failed to paint the off-screen surface.\n"); 1890 goto Cleanup; 1891 } 1892 #endif 1893 } 1894 else 1895 { 1896 /* We directly draw to the DC */ 1897 TRACE("Performing on screen rendering.\n"); 1898 pdcClipObj = (CLIPOBJ *)&pdc->co; 1899 // psurfOffScreen = NULL; 1900 } 1901 1902 /* Now do the rendering */ 1903 if (hbmAlpha && ((diFlags & DI_NORMAL) == DI_NORMAL)) 1904 { 1905 BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } }; 1906 PSURFACE psurf = NULL; 1907 1908 psurf = SURFACE_ShareLockSurface(hbmAlpha); 1909 if (!psurf) 1910 { 1911 ERR("SURFACE_LockSurface failed!\n"); 1912 goto NoAlpha; 1913 } 1914 1915 /* Initialize color translation object */ 1916 EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xFFFFFFFF, 0xFFFFFFFF, 0); 1917 1918 /* Now do it */ 1919 Ret = IntEngAlphaBlend(&psurfDest->SurfObj, 1920 &psurf->SurfObj, 1921 pdcClipObj, 1922 &exlo.xlo, 1923 &rcDest, 1924 &rcSrc, 1925 &blendobj); 1926 1927 EXLATEOBJ_vCleanup(&exlo); 1928 SURFACE_ShareUnlockSurface(psurf); 1929 if (Ret) goto done; 1930 ERR("NtGdiAlphaBlend failed!\n"); 1931 } 1932 NoAlpha: 1933 if (diFlags & DI_MASK) 1934 { 1935 DWORD rop4 = (diFlags & DI_IMAGE) ? ROP4_SRCAND : ROP4_SRCCOPY; 1936 1937 EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0); 1938 1939 Ret = IntEngStretchBlt(&psurfDest->SurfObj, 1940 &psurfMask->SurfObj, 1941 NULL, 1942 pdcClipObj, 1943 &exlo.xlo, 1944 NULL, 1945 &rcDest, 1946 &rcSrc, 1947 NULL, 1948 NULL, 1949 NULL, 1950 rop4); 1951 1952 EXLATEOBJ_vCleanup(&exlo); 1953 1954 if (!Ret) 1955 { 1956 ERR("Failed to mask the bitmap data.\n"); 1957 goto Cleanup; 1958 } 1959 } 1960 1961 if (diFlags & DI_IMAGE) 1962 { 1963 if (psurfColor) 1964 { 1965 DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ; 1966 1967 EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0); 1968 1969 Ret = IntEngStretchBlt(&psurfDest->SurfObj, 1970 &psurfColor->SurfObj, 1971 NULL, 1972 pdcClipObj, 1973 &exlo.xlo, 1974 NULL, 1975 &rcDest, 1976 &rcSrc, 1977 NULL, 1978 NULL, 1979 NULL, 1980 rop4); 1981 1982 EXLATEOBJ_vCleanup(&exlo); 1983 1984 if (!Ret) 1985 { 1986 ERR("Failed to render the icon bitmap.\n"); 1987 goto Cleanup; 1988 } 1989 } 1990 else 1991 { 1992 /* Mask bitmap holds the information in its bottom half */ 1993 DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY; 1994 RECTL_vOffsetRect(&rcSrc, 0, pIcon->cy); 1995 1996 EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0); 1997 1998 Ret = IntEngStretchBlt(&psurfDest->SurfObj, 1999 &psurfMask->SurfObj, 2000 NULL, 2001 pdcClipObj, 2002 &exlo.xlo, 2003 NULL, 2004 &rcDest, 2005 &rcSrc, 2006 NULL, 2007 NULL, 2008 NULL, 2009 rop4); 2010 2011 EXLATEOBJ_vCleanup(&exlo); 2012 2013 if (!Ret) 2014 { 2015 ERR("Failed to render the icon bitmap.\n"); 2016 goto Cleanup; 2017 } 2018 } 2019 } 2020 2021 done: 2022 #if 0 2023 /* We're done. Was it a double buffered draw ? */ 2024 if (bOffScreen) 2025 { 2026 /* Yes. Draw it back to our DC */ 2027 POINTL ptSrc = {0, 0}; 2028 2029 /* Calculate destination rectangle */ 2030 RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight); 2031 IntLPtoDP(pdc, (LPPOINT)&rcDest, 2); 2032 RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); 2033 2034 /* Get the clip object */ 2035 pdcClipObj = pdc->rosdc.CombinedClip; 2036 2037 /* We now have our destination surface and rectangle */ 2038 psurfDest = pdc->dclevel.pSurface; 2039 2040 /* Color translation */ 2041 EXLATEOBJ_vInitialize(&exlo, psurfOffScreen->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0); 2042 2043 /* Blt it! */ 2044 Ret = IntEngBitBlt(&psurfDest->SurfObj, 2045 &psurfOffScreen->SurfObj, 2046 NULL, 2047 pdcClipObj, 2048 &exlo.xlo, 2049 &rcDest, 2050 &ptSrc, 2051 NULL, 2052 NULL, 2053 NULL, 2054 ROP4_SRCCOPY); 2055 2056 EXLATEOBJ_vCleanup(&exlo); 2057 } 2058 #endif 2059 Cleanup: 2060 if (pdc) 2061 { 2062 DC_vFinishBlit(pdc, NULL); 2063 DC_UnlockDc(pdc); 2064 } 2065 2066 #if 0 2067 /* Delete off screen rendering surface */ 2068 if (psurfOffScreen) 2069 GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject); 2070 #endif 2071 2072 /* Unlock other surfaces */ 2073 SURFACE_ShareUnlockSurface(psurfMask); 2074 if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor); 2075 2076 return Ret; 2077 } 2078 2079 /* 2080 * @implemented 2081 */ 2082 BOOL 2083 APIENTRY 2084 NtUserDrawIconEx( 2085 HDC hdc, 2086 int xLeft, 2087 int yTop, 2088 HICON hIcon, 2089 int cxWidth, 2090 int cyHeight, 2091 UINT istepIfAniCur, 2092 HBRUSH hbrFlickerFreeDraw, 2093 UINT diFlags, 2094 BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32! 2095 PVOID pDIXData) 2096 { 2097 PCURICON_OBJECT pIcon; 2098 BOOL Ret; 2099 2100 TRACE("Enter NtUserDrawIconEx\n"); 2101 UserEnterExclusive(); 2102 2103 if (!(pIcon = UserGetCurIconObject(hIcon))) 2104 { 2105 ERR("UserGetCurIconObject(0x%p) failed!\n", hIcon); 2106 UserLeave(); 2107 return FALSE; 2108 } 2109 2110 Ret = UserDrawIconEx(hdc, 2111 xLeft, 2112 yTop, 2113 pIcon, 2114 cxWidth, 2115 cyHeight, 2116 istepIfAniCur, 2117 hbrFlickerFreeDraw, 2118 diFlags); 2119 2120 UserDereferenceObject(pIcon); 2121 2122 UserLeave(); 2123 return Ret; 2124 } 2125 2126 /* 2127 * @unimplemented 2128 */ 2129 HCURSOR 2130 NTAPI 2131 NtUserGetCursorFrameInfo( 2132 HCURSOR hCursor, 2133 DWORD istep, 2134 INT* rate_jiffies, 2135 DWORD* num_steps) 2136 { 2137 PCURICON_OBJECT CurIcon; 2138 HCURSOR ret; 2139 INT jiffies = 0; 2140 DWORD steps = 1; 2141 NTSTATUS Status = STATUS_SUCCESS; 2142 2143 TRACE("Enter NtUserGetCursorFrameInfo\n"); 2144 UserEnterShared(); 2145 2146 if (!(CurIcon = UserGetCurIconObject(hCursor))) 2147 { 2148 UserLeave(); 2149 return NULL; 2150 } 2151 2152 ret = UserHMGetHandle(CurIcon); 2153 2154 if (CurIcon->CURSORF_flags & CURSORF_ACON) 2155 { 2156 PACON AniCurIcon = (PACON)CurIcon; 2157 if (istep >= AniCurIcon->cicur) 2158 { 2159 UserDereferenceObject(CurIcon); 2160 UserLeave(); 2161 return NULL; 2162 } 2163 jiffies = AniCurIcon->ajifRate[istep]; 2164 steps = AniCurIcon->cicur; 2165 ret = UserHMGetHandle(AniCurIcon->aspcur[AniCurIcon->aicur[istep]]); 2166 } 2167 2168 _SEH2_TRY 2169 { 2170 ProbeForWrite(rate_jiffies, sizeof(INT), 1); 2171 ProbeForWrite(num_steps, sizeof(DWORD), 1); 2172 *rate_jiffies = jiffies; 2173 *num_steps = steps; 2174 } 2175 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2176 { 2177 Status = _SEH2_GetExceptionCode(); 2178 } 2179 _SEH2_END 2180 2181 if (!NT_SUCCESS(Status)) 2182 { 2183 WARN("Status: 0x%08lx\n", Status); 2184 SetLastNtError(Status); 2185 ret = NULL; 2186 } 2187 2188 UserDereferenceObject(CurIcon); 2189 UserLeave(); 2190 2191 TRACE("Leaving NtUserGetCursorFrameInfo, ret = 0x%p\n", ret); 2192 2193 return ret; 2194 } 2195 2196 /* 2197 * @implemented 2198 */ 2199 BOOL 2200 APIENTRY 2201 NtUserSetSystemCursor( 2202 HCURSOR hcur, 2203 DWORD id) 2204 { 2205 PCURICON_OBJECT pcur, pcurOrig = NULL; 2206 int i; 2207 PPROCESSINFO ppi; 2208 BOOL Ret = FALSE; 2209 UserEnterExclusive(); 2210 2211 if (!CheckWinstaAttributeAccess(WINSTA_WRITEATTRIBUTES)) 2212 { 2213 goto Exit; 2214 } 2215 2216 if (hcur) 2217 { 2218 pcur = UserGetCurIconObject(hcur); 2219 if (!pcur) 2220 { 2221 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); 2222 goto Exit; 2223 } 2224 2225 ppi = PsGetCurrentProcessWin32Process(); 2226 2227 for (i = 0 ; i < 16; i++) 2228 { 2229 if (gasyscur[i].type == id) 2230 { 2231 pcurOrig = gasyscur[i].handle; 2232 2233 if (pcurOrig) break; 2234 2235 if (ppi->W32PF_flags & W32PF_CREATEDWINORDC) 2236 { 2237 gasyscur[i].handle = pcur; 2238 pcur->CURSORF_flags |= CURSORF_GLOBAL; 2239 pcur->head.ppi = NULL; 2240 IntInsertCursorIntoList(pcur); 2241 Ret = TRUE; 2242 } 2243 break; 2244 } 2245 } 2246 if (pcurOrig) 2247 { 2248 FIXME("Need to copy cursor data or do something! pcurOrig %p new pcur %p\n",pcurOrig,pcur); 2249 } 2250 } 2251 Exit: 2252 UserLeave(); 2253 return Ret; 2254 } 2255 2256 /* EOF */ 2257