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
9 * We handle two types of cursors/icons:
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
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
23 DBG_DEFAULT_CHANNEL(UserIcon
);
25 SYSTEM_CURSORINFO gSysCursorInfo
;
27 PCURICON_OBJECT gcurFirst
= NULL
; // After all is done, this should be WINLOGO!
32 SYSTEMCURICO gasyscur
[] = {
47 {OCR_APPSTARTING
,NULL
},
54 SYSTEMCURICO gasysico
[] = {
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;
80 IntInsertCursorIntoList(
81 _Inout_ PCURICON_OBJECT pcur
)
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);
88 /* Get the right list head */
89 ppcurHead
= (pcur
->CURSORF_flags
& CURSORF_GLOBAL
) ?
90 &gcurFirst
: &ppi
->pCursorCache
;
92 UserReferenceObject(pcur
);
93 pcur
->pcurNext
= *ppcurHead
;
95 pcur
->CURSORF_flags
|= CURSORF_LINKED
;
98 // FIXME: should think about using a LIST_ENTRY!
101 IntRemoveCursorFromList(
102 _Inout_ PCURICON_OBJECT pcur
)
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);
110 /* Get the right list head */
111 ppcurHead
= (pcur
->CURSORF_flags
& CURSORF_GLOBAL
) ?
112 &gcurFirst
: &ppi
->pCursorCache
;
114 /* Loop all cursors in the cache */
115 for (ppcur
= ppcurHead
;
117 ppcur
= &(*ppcur
)->pcurNext
)
119 /* Check if this is the one we are looking for */
120 if ((*ppcur
) == pcur
)
122 /* Remove it from the list */
123 (*ppcur
) = pcur
->pcurNext
;
126 UserDereferenceObject(pcur
);
127 pcur
->CURSORF_flags
&= ~CURSORF_LINKED
;
132 /* We did not find it, this must not happen */
137 IntLoadSystenIcons(HICON hcur
, DWORD id
)
139 PCURICON_OBJECT pcur
;
145 pcur
= UserGetCurIconObject(hcur
);
148 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
152 ppi
= PsGetCurrentProcessWin32Process();
154 if (!(ppi
->W32PF_flags
& W32PF_CREATEDWINORDC
))
157 // Set Small Window Icon and do not link.
158 if ( id
== OIC_WINLOGO
+1 )
160 pcur
->CURSORF_flags
|= CURSORF_GLOBAL
;
161 UserReferenceObject(pcur
);
162 pcur
->head
.ppi
= NULL
;
166 for (i
= 0 ; i
< 6; i
++)
168 if (gasysico
[i
].type
== id
)
170 gasysico
[i
].handle
= pcur
;
171 pcur
->CURSORF_flags
|= CURSORF_GLOBAL
;
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.
177 pcur
->head
.ppi
= NULL
;
179 IntInsertCursorIntoList(pcur
);
187 IntGetSysCursorInfo(VOID
)
189 return &gSysCursorInfo
;
194 is_icon(PCURICON_OBJECT object
)
196 return MAKEINTRESOURCE(object
->rt
) == RT_ICON
;
199 /* This function creates a reference for the object! */
200 PCURICON_OBJECT FASTCALL
UserGetCurIconObject(HCURSOR hCurIcon
)
202 PCURICON_OBJECT CurIcon
;
206 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
210 if (UserObjectInDestroy(hCurIcon
))
212 WARN("Requesting invalid/destroyed cursor.\n");
213 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
217 CurIcon
= (PCURICON_OBJECT
)UserReferenceObjectByHandle(hCurIcon
, TYPE_CURSOR
);
220 /* We never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
221 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
225 ASSERT(CurIcon
->head
.cLockObj
>= 1);
230 IntSystemSetCursor(PCURICON_OBJECT pcurNew
)
232 PCURICON_OBJECT pcurOld
= UserSetCursor(pcurNew
, FALSE
);
233 if (pcurNew
) UserReferenceObject(pcurNew
);
234 if (pcurOld
) UserDereferenceObject(pcurOld
);
238 BOOL
UserSetCursorPos( INT x
, INT y
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
241 PSYSTEM_CURSORINFO CurInfo
;
246 if (!(DesktopWindow
= UserGetDesktopWindow()))
251 CurInfo
= IntGetSysCursorInfo();
253 /* Clip cursor position */
254 if (!CurInfo
->bClipped
)
255 rcClip
= DesktopWindow
->rcClient
;
257 rcClip
= CurInfo
->rcClip
;
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
;
267 /* 1. Generate a mouse move message, this sets the htEx and Track Window too. */
268 Msg
.message
= WM_MOUSEMOVE
;
269 Msg
.wParam
= UserGetMouseButtonsState();
270 Msg
.lParam
= MAKELPARAM(x
, y
);
272 co_MsqInsertMouseMessage(&Msg
, flags
, dwExtraInfo
, Hook
);
274 /* 2. Store the new cursor position */
281 IntCreateCurIconHandle(BOOLEAN Animated
)
283 PCURICON_OBJECT CurIcon
;
286 CurIcon
= UserCreateObject(
292 Animated
? sizeof(ACON
) : sizeof(CURICON_OBJECT
));
296 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
302 /* We MUST set this flag, to track whether this is an ACON! */
303 CurIcon
->CURSORF_flags
|= CURSORF_ACON
;
306 NT_ASSERT(CurIcon
->pcurNext
== NULL
);
307 UserDereferenceObject(CurIcon
);
313 IntDestroyCurIconObject(
316 PCURICON_OBJECT CurIcon
= Object
;
318 /* Check if the cursor is in a list */
319 if (CurIcon
->CURSORF_flags
& CURSORF_LINKED
)
321 /* Remove the cursor from it's list */
322 IntRemoveCursorFromList(CurIcon
);
325 /* We just mark the handle as being destroyed.
326 * Deleting all the stuff will be deferred to the actual struct free. */
327 UserDeleteObject(CurIcon
->head
.h
, TYPE_CURSOR
);
335 PCURICON_OBJECT CurIcon
= Object
;
337 if (!(CurIcon
->CURSORF_flags
& CURSORF_ACON
))
339 HBITMAP bmpMask
= CurIcon
->hbmMask
;
340 HBITMAP bmpColor
= CurIcon
->hbmColor
;
341 HBITMAP bmpAlpha
= CurIcon
->hbmAlpha
;
346 GreSetObjectOwner(bmpMask
, GDI_OBJ_HMGR_POWNED
);
347 NT_VERIFY(GreDeleteObject(bmpMask
) == TRUE
);
348 CurIcon
->hbmMask
= NULL
;
352 GreSetObjectOwner(bmpColor
, GDI_OBJ_HMGR_POWNED
);
353 NT_VERIFY(GreDeleteObject(bmpColor
) == TRUE
);
354 CurIcon
->hbmColor
= NULL
;
358 GreSetObjectOwner(bmpAlpha
, GDI_OBJ_HMGR_POWNED
);
359 NT_VERIFY(GreDeleteObject(bmpAlpha
) == TRUE
);
360 CurIcon
->hbmAlpha
= NULL
;
365 PACON AniCurIcon
= (PACON
)CurIcon
;
368 for (i
= 0; i
< AniCurIcon
->cpcur
; i
++)
370 UserDereferenceObject(AniCurIcon
->aspcur
[i
]);
371 NT_VERIFY(IntDestroyCurIconObject(AniCurIcon
->aspcur
[i
]) == TRUE
);
373 ExFreePoolWithTag(AniCurIcon
->aspcur
, USERTAG_CURSOR
);
376 if (CurIcon
->CURSORF_flags
& CURSORF_LRSHARED
)
378 if (!IS_INTRESOURCE(CurIcon
->strName
.Buffer
))
379 ExFreePoolWithTag(CurIcon
->strName
.Buffer
, TAG_STRING
);
380 if (CurIcon
->atomModName
)
381 RtlDeleteAtomFromAtomTable(gAtomTable
, CurIcon
->atomModName
);
382 CurIcon
->strName
.Buffer
= NULL
;
383 CurIcon
->atomModName
= 0;
386 /* Finally free the thing */
387 FreeProcMarkObject(CurIcon
);
391 IntCleanupCurIconCache(PPROCESSINFO Win32Process
)
393 PCURICON_OBJECT CurIcon
;
395 /* Run through the list of icon objects */
396 while (Win32Process
->pCursorCache
)
398 CurIcon
= Win32Process
->pCursorCache
;
399 Win32Process
->pCursorCache
= CurIcon
->pcurNext
;
400 UserDereferenceObject(CurIcon
);
407 _Success_(return != FALSE
)
411 _In_ HANDLE hCurIcon
,
412 _Out_opt_ PICONINFO IconInfo
,
413 _Inout_opt_ PUNICODE_STRING lpModule
,
414 _Inout_opt_ PUNICODE_STRING lpResName
,
415 _Out_opt_ LPDWORD pbpp
,
419 PCURICON_OBJECT CurIcon
;
420 NTSTATUS Status
= STATUS_SUCCESS
;
424 TRACE("Enter NtUserGetIconInfo\n");
426 /* Check if something was actually asked */
427 if (!IconInfo
&& !lpModule
&& !lpResName
)
429 WARN("Nothing to fill.\n");
430 EngSetLastError(ERROR_INVALID_PARAMETER
);
434 UserEnterExclusive();
436 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
438 WARN("UserGetIconObject(0x%p) Failed.\n", hCurIcon
);
443 /* Give back the icon information */
446 PCURICON_OBJECT FrameCurIcon
= CurIcon
;
447 if (CurIcon
->CURSORF_flags
& CURSORF_ACON
)
449 /* Get information from first frame. */
450 FrameCurIcon
= ((PACON
)CurIcon
)->aspcur
[0];
454 ii
.fIcon
= is_icon(FrameCurIcon
);
455 ii
.xHotspot
= FrameCurIcon
->xHotspot
;
456 ii
.yHotspot
= FrameCurIcon
->yHotspot
;
459 ii
.hbmMask
= BITMAP_CopyBitmap(FrameCurIcon
->hbmMask
);
460 GreSetObjectOwner(ii
.hbmMask
, GDI_OBJ_HMGR_POWNED
);
461 ii
.hbmColor
= BITMAP_CopyBitmap(FrameCurIcon
->hbmColor
);
462 GreSetObjectOwner(ii
.hbmColor
, GDI_OBJ_HMGR_POWNED
);
463 colorBpp
= FrameCurIcon
->bpp
;
468 ProbeForWrite(IconInfo
, sizeof(ICONINFO
), 1);
469 RtlCopyMemory(IconInfo
, &ii
, sizeof(ICONINFO
));
473 ProbeForWrite(pbpp
, sizeof(DWORD
), 1);
477 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
479 Status
= _SEH2_GetExceptionCode();
483 if (!NT_SUCCESS(Status
))
485 WARN("Status: 0x%08x.\n", Status
);
486 SetLastNtError(Status
);
491 /* Give back the module name */
495 if (!CurIcon
->atomModName
)
498 RtlQueryAtomInAtomTable(gAtomTable
, CurIcon
->atomModName
, NULL
, NULL
, NULL
, &BufLen
);
499 /* Get the module name from the atom table */
502 BufLen
+= sizeof(WCHAR
);
503 if (BufLen
> (lpModule
->MaximumLength
))
505 lpModule
->Length
= 0;
506 lpModule
->MaximumLength
= BufLen
;
510 ProbeForWrite(lpModule
->Buffer
, lpModule
->MaximumLength
, 1);
511 BufLen
= lpModule
->MaximumLength
;
512 RtlQueryAtomInAtomTable(gAtomTable
, CurIcon
->atomModName
, NULL
, NULL
, lpModule
->Buffer
, &BufLen
);
513 lpModule
->Length
= BufLen
;
516 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
518 Status
= _SEH2_GetExceptionCode();
522 if (!NT_SUCCESS(Status
))
524 SetLastNtError(Status
);
531 if (!CurIcon
->strName
.Buffer
)
537 ProbeForWrite(lpResName
, sizeof(UNICODE_STRING
), 1);
538 if (IS_INTRESOURCE(CurIcon
->strName
.Buffer
))
540 lpResName
->Buffer
= CurIcon
->strName
.Buffer
;
541 lpResName
->Length
= 0;
542 lpResName
->MaximumLength
= 0;
544 else if (lpResName
->MaximumLength
< CurIcon
->strName
.MaximumLength
)
546 lpResName
->Length
= 0;
547 lpResName
->MaximumLength
= CurIcon
->strName
.MaximumLength
;
551 ProbeForWrite(lpResName
->Buffer
, lpResName
->MaximumLength
, 1);
552 RtlCopyMemory(lpResName
->Buffer
, CurIcon
->strName
.Buffer
, CurIcon
->strName
.Length
);
553 lpResName
->Length
= CurIcon
->strName
.Length
;
556 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
558 Status
= _SEH2_GetExceptionCode();
563 if (!NT_SUCCESS(Status
))
565 SetLastNtError(Status
);
572 UserDereferenceObject(CurIcon
);
574 TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret
);
589 PLONG plcx
, // &size.cx
590 PLONG plcy
) // &size.cy
592 PCURICON_OBJECT CurIcon
;
593 NTSTATUS Status
= STATUS_SUCCESS
;
596 TRACE("Enter NtUserGetIconSize\n");
599 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
604 if (CurIcon
->CURSORF_flags
& CURSORF_ACON
)
606 /* Use first frame for animated cursors */
607 PACON AniCurIcon
= (PACON
)CurIcon
;
608 CurIcon
= AniCurIcon
->aspcur
[0];
609 UserDereferenceObject(AniCurIcon
);
610 UserReferenceObject(CurIcon
);
615 ProbeForWrite(plcx
, sizeof(LONG
), 1);
617 ProbeForWrite(plcy
, sizeof(LONG
), 1);
620 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
622 Status
= _SEH2_GetExceptionCode();
626 if (NT_SUCCESS(Status
))
629 SetLastNtError(Status
); // Maybe not, test this
631 UserDereferenceObject(CurIcon
);
634 TRACE("Leave NtUserGetIconSize, ret=%i\n", bRet
);
649 PSYSTEM_CURSORINFO CurInfo
;
650 NTSTATUS Status
= STATUS_SUCCESS
;
651 PCURICON_OBJECT CurIcon
;
653 DECLARE_RETURN(BOOL
);
655 TRACE("Enter NtUserGetCursorInfo\n");
658 CurInfo
= IntGetSysCursorInfo();
659 CurIcon
= (PCURICON_OBJECT
)CurInfo
->CurrentCursorObject
;
661 SafeCi
.cbSize
= sizeof(CURSORINFO
);
662 SafeCi
.flags
= ((CurIcon
&& CurInfo
->ShowingCursor
>= 0) ? CURSOR_SHOWING
: 0);
663 SafeCi
.hCursor
= (CurIcon
? CurIcon
->head
.h
: NULL
);
665 SafeCi
.ptScreenPos
= gpsi
->ptCursor
;
669 if (pci
->cbSize
== sizeof(CURSORINFO
))
671 ProbeForWrite(pci
, sizeof(CURSORINFO
), 1);
672 RtlCopyMemory(pci
, &SafeCi
, sizeof(CURSORINFO
));
677 EngSetLastError(ERROR_INVALID_PARAMETER
);
680 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
682 Status
= _SEH2_GetExceptionCode();
685 if (!NT_SUCCESS(Status
))
687 SetLastNtError(Status
);
693 TRACE("Leave NtUserGetCursorInfo, ret=%i\n",_ret_
);
703 PSYSTEM_CURSORINFO CurInfo
;
704 PWND DesktopWindow
= NULL
;
706 if (!CheckWinstaAttributeAccess(WINSTA_WRITEATTRIBUTES
))
711 CurInfo
= IntGetSysCursorInfo();
713 DesktopWindow
= UserGetDesktopWindow();
715 if (prcl
!= NULL
&& DesktopWindow
!= NULL
)
717 if (prcl
->right
< prcl
->left
|| prcl
->bottom
< prcl
->top
)
719 EngSetLastError(ERROR_INVALID_PARAMETER
);
723 CurInfo
->bClipped
= TRUE
;
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
;
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
;
737 /* Make sure cursor is in clipping region */
738 UserSetCursorPos(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
, 0, 0, FALSE
);
742 CurInfo
->bClipped
= FALSE
;
763 /* Probe and copy rect */
764 ProbeForRead(prcl
, sizeof(RECTL
), 1);
767 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
769 EngSetLastError(ERROR_INVALID_PARAMETER
);
770 _SEH2_YIELD(return FALSE
;)
777 UserEnterExclusive();
779 /* Call the internal function */
780 bResult
= UserClipCursor(prcl
);
794 _In_ HANDLE hCurIcon
,
798 PCURICON_OBJECT CurIcon
= NULL
;
800 TRACE("Enter NtUserDestroyCursorIcon (%p, %i)\n", hCurIcon
, bForce
);
801 UserEnterExclusive();
803 CurIcon
= UserGetCurIconObject(hCurIcon
);
812 /* Can not destroy global objects */
813 if (CurIcon
->head
.ppi
== NULL
)
815 ERR("Trying to delete global cursor!\n");
820 /* Maybe we have good reasons not to destroy this object */
821 if (CurIcon
->head
.ppi
!= PsGetCurrentProcessWin32Process())
823 /* No way, you're not touching my cursor */
828 if (CurIcon
->CURSORF_flags
& CURSORF_CURRENT
)
830 WARN("Trying to delete current cursor!\n");
835 if (CurIcon
->CURSORF_flags
& CURSORF_LRSHARED
)
837 WARN("Trying to delete shared cursor.\n");
838 /* This one is not an error */
844 /* Destroy the handle */
845 ret
= IntDestroyCurIconObject(CurIcon
);
849 UserDereferenceObject(CurIcon
);
850 TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n", ret
);
861 NtUserFindExistingCursorIcon(
862 _In_ PUNICODE_STRING pustrModule
,
863 _In_ PUNICODE_STRING pustrRsrc
,
864 _In_ FINDEXISTINGCURICONPARAM
* param
)
866 PCURICON_OBJECT CurIcon
;
868 UNICODE_STRING ustrModuleSafe
, ustrRsrcSafe
;
869 FINDEXISTINGCURICONPARAM paramSafe
;
871 PPROCESSINFO pProcInfo
= PsGetCurrentProcessWin32Process();
872 RTL_ATOM atomModName
;
874 TRACE("Enter NtUserFindExistingCursorIcon\n");
878 ProbeForRead(param
, sizeof(*param
), 1);
879 RtlCopyMemory(¶mSafe
, param
, sizeof(paramSafe
));
881 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
883 Status
= _SEH2_GetExceptionCode();
887 /* Capture resource name (it can be an INTRESOURCE == ATOM) */
888 Status
= ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrcSafe
, pustrRsrc
);
889 if (!NT_SUCCESS(Status
))
891 Status
= ProbeAndCaptureUnicodeString(&ustrModuleSafe
, UserMode
, pustrModule
);
892 if (!NT_SUCCESS(Status
))
894 Status
= RtlLookupAtomInAtomTable(gAtomTable
, ustrModuleSafe
.Buffer
, &atomModName
);
895 ReleaseCapturedUnicodeString(&ustrModuleSafe
, UserMode
);
896 if (!NT_SUCCESS(Status
))
898 /* The module is not in the atom table. No chance to find the cursor */
903 CurIcon
= pProcInfo
->pCursorCache
;
907 if (paramSafe
.bIcon
!= is_icon(CurIcon
))
909 CurIcon
= CurIcon
->pcurNext
;
912 /* See if module names match */
913 if (atomModName
== CurIcon
->atomModName
)
915 /* They do. Now see if this is the same resource */
916 if (IS_INTRESOURCE(CurIcon
->strName
.Buffer
) != IS_INTRESOURCE(ustrRsrcSafe
.Buffer
))
918 /* One is an INT resource and the other is not -> no match */
919 CurIcon
= CurIcon
->pcurNext
;
923 if (IS_INTRESOURCE(CurIcon
->strName
.Buffer
))
925 if (CurIcon
->strName
.Buffer
== ustrRsrcSafe
.Buffer
)
927 /* INT resources match */
931 else if (RtlCompareUnicodeString(&ustrRsrcSafe
, &CurIcon
->strName
, TRUE
) == 0)
933 /* Resource name strings match */
937 CurIcon
= CurIcon
->pcurNext
;
940 /* Now search Global Cursors or Icons. */
947 if (paramSafe
.bIcon
!= is_icon(CurIcon
))
949 CurIcon
= CurIcon
->pcurNext
;
952 /* See if module names match */
953 if (atomModName
== CurIcon
->atomModName
)
955 /* They do. Now see if this is the same resource */
956 if (IS_INTRESOURCE(CurIcon
->strName
.Buffer
) != IS_INTRESOURCE(ustrRsrcSafe
.Buffer
))
958 /* One is an INT resource and the other is not -> no match */
959 CurIcon
= CurIcon
->pcurNext
;
962 if (IS_INTRESOURCE(CurIcon
->strName
.Buffer
))
964 if (CurIcon
->strName
.Buffer
== ustrRsrcSafe
.Buffer
)
966 /* INT resources match */
970 else if (RtlCompareUnicodeString(&ustrRsrcSafe
, &CurIcon
->strName
, TRUE
) == 0)
972 /* Resource name strings match */
976 CurIcon
= CurIcon
->pcurNext
;
980 Ret
= CurIcon
->head
.h
;
984 if (!IS_INTRESOURCE(ustrRsrcSafe
.Buffer
))
985 ExFreePoolWithTag(ustrRsrcSafe
.Buffer
, TAG_STRING
);
999 PSYSTEM_CURSORINFO CurInfo
;
1002 DECLARE_RETURN(BOOL
);
1004 TRACE("Enter NtUserGetClipCursor\n");
1007 if (!CheckWinstaAttributeAccess(WINSTA_READATTRIBUTES
))
1015 CurInfo
= IntGetSysCursorInfo();
1016 if (CurInfo
->bClipped
)
1018 Rect
= CurInfo
->rcClip
;
1024 Rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1025 Rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1028 Status
= MmCopyToCaller(lpRect
, &Rect
, sizeof(RECT
));
1029 if (!NT_SUCCESS(Status
))
1031 SetLastNtError(Status
);
1038 TRACE("Leave NtUserGetClipCursor, ret=%i\n",_ret_
);
1052 PCURICON_OBJECT pcurOld
, pcurNew
;
1053 HCURSOR hOldCursor
= NULL
;
1055 TRACE("Enter NtUserSetCursor: %p\n", hCursor
);
1056 UserEnterExclusive();
1060 pcurNew
= UserGetCurIconObject(hCursor
);
1063 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
1066 pcurNew
->CURSORF_flags
|= CURSORF_CURRENT
;
1073 pcurOld
= UserSetCursor(pcurNew
, FALSE
);
1075 // If returning an old cursor than validate it, Justin Case!
1077 (pcurOld
= UserGetObjectNoErr(gHandleTable
, UserHMGetHandle(pcurOld
), TYPE_CURSOR
)))
1079 hOldCursor
= UserHMGetHandle(pcurOld
);
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.
1087 This fixes a SeaMonkey crash while the mouse crosses a boundary.
1089 if (pcurOld
->CURSORF_flags
& CURSORF_GLOBAL
)
1091 TRACE("Returning Global Cursor hcur %p\n",hOldCursor
);
1093 /*if (pcurOld->head.cLockObj > 2) // Throttle down to 2.
1095 UserDereferenceObject(pcurOld);
1101 /* See if it was destroyed in the meantime */
1102 if (UserObjectInDestroy(hOldCursor
))
1104 pcurOld
->CURSORF_flags
&= ~CURSORF_CURRENT
;
1105 UserDereferenceObject(pcurOld
);
1119 NtUserSetCursorContents(
1121 PICONINFO UnsafeIconInfo
)
1123 FIXME(" is UNIMPLEMENTED.\n");
1131 _Inout_ PCURICON_OBJECT pcur
,
1132 _In_opt_ PUNICODE_STRING pustrName
,
1133 _In_ ATOM atomModName
,
1134 _In_
const CURSORDATA
* pcursordata
)
1136 /* Check if the CURSORF_ACON is also set in the cursor data */
1137 if (pcursordata
->CURSORF_flags
& CURSORF_ACON
)
1139 ERR("Mismatch in CURSORF_flags! cursor: 0x%08lx, data: 0x%08lx\n",
1140 pcur
->CURSORF_flags
, pcursordata
->CURSORF_flags
);
1144 /* Check if this cursor was already set */
1145 if (pcur
->hbmMask
!= NULL
)
1147 ERR("Cursor data already set!\n");
1151 /* We need a mask */
1152 if (pcursordata
->hbmMask
== NULL
)
1154 ERR("NtUserSetCursorIconData was got no hbmMask.\n");
1155 EngSetLastError(ERROR_INVALID_PARAMETER
);
1159 /* Take ownership of the mask bitmap */
1160 if (!GreSetBitmapOwner(pcursordata
->hbmMask
, GDI_OBJ_HMGR_PUBLIC
))
1162 ERR("Failed to set ownership of hbmMask %p.\n", pcursordata
->hbmMask
);
1166 /* Check if we have a color bitmap */
1167 if (pcursordata
->hbmColor
)
1169 /* Take ownership of the color bitmap */
1170 if (!GreSetBitmapOwner(pcursordata
->hbmColor
, GDI_OBJ_HMGR_PUBLIC
))
1172 ERR("Failed to set ownership of hbmColor %p.\n", pcursordata
->hbmColor
);
1173 GreSetBitmapOwner(pcursordata
->hbmMask
, GDI_OBJ_HMGR_POWNED
);
1178 /* Check if we have an alpha bitmap */
1179 if (pcursordata
->hbmAlpha
)
1181 /* Take ownership of the alpha bitmap */
1182 if (!GreSetBitmapOwner(pcursordata
->hbmAlpha
, GDI_OBJ_HMGR_PUBLIC
))
1184 ERR("Failed to set ownership of hbmAlpha %p.\n", pcursordata
->hbmAlpha
);
1185 GreSetBitmapOwner(pcursordata
->hbmMask
, GDI_OBJ_HMGR_POWNED
);
1186 if (pcursordata
->hbmColor
)
1188 GreSetBitmapOwner(pcursordata
->hbmColor
, GDI_OBJ_HMGR_POWNED
);
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
)
1198 if (!IS_INTRESOURCE(pcur
->strName
.Buffer
))
1200 ExFreePoolWithTag(pcur
->strName
.Buffer
, TAG_STRING
);
1202 RtlInitEmptyUnicodeString(&pcur
->strName
, NULL
, 0);
1205 /* Free the module atom */
1206 if (pcur
->atomModName
!= 0)
1208 NT_VERIFY(NT_SUCCESS(RtlDeleteAtomFromAtomTable(gAtomTable
, pcur
->atomModName
)));
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
)
1230 pcur
->strName
= *pustrName
;
1239 _Inout_ PACON pacon
,
1240 _In_opt_ PUNICODE_STRING pustrName
,
1241 _In_ ATOM atomModName
,
1242 _In_
const CURSORDATA
*pcursordata
)
1244 PCURICON_OBJECT
*aspcur
;
1247 PCURSORDATA pcdFrame
;
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);
1260 /* Check if the CURSORF_ACON is also set in the cursor data */
1261 if (!(pcursordata
->CURSORF_flags
& CURSORF_ACON
))
1263 ERR("Mismatch in CURSORF_flags! acon: 0x%08lx, data: 0x%08lx\n",
1264 pacon
->CURSORF_flags
, pcursordata
->CURSORF_flags
);
1268 /* Check if this acon was already set */
1269 if (pacon
->aspcur
!= NULL
)
1271 ERR("Acon data already set!\n");
1275 /* Loop all frames indexes */
1276 for (i
= 0; i
< pcursordata
->cicur
; i
++)
1278 /* Check if the index is within the range of the frames */
1279 if (pcursordata
->aicur
[i
] >= pcursordata
->cpcur
)
1281 ERR("aicur[%lu] is out or range. Got %lu, cpcur = %u\n",
1282 i
, pcursordata
->aicur
[i
], pcursordata
->cpcur
);
1286 /* FIXME: check the JIF rates? */
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
));
1295 /* Allocate a buffer */
1296 aspcur
= ExAllocatePoolWithTag(PagedPool
, cjSize
, USERTAG_CURSOR
);
1299 ERR("Failed to allocate memory (cpcur = %u, cicur = %u)\n",
1300 pcursordata
->cpcur
, pcursordata
->cicur
);
1304 /* Set the pointers */
1305 aicur
= (DWORD
*)&aspcur
[pcursordata
->cpcur
];
1306 ajifRate
= (INT
*)&aicur
[pcursordata
->cicur
];
1308 /* Copy the values */
1309 RtlCopyMemory(aicur
, pcursordata
->aicur
, pcursordata
->cicur
* sizeof(DWORD
));
1310 RtlCopyMemory(ajifRate
, pcursordata
->ajifRate
, pcursordata
->cicur
* sizeof(INT
));
1312 /* Zero out the array, so we can handle cleanup */
1313 RtlZeroMemory(aspcur
, pcursordata
->cpcur
* sizeof(PCURICON_OBJECT
));
1315 /* Get a pointer to the cursor data for each frame */
1316 pcdFrame
= pcursordata
->aspcur
;
1318 /* Create the cursors */
1319 for (i
= 0; i
< pcursordata
->cpcur
; i
++)
1321 /* Create a cursor for this frame */
1322 hcurFrame
= IntCreateCurIconHandle(FALSE
);
1323 if (hcurFrame
== NULL
)
1325 ERR("Failed to create a cursor for frame %u\n", i
);
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
);
1334 /* Check if the flags are valid */
1335 if (pcdFrame
->CURSORF_flags
& ~(CURSORF_USER_MASK
|CURSORF_ACONFRAME
))
1337 ERR("Invalid flags for acon frame %u: 0x%lx\n",
1338 i
, pcdFrame
->CURSORF_flags
);
1342 /* Set the cursor data for this frame */
1343 if (!IntSetCursorData(aspcur
[i
], NULL
, 0, &pcdFrame
[i
]))
1345 ERR("Failed to set cursor data for frame %u\n", i
);
1349 /* Mark this cursor as an acon frame */
1350 aspcur
[i
]->CURSORF_flags
|= CURSORF_ACONFRAME
;
1353 /* Free the old name (Must be NULL atm.) */
1354 NT_ASSERT(pacon
->strName
.Buffer
== NULL
);
1355 if (pacon
->strName
.Buffer
!= NULL
)
1357 if (!IS_INTRESOURCE(pacon
->strName
.Buffer
))
1359 ExFreePoolWithTag(pacon
->strName
.Buffer
, TAG_STRING
);
1361 RtlInitEmptyUnicodeString(&pacon
->strName
, NULL
, 0);
1364 /* Free the module atom */
1365 if (pacon
->atomModName
!= 0)
1367 NT_VERIFY(NT_SUCCESS(RtlDeleteAtomFromAtomTable(gAtomTable
, pacon
->atomModName
)));
1370 /* Free the previous frames */
1371 if (pacon
->aspcur
!= NULL
)
1373 for (i
= 0; i
< pacon
->cpcur
; i
++)
1375 UserDereferenceObject(pacon
->aspcur
[i
]);
1376 NT_VERIFY(IntDestroyCurIconObject(pacon
->aspcur
[i
]) == TRUE
);
1378 ExFreePoolWithTag(pacon
->aspcur
, USERTAG_CURSOR
);
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
;
1391 if (pustrName
!= NULL
)
1393 pacon
->strName
= *pustrName
;
1400 /* Clean up the cursors we created */
1401 for (i
= 0; i
< pcursordata
->cpcur
; i
++)
1403 if (aspcur
[i
] == NULL
)
1406 /* Destroy this cursor */
1407 UserDereferenceObject(aspcur
[i
]);
1408 NT_VERIFY(IntDestroyCurIconObject(aspcur
[i
]) == TRUE
);
1411 /* Delete the allocated structure */
1412 ExFreePoolWithTag(aspcur
, USERTAG_CURSOR
);
1419 UserSetCursorIconData(
1420 _In_ HCURSOR hcursor
,
1421 _In_opt_ PUNICODE_STRING pustrModule
,
1422 _In_opt_ PUNICODE_STRING pustrRsrc
,
1423 _In_ PCURSORDATA pcursordata
)
1425 PCURICON_OBJECT pcur
;
1430 /* Do we have a module name? */
1431 if (pustrModule
!= NULL
)
1433 /* Create an atom for the module name */
1434 status
= RtlAddAtomToAtomTable(gAtomTable
,
1435 pustrModule
->Buffer
,
1437 if (!NT_SUCCESS(status
))
1439 ERR("Failed to create atom from module name '%wZ': %0x8lx\n",
1440 pustrModule
, status
);
1446 /* No module name atom */
1450 /* Reference the cursor */
1451 pcur
= UserGetCurIconObject(hcursor
);
1454 ERR("Failed to reference cursor %p\n", hcursor
);
1459 /* Check if this is an acon */
1460 if (pcur
->CURSORF_flags
& CURSORF_ACON
)
1462 bResult
= IntSetAconData((PACON
)pcur
,
1469 bResult
= IntSetCursorData(pcur
,
1477 /* Check if we had success */
1478 if (bResult
!= FALSE
)
1480 /* Check if this is an LRSHARED cursor now */
1481 if (pcur
->CURSORF_flags
& CURSORF_LRSHARED
)
1483 /* Insert the cursor into the list. */
1484 IntInsertCursorIntoList(pcur
);
1489 /* Cleanup on failure */
1490 if (atomModName
!= 0)
1492 NT_VERIFY(NT_SUCCESS(RtlDeleteAtomFromAtomTable(gAtomTable
, atomModName
)));
1496 /* Dereference the cursor and return the result */
1498 UserDereferenceObject(pcur
);
1510 NtUserSetCursorIconData(
1511 _In_ HCURSOR hcursor
,
1512 _In_opt_ PUNICODE_STRING pustrModule
,
1513 _In_opt_ PUNICODE_STRING pustrRsrc
,
1514 _In_
const CURSORDATA
* pCursorData
)
1516 CURSORDATA cursordata
;
1517 UNICODE_STRING ustrModule
, ustrRsrc
;
1518 _SEH2_VOLATILE PVOID pvBuffer
;
1524 BOOL bResult
= FALSE
;
1526 TRACE("Enter NtUserSetCursorIconData\n");
1528 /* Initialize buffer, so we can handle cleanup */
1529 ustrRsrc
.Buffer
= NULL
;
1530 ustrModule
.Buffer
= NULL
;
1535 /* Probe and capture the cursor data structure */
1536 ProbeForRead(pCursorData
, sizeof(*pCursorData
), 1);
1537 cursordata
= *pCursorData
;
1539 /* Check if this is an animated cursor */
1540 if (cursordata
.CURSORF_flags
& CURSORF_ACON
)
1542 /* Check of the range is ok */
1543 if ((cursordata
.cpcur
== 0) || (cursordata
.cicur
== 0) ||
1544 (cursordata
.cpcur
> 1000) || (cursordata
.cicur
> 1000))
1546 ERR("Range error (cpcur = %u, cicur = %u)\n",
1547 cursordata
.cpcur
, cursordata
.cicur
);
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
));
1557 /* Allocate a buffer */
1558 pvBuffer
= ExAllocatePoolWithTag(PagedPool
, cjSize
, USERTAG_CURSOR
);
1559 if (pvBuffer
== NULL
)
1561 ERR("Failed to allocate memory (cpcur = %u, cicur = %u)\n",
1562 cursordata
.cpcur
, cursordata
.cicur
);
1566 /* Calculate the kernel mode pointers */
1567 aspcur
= (CURSORDATA
*)pvBuffer
;
1568 aicur
= (DWORD
*)&aspcur
[cursordata
.cpcur
];
1569 ajifRate
= (INT
*)&aicur
[cursordata
.cicur
];
1571 /* Probe and copy aspcur */
1572 ProbeForRead(cursordata
.aspcur
, cursordata
.cpcur
* sizeof(CURSORDATA
), 1);
1573 RtlCopyMemory(aspcur
,
1575 cursordata
.cpcur
* sizeof(CURSORDATA
));
1577 /* Probe and copy aicur */
1578 ProbeForRead(cursordata
.aicur
, cursordata
.cicur
* sizeof(DWORD
), 1);
1579 RtlCopyMemory(aicur
,
1581 cursordata
.cicur
* sizeof(DWORD
));
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
));
1589 /* Set the new pointers */
1590 cursordata
.aspcur
= aspcur
;
1591 cursordata
.aicur
= aicur
;
1592 cursordata
.ajifRate
= ajifRate
;
1596 /* This is a standard cursor, we don't use the pointers */
1597 cursordata
.aspcur
= NULL
;
1598 cursordata
.aicur
= NULL
;
1599 cursordata
.ajifRate
= NULL
;
1602 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1604 SetLastNtError(_SEH2_GetExceptionCode());
1609 /* Check if we got a module name */
1610 if (pustrModule
!= NULL
)
1612 /* Capture the name */
1613 status
= ProbeAndCaptureUnicodeString(&ustrModule
, UserMode
, pustrModule
);
1614 if (!NT_SUCCESS(status
))
1616 ERR("Failed to copy pustrModule: status 0x%08lx\n", status
);
1621 /* Check if we got a resource name */
1622 if (pustrRsrc
!= NULL
)
1624 /* We use this function, because INTRESOURCEs and ATOMs are the same */
1625 status
= ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrc
, pustrRsrc
);
1626 if (!NT_SUCCESS(status
))
1628 ERR("Failed to copy pustrRsrc: status 0x%08lx\n", status
);
1633 /* Make sure the caller doesn't give us invalid flags */
1634 if (cursordata
.CURSORF_flags
& ~CURSORF_USER_MASK
)
1636 ERR("Invalid cursor flags: 0x%08lx\n", cursordata
.CURSORF_flags
);
1640 /* Acquire the global user lock */
1641 UserEnterExclusive();
1643 /* Call the internal function */
1644 bResult
= UserSetCursorIconData(hcursor
,
1645 pustrModule
? &ustrModule
: NULL
,
1646 pustrRsrc
? &ustrRsrc
: NULL
,
1649 /* Release the global user lock */
1654 /* Free the captured module name */
1655 if ((ustrModule
.Buffer
!= NULL
) && !IS_INTRESOURCE(ustrModule
.Buffer
))
1657 ReleaseCapturedUnicodeString(&ustrModule
, UserMode
);
1660 if (pvBuffer
!= NULL
)
1662 ExFreePoolWithTag(pvBuffer
, USERTAG_CURSOR
);
1665 /* Additional cleanup on failure */
1666 if (bResult
== FALSE
)
1668 if (ustrRsrc
.Buffer
!= NULL
)
1670 ExFreePoolWithTag(ustrRsrc
.Buffer
, TAG_STRING
);
1674 TRACE("Leave NtUserSetCursorIconData, bResult = %i\n", bResult
);
1679 /* Mostly inspired from wine code.
1680 * We use low level functions because:
1681 * - at this point, the icon bitmap could have a different bit depth than the DC,
1682 * making it thus impossible to use NtCreateCompatibleDC and selecting the bitmap.
1683 * This happens after a mode setting change.
1684 * - it avoids massive GDI objects locking when only the destination surface needs it.
1685 * - It makes (small) performance gains.
1692 PCURICON_OBJECT pIcon
,
1696 HBRUSH hbrFlickerFreeDraw
,
1699 PSURFACE psurfDest
, psurfMask
, psurfColor
; //, psurfOffScreen = NULL;
1702 HBITMAP hbmMask
, hbmColor
, hbmAlpha
;
1704 RECTL rcDest
, rcSrc
;
1705 CLIPOBJ
* pdcClipObj
= NULL
;
1709 if ((diFlags
& DI_NORMAL
) == 0)
1711 ERR("DrawIconEx called without mask or color bitmap to draw.\n");
1715 if (pIcon
->CURSORF_flags
& CURSORF_ACON
)
1717 ACON
* pAcon
= (ACON
*)pIcon
;
1718 if (istepIfAniCur
>= pAcon
->cicur
)
1720 ERR("NtUserDrawIconEx: istepIfAniCur too big!\n");
1723 pIcon
= pAcon
->aspcur
[pAcon
->aicur
[istepIfAniCur
]];
1726 hbmMask
= pIcon
->hbmMask
;
1727 hbmColor
= pIcon
->hbmColor
;
1728 hbmAlpha
= pIcon
->hbmAlpha
;
1732 * Shared locks are enough, we are only reading those bitmaps
1734 psurfMask
= SURFACE_ShareLockSurface(hbmMask
);
1735 if (psurfMask
== NULL
)
1737 ERR("Unable to lock the mask surface.\n");
1741 /* Color bitmap is not mandatory */
1742 if (hbmColor
== NULL
)
1744 /* But then the mask bitmap must have the information in it's bottom half */
1745 ASSERT(psurfMask
->SurfObj
.sizlBitmap
.cy
== 2*pIcon
->cy
);
1748 else if ((psurfColor
= SURFACE_ShareLockSurface(hbmColor
)) == NULL
)
1750 ERR("Unable to lock the color bitmap.\n");
1751 SURFACE_ShareUnlockSurface(psurfMask
);
1755 pdc
= DC_LockDc(hDc
);
1758 ERR("Could not lock the destination DC.\n");
1759 SURFACE_ShareUnlockSurface(psurfMask
);
1760 if (psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1764 /* Fix width parameter, if needed */
1767 if (diFlags
& DI_DEFAULTSIZE
)
1768 cxWidth
= is_icon(pIcon
) ?
1769 UserGetSystemMetrics(SM_CXICON
) : UserGetSystemMetrics(SM_CXCURSOR
);
1771 cxWidth
= pIcon
->cx
;
1774 /* Fix height parameter, if needed */
1777 if (diFlags
& DI_DEFAULTSIZE
)
1778 cyHeight
= is_icon(pIcon
) ?
1779 UserGetSystemMetrics(SM_CYICON
) : UserGetSystemMetrics(SM_CYCURSOR
);
1781 cyHeight
= pIcon
->cy
;
1784 /* Calculate destination rectangle */
1785 RECTL_vSetRect(&rcDest
, xLeft
, yTop
, xLeft
+ cxWidth
, yTop
+ cyHeight
);
1786 IntLPtoDP(pdc
, (LPPOINT
)&rcDest
, 2);
1787 RECTL_vOffsetRect(&rcDest
, pdc
->ptlDCOrig
.x
, pdc
->ptlDCOrig
.y
);
1789 /* Prepare the underlying surface */
1790 DC_vPrepareDCsForBlit(pdc
, &rcDest
, NULL
, NULL
);
1792 /* We now have our destination surface and rectangle */
1793 psurfDest
= pdc
->dclevel
.pSurface
;
1795 if (psurfDest
== NULL
)
1798 DC_vFinishBlit(pdc
, NULL
);
1800 SURFACE_ShareUnlockSurface(psurfMask
);
1801 if (psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1805 /* Set source rect */
1806 RECTL_vSetRect(&rcSrc
, 0, 0, pIcon
->cx
, pIcon
->cy
);
1808 /* Should we render off-screen? */
1809 bOffScreen
= hbrFlickerFreeDraw
&&
1810 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw
) == GDI_OBJECT_TYPE_BRUSH
);
1814 /* Yes: Allocate and paint the offscreen surface */
1816 PBRUSH pbrush
= BRUSH_ShareLockBrush(hbrFlickerFreeDraw
);
1818 TRACE("Performing off-screen rendering.\n");
1822 ERR("Failed to get brush object.\n");
1826 #if 0 //We lock the hdc surface during the whole function it makes no sense to use an offscreen surface for "flicker free" drawing
1827 psurfOffScreen
= SURFACE_AllocSurface(STYPE_BITMAP
,
1828 cxWidth
, cyHeight
, psurfDest
->SurfObj
.iBitmapFormat
,
1830 if (!psurfOffScreen
)
1832 ERR("Failed to allocate the off-screen surface.\n");
1833 BRUSH_ShareUnlockBrush(pbrush
);
1837 /* Paint the brush */
1838 EBRUSHOBJ_vInit(&eboFill
, pbrush
, psurfOffScreen
, 0x00FFFFFF, 0, NULL
);
1839 RECTL_vSetRect(&rcDest
, 0, 0, cxWidth
, cyHeight
);
1841 Ret
= IntEngBitBlt(&psurfOffScreen
->SurfObj
,
1849 &eboFill
.BrushObject
,
1853 /* Clean up everything */
1854 EBRUSHOBJ_vCleanup(&eboFill
);
1855 BRUSH_ShareUnlockBrush(pbrush
);
1859 ERR("Failed to paint the off-screen surface.\n");
1863 /* We now have our destination surface */
1864 psurfDest
= psurfOffScreen
;
1866 pdcClipObj
= &pdc
->co
.ClipObj
;
1867 /* Paint the brush */
1868 EBRUSHOBJ_vInit(&eboFill
, pbrush
, psurfDest
, 0x00FFFFFF, 0, NULL
);
1870 Ret
= IntEngBitBlt(&psurfDest
->SurfObj
,
1878 &eboFill
.BrushObject
,
1882 /* Clean up everything */
1883 EBRUSHOBJ_vCleanup(&eboFill
);
1884 BRUSH_ShareUnlockBrush(pbrush
);
1888 ERR("Failed to paint the off-screen surface.\n");
1895 /* We directly draw to the DC */
1896 TRACE("Performing on screen rendering.\n");
1897 pdcClipObj
= &pdc
->co
.ClipObj
;
1898 // psurfOffScreen = NULL;
1901 /* Now do the rendering */
1902 if (hbmAlpha
&& ((diFlags
& DI_NORMAL
) == DI_NORMAL
))
1904 BLENDOBJ blendobj
= { {AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
} };
1905 PSURFACE psurf
= NULL
;
1907 psurf
= SURFACE_ShareLockSurface(hbmAlpha
);
1910 ERR("SURFACE_LockSurface failed!\n");
1914 /* Initialize color translation object */
1915 EXLATEOBJ_vInitialize(&exlo
, psurf
->ppal
, psurfDest
->ppal
, 0xFFFFFFFF, 0xFFFFFFFF, 0);
1918 Ret
= IntEngAlphaBlend(&psurfDest
->SurfObj
,
1926 EXLATEOBJ_vCleanup(&exlo
);
1927 SURFACE_ShareUnlockSurface(psurf
);
1929 ERR("NtGdiAlphaBlend failed!\n");
1932 if (diFlags
& DI_MASK
)
1934 DWORD rop4
= (diFlags
& DI_IMAGE
) ? ROP4_SRCAND
: ROP4_SRCCOPY
;
1936 EXLATEOBJ_vInitSrcMonoXlate(&exlo
, psurfDest
->ppal
, 0x00FFFFFF, 0);
1938 Ret
= IntEngStretchBlt(&psurfDest
->SurfObj
,
1939 &psurfMask
->SurfObj
,
1951 EXLATEOBJ_vCleanup(&exlo
);
1955 ERR("Failed to mask the bitmap data.\n");
1960 if (diFlags
& DI_IMAGE
)
1964 DWORD rop4
= (diFlags
& DI_MASK
) ? ROP4_SRCINVERT
: ROP4_SRCCOPY
;
1966 EXLATEOBJ_vInitialize(&exlo
, psurfColor
->ppal
, psurfDest
->ppal
, 0x00FFFFFF, 0x00FFFFFF, 0);
1968 Ret
= IntEngStretchBlt(&psurfDest
->SurfObj
,
1969 &psurfColor
->SurfObj
,
1981 EXLATEOBJ_vCleanup(&exlo
);
1985 ERR("Failed to render the icon bitmap.\n");
1991 /* Mask bitmap holds the information in its bottom half */
1992 DWORD rop4
= (diFlags
& DI_MASK
) ? ROP4_SRCINVERT
: ROP4_SRCCOPY
;
1993 RECTL_vOffsetRect(&rcSrc
, 0, pIcon
->cy
);
1995 EXLATEOBJ_vInitSrcMonoXlate(&exlo
, psurfDest
->ppal
, 0x00FFFFFF, 0);
1997 Ret
= IntEngStretchBlt(&psurfDest
->SurfObj
,
1998 &psurfMask
->SurfObj
,
2010 EXLATEOBJ_vCleanup(&exlo
);
2014 ERR("Failed to render the icon bitmap.\n");
2022 /* We're done. Was it a double buffered draw ? */
2025 /* Yes. Draw it back to our DC */
2026 POINTL ptSrc
= {0, 0};
2028 /* Calculate destination rectangle */
2029 RECTL_vSetRect(&rcDest
, xLeft
, yTop
, xLeft
+ cxWidth
, yTop
+ cyHeight
);
2030 IntLPtoDP(pdc
, (LPPOINT
)&rcDest
, 2);
2031 RECTL_vOffsetRect(&rcDest
, pdc
->ptlDCOrig
.x
, pdc
->ptlDCOrig
.y
);
2033 /* Get the clip object */
2034 pdcClipObj
= pdc
->rosdc
.CombinedClip
;
2036 /* We now have our destination surface and rectangle */
2037 psurfDest
= pdc
->dclevel
.pSurface
;
2039 /* Color translation */
2040 EXLATEOBJ_vInitialize(&exlo
, psurfOffScreen
->ppal
, psurfDest
->ppal
, 0x00FFFFFF, 0x00FFFFFF, 0);
2043 Ret
= IntEngBitBlt(&psurfDest
->SurfObj
,
2044 &psurfOffScreen
->SurfObj
,
2055 EXLATEOBJ_vCleanup(&exlo
);
2061 DC_vFinishBlit(pdc
, NULL
);
2066 /* Delete off screen rendering surface */
2068 GDIOBJ_vDeleteObject(&psurfOffScreen
->BaseObject
);
2071 /* Unlock other surfaces */
2072 SURFACE_ShareUnlockSurface(psurfMask
);
2073 if (psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
2091 HBRUSH hbrFlickerFreeDraw
,
2093 BOOL bMetaHDC
, // When TRUE, GDI functions need to be handled in User32!
2096 PCURICON_OBJECT pIcon
;
2099 TRACE("Enter NtUserDrawIconEx\n");
2100 UserEnterExclusive();
2102 if (!(pIcon
= UserGetCurIconObject(hIcon
)))
2104 ERR("UserGetCurIconObject(0x%p) failed!\n", hIcon
);
2109 Ret
= UserDrawIconEx(hdc
,
2119 UserDereferenceObject(pIcon
);
2130 NtUserGetCursorFrameInfo(
2136 PCURICON_OBJECT CurIcon
;
2140 NTSTATUS Status
= STATUS_SUCCESS
;
2142 TRACE("Enter NtUserGetCursorFrameInfo\n");
2145 if (!(CurIcon
= UserGetCurIconObject(hCursor
)))
2151 ret
= CurIcon
->head
.h
;
2153 if (CurIcon
->CURSORF_flags
& CURSORF_ACON
)
2155 PACON AniCurIcon
= (PACON
)CurIcon
;
2156 if (istep
>= AniCurIcon
->cicur
)
2158 UserDereferenceObject(CurIcon
);
2162 jiffies
= AniCurIcon
->ajifRate
[istep
];
2163 steps
= AniCurIcon
->cicur
;
2164 ret
= AniCurIcon
->aspcur
[AniCurIcon
->aicur
[istep
]]->head
.h
;
2169 ProbeForWrite(rate_jiffies
, sizeof(INT
), 1);
2170 ProbeForWrite(num_steps
, sizeof(DWORD
), 1);
2171 *rate_jiffies
= jiffies
;
2174 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2176 Status
= _SEH2_GetExceptionCode();
2180 if (!NT_SUCCESS(Status
))
2182 WARN("Status: 0x%08x.\n", Status
);
2183 SetLastNtError(Status
);
2187 UserDereferenceObject(CurIcon
);
2190 TRACE("Leaving NtUserGetCursorFrameInfo, ret = 0x%p\n", ret
);
2200 NtUserSetSystemCursor(
2204 PCURICON_OBJECT pcur
, pcurOrig
= NULL
;
2208 UserEnterExclusive();
2210 if (!CheckWinstaAttributeAccess(WINSTA_WRITEATTRIBUTES
))
2217 pcur
= UserGetCurIconObject(hcur
);
2220 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
2224 ppi
= PsGetCurrentProcessWin32Process();
2226 for (i
= 0 ; i
< 16; i
++)
2228 if (gasyscur
[i
].type
== id
)
2230 pcurOrig
= gasyscur
[i
].handle
;
2232 if (pcurOrig
) break;
2234 if (ppi
->W32PF_flags
& W32PF_CREATEDWINORDC
)
2236 gasyscur
[i
].handle
= pcur
;
2237 pcur
->CURSORF_flags
|= CURSORF_GLOBAL
;
2238 pcur
->head
.ppi
= NULL
;
2239 IntInsertCursorIntoList(pcur
);
2247 FIXME("Need to copy cursor data or do something! pcurOrig %p new pcur %p\n",pcurOrig
,pcur
);