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
20 * There's a M:N relationship between processes and (shared) cursor/icons.
21 * A process can have multiple cursor/icons and a cursor/icon can be used
22 * by multiple processes. To keep track of this we keep a list of all
23 * cursor/icons (CurIconList) and per cursor/icon we keep a list of
24 * CURICON_PROCESS structs starting at CurIcon->ProcessList.
28 DBG_DEFAULT_CHANNEL(UserIcon
);
30 static PPAGED_LOOKASIDE_LIST pgProcessLookasideList
;
31 static LIST_ENTRY gCurIconList
;
33 SYSTEM_CURSORINFO gSysCursorInfo
;
38 pgProcessLookasideList
= ExAllocatePool(NonPagedPool
, sizeof(PAGED_LOOKASIDE_LIST
));
39 if(!pgProcessLookasideList
)
42 ExInitializePagedLookasideList(pgProcessLookasideList
,
46 sizeof(CURICON_PROCESS
),
49 InitializeListHead(&gCurIconList
);
51 gSysCursorInfo
.Enabled
= FALSE
;
52 gSysCursorInfo
.ButtonsDown
= 0;
53 gSysCursorInfo
.bClipped
= FALSE
;
54 gSysCursorInfo
.LastBtnDown
= 0;
55 gSysCursorInfo
.CurrentCursorObject
= NULL
;
56 gSysCursorInfo
.ShowingCursor
= -1;
57 gSysCursorInfo
.ClickLockActive
= FALSE
;
58 gSysCursorInfo
.ClickLockTime
= 0;
66 return &gSysCursorInfo
;
69 /* This function creates a reference for the object! */
70 PCURICON_OBJECT FASTCALL
UserGetCurIconObject(HCURSOR hCurIcon
)
72 PCURICON_OBJECT CurIcon
;
76 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
80 CurIcon
= (PCURICON_OBJECT
)UserReferenceObjectByHandle(hCurIcon
, TYPE_CURSOR
);
83 /* We never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
84 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
88 ASSERT(CurIcon
->head
.cLockObj
>= 1);
92 BOOL
UserSetCursorPos( INT x
, INT y
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
95 PSYSTEM_CURSORINFO CurInfo
;
100 if(!(DesktopWindow
= UserGetDesktopWindow()))
105 CurInfo
= IntGetSysCursorInfo();
107 /* Clip cursor position */
108 if (!CurInfo
->bClipped
)
109 rcClip
= DesktopWindow
->rcClient
;
111 rcClip
= CurInfo
->rcClip
;
113 if(x
>= rcClip
.right
) x
= rcClip
.right
- 1;
114 if(x
< rcClip
.left
) x
= rcClip
.left
;
115 if(y
>= rcClip
.bottom
) y
= rcClip
.bottom
- 1;
116 if(y
< rcClip
.top
) y
= rcClip
.top
;
121 /* 1. Generate a mouse move message, this sets the htEx and Track Window too. */
122 Msg
.message
= WM_MOUSEMOVE
;
123 Msg
.wParam
= UserGetMouseButtonsState();
124 Msg
.lParam
= MAKELPARAM(x
, y
);
126 co_MsqInsertMouseMessage(&Msg
, flags
, dwExtraInfo
, Hook
);
128 /* 2. Store the new cursor position */
135 * We have to register that this object is in use by the current
136 * process. The only way to do that seems to be to walk the list
137 * of cursor/icon objects starting at W32Process->CursorIconListHead.
138 * If the object is already present in the list, we don't have to do
139 * anything, if it's not present we add it and inc the ProcessCount
140 * in the object. Having to walk the list kind of sucks, but that's
143 static BOOLEAN FASTCALL
144 ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon
)
146 PPROCESSINFO Win32Process
;
147 PCURICON_PROCESS Current
;
149 Win32Process
= PsGetCurrentProcessWin32Process();
151 LIST_FOR_EACH(Current
, &CurIcon
->ProcessList
, CURICON_PROCESS
, ListEntry
)
153 if (Current
->Process
== Win32Process
)
155 /* Already registered for this process */
160 /* Not registered yet */
161 Current
= ExAllocateFromPagedLookasideList(pgProcessLookasideList
);
166 InsertHeadList(&CurIcon
->ProcessList
, &Current
->ListEntry
);
167 Current
->Process
= Win32Process
;
172 PCURICON_OBJECT FASTCALL
173 IntFindExistingCurIconObject(HMODULE hModule
,
174 HRSRC hRsrc
, LONG cx
, LONG cy
)
176 PCURICON_OBJECT CurIcon
;
178 LIST_FOR_EACH(CurIcon
, &gCurIconList
, CURICON_OBJECT
, ListEntry
)
181 // if (NT_SUCCESS(UserReferenceObjectByPointer(Object, TYPE_CURSOR))) // <- huh????
182 // UserReferenceObject( CurIcon);
184 if ((CurIcon
->hModule
== hModule
) && (CurIcon
->hRsrc
== hRsrc
))
186 if (cx
&& ((cx
!= CurIcon
->Size
.cx
) || (cy
!= CurIcon
->Size
.cy
)))
188 // UserDereferenceObject(CurIcon);
191 if (! ReferenceCurIconByProcess(CurIcon
))
199 // UserDereferenceObject(CurIcon);
207 IntCreateCurIconHandle(BOOLEAN Anim
)
209 PCURICON_OBJECT CurIcon
;
212 CurIcon
= UserCreateObject(
218 sizeof(CURICON_OBJECT
));
222 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
226 CurIcon
->Self
= hCurIcon
;
227 InitializeListHead(&CurIcon
->ProcessList
);
229 if (!ReferenceCurIconByProcess(CurIcon
))
231 ERR("Failed to add process\n");
232 UserDeleteObject(hCurIcon
, TYPE_CURSOR
);
233 UserDereferenceObject(CurIcon
);
237 InsertHeadList(&gCurIconList
, &CurIcon
->ListEntry
);
239 UserDereferenceObject(CurIcon
);
245 IntDestroyCurIconObject(PCURICON_OBJECT CurIcon
, PPROCESSINFO ppi
)
247 PSYSTEM_CURSORINFO CurInfo
;
248 HBITMAP bmpMask
, bmpColor
;
249 BOOLEAN Ret
, bListEmpty
, bFound
= FALSE
;
250 PCURICON_PROCESS Current
= NULL
;
252 /* For handles created without any data (error handling) */
253 if(IsListEmpty(&CurIcon
->ProcessList
))
256 /* Now find this process in the list of processes referencing this object and
257 remove it from that list */
258 LIST_FOR_EACH(Current
, &CurIcon
->ProcessList
, CURICON_PROCESS
, ListEntry
)
260 if (Current
->Process
== ppi
)
263 bListEmpty
= RemoveEntryList(&Current
->ListEntry
);
270 /* This object doesn't belong to this process */
271 EngSetLastError(ERROR_INVALID_HANDLE
);
275 ExFreeToPagedLookasideList(pgProcessLookasideList
, Current
);
277 /* If there are still processes referencing this object we can't destroy it yet */
280 if(CurIcon
->head
.ppi
== ppi
)
282 /* Set the first process of the list as owner */
283 Current
= CONTAINING_RECORD(CurIcon
->ProcessList
.Flink
, CURICON_PROCESS
, ListEntry
);
284 UserSetObjectOwner(CurIcon
, TYPE_CURSOR
, Current
->Process
);
286 UserDereferenceObject(CurIcon
);
291 /* Remove it from the list */
292 RemoveEntryList(&CurIcon
->ListEntry
);
294 CurInfo
= IntGetSysCursorInfo();
296 if (CurInfo
->CurrentCursorObject
== CurIcon
)
298 /* Hide the cursor if we're destroying the current cursor */
299 UserSetCursor(NULL
, TRUE
);
302 bmpMask
= CurIcon
->IconInfo
.hbmMask
;
303 bmpColor
= CurIcon
->IconInfo
.hbmColor
;
308 GreSetObjectOwner(bmpMask
, GDI_OBJ_HMGR_POWNED
);
309 GreDeleteObject(bmpMask
);
310 CurIcon
->IconInfo
.hbmMask
= NULL
;
314 GreSetObjectOwner(bmpColor
, GDI_OBJ_HMGR_POWNED
);
315 GreDeleteObject(bmpColor
);
316 CurIcon
->IconInfo
.hbmColor
= NULL
;
319 /* We were given a pointer, no need to keep the reference anylonger! */
320 UserDereferenceObject(CurIcon
);
321 Ret
= UserDeleteObject(CurIcon
->Self
, TYPE_CURSOR
);
330 PCURICON_OBJECT pcurOld
, pcurNew
;
331 HCURSOR hOldCursor
= NULL
;
335 pcurNew
= UserGetCurIconObject(hCursor
);
338 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
347 pcurOld
= UserSetCursor(pcurNew
, FALSE
);
350 hOldCursor
= (HCURSOR
)pcurOld
->Self
;
351 UserDereferenceObject(pcurOld
);
362 PCURICON_OBJECT CurIcon
;
365 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
370 ret
= IntDestroyCurIconObject(CurIcon
, PsGetCurrentProcessWin32Process());
371 /* Note: IntDestroyCurIconObject will remove our reference for us! */
384 PUNICODE_STRING lpInstName
, // Optional
385 PUNICODE_STRING lpResName
, // Optional
386 LPDWORD pbpp
, // Optional
390 PCURICON_OBJECT CurIcon
;
391 NTSTATUS Status
= STATUS_SUCCESS
;
395 TRACE("Enter NtUserGetIconInfo\n");
396 UserEnterExclusive();
400 EngSetLastError(ERROR_INVALID_PARAMETER
);
404 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
409 RtlCopyMemory(&ii
, &CurIcon
->IconInfo
, sizeof(ICONINFO
));
412 ii
.hbmMask
= BITMAP_CopyBitmap(CurIcon
->IconInfo
.hbmMask
);
413 ii
.hbmColor
= BITMAP_CopyBitmap(CurIcon
->IconInfo
.hbmColor
);
419 psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->IconInfo
.hbmColor
);
422 colorBpp
= BitsPerFormat(psurfBmp
->SurfObj
.iBitmapFormat
);
423 SURFACE_ShareUnlockSurface(psurfBmp
);
430 ProbeForWrite(IconInfo
, sizeof(ICONINFO
), 1);
431 RtlCopyMemory(IconInfo
, &ii
, sizeof(ICONINFO
));
433 /// @todo Implement support for lpInstName
436 RtlInitEmptyUnicodeString(lpInstName
, NULL
, 0);
439 /// @todo Implement support for lpResName
442 RtlInitEmptyUnicodeString(lpResName
, NULL
, 0);
447 ProbeForWrite(pbpp
, sizeof(DWORD
), 1);
451 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
453 Status
= _SEH2_GetExceptionCode();
457 if (NT_SUCCESS(Status
))
460 SetLastNtError(Status
);
462 UserDereferenceObject(CurIcon
);
465 TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret
);
480 PLONG plcx
, // &size.cx
481 PLONG plcy
) // &size.cy
483 PCURICON_OBJECT CurIcon
;
484 NTSTATUS Status
= STATUS_SUCCESS
;
487 TRACE("Enter NtUserGetIconSize\n");
488 UserEnterExclusive();
490 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
497 ProbeForWrite(plcx
, sizeof(LONG
), 1);
498 RtlCopyMemory(plcx
, &CurIcon
->Size
.cx
, sizeof(LONG
));
499 ProbeForWrite(plcy
, sizeof(LONG
), 1);
500 RtlCopyMemory(plcy
, &CurIcon
->Size
.cy
, sizeof(LONG
));
502 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
504 Status
= _SEH2_GetExceptionCode();
508 if (NT_SUCCESS(Status
))
511 SetLastNtError(Status
); // Maybe not, test this
513 UserDereferenceObject(CurIcon
);
516 TRACE("Leave NtUserGetIconSize, ret=%i\n", bRet
);
531 PSYSTEM_CURSORINFO CurInfo
;
532 NTSTATUS Status
= STATUS_SUCCESS
;
533 PCURICON_OBJECT CurIcon
;
535 DECLARE_RETURN(BOOL
);
537 TRACE("Enter NtUserGetCursorInfo\n");
538 UserEnterExclusive();
540 CurInfo
= IntGetSysCursorInfo();
541 CurIcon
= (PCURICON_OBJECT
)CurInfo
->CurrentCursorObject
;
543 SafeCi
.cbSize
= sizeof(CURSORINFO
);
544 SafeCi
.flags
= ((CurIcon
&& CurInfo
->ShowingCursor
>= 0) ? CURSOR_SHOWING
: 0);
545 SafeCi
.hCursor
= (CurIcon
? (HCURSOR
)CurIcon
->Self
: (HCURSOR
)0);
547 SafeCi
.ptScreenPos
= gpsi
->ptCursor
;
551 if (pci
->cbSize
== sizeof(CURSORINFO
))
553 ProbeForWrite(pci
, sizeof(CURSORINFO
), 1);
554 RtlCopyMemory(pci
, &SafeCi
, sizeof(CURSORINFO
));
559 EngSetLastError(ERROR_INVALID_PARAMETER
);
562 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
564 Status
= _SEH2_GetExceptionCode();
567 if (!NT_SUCCESS(Status
))
569 SetLastNtError(Status
);
575 TRACE("Leave NtUserGetCursorInfo, ret=%i\n",_ret_
);
585 /* FIXME: Check if process has WINSTA_WRITEATTRIBUTES */
586 PSYSTEM_CURSORINFO CurInfo
;
587 PWND DesktopWindow
= NULL
;
589 CurInfo
= IntGetSysCursorInfo();
591 DesktopWindow
= UserGetDesktopWindow();
593 if (prcl
!= NULL
&& DesktopWindow
!= NULL
)
595 if (prcl
->right
< prcl
->left
|| prcl
->bottom
< prcl
->top
)
597 EngSetLastError(ERROR_INVALID_PARAMETER
);
601 CurInfo
->bClipped
= TRUE
;
603 /* Set nw cliping region. Note: we can't use RECTL_bIntersectRect because
604 it sets rect to 0 0 0 0 when it's empty. For more info see monitor winetest */
605 CurInfo
->rcClip
.left
= max(prcl
->left
, DesktopWindow
->rcWindow
.left
);
606 CurInfo
->rcClip
.right
= min(prcl
->right
, DesktopWindow
->rcWindow
.right
);
607 if (CurInfo
->rcClip
.right
< CurInfo
->rcClip
.left
)
608 CurInfo
->rcClip
.right
= CurInfo
->rcClip
.left
;
610 CurInfo
->rcClip
.top
= max(prcl
->top
, DesktopWindow
->rcWindow
.top
);
611 CurInfo
->rcClip
.bottom
= min(prcl
->bottom
, DesktopWindow
->rcWindow
.bottom
);
612 if (CurInfo
->rcClip
.bottom
< CurInfo
->rcClip
.top
)
613 CurInfo
->rcClip
.bottom
= CurInfo
->rcClip
.top
;
615 /* Make sure cursor is in clipping region */
616 UserSetCursorPos(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
, 0, 0, FALSE
);
620 CurInfo
->bClipped
= FALSE
;
641 /* Probe and copy rect */
642 ProbeForRead(prcl
, sizeof(RECTL
), 1);
645 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
647 EngSetLastError(ERROR_INVALID_PARAMETER
);
648 _SEH2_YIELD(return FALSE
;)
655 UserEnterExclusive();
657 /* Call the internal function */
658 bResult
= UserClipCursor(prcl
);
672 _In_ HANDLE hCurIcon
,
675 PCURICON_OBJECT CurIcon
;
677 DECLARE_RETURN(BOOL
);
679 TRACE("Enter NtUserDestroyCursorIcon\n");
680 UserEnterExclusive();
682 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
687 ret
= IntDestroyCurIconObject(CurIcon
, PsGetCurrentProcessWin32Process());
688 /* Note: IntDestroyCurIconObject will remove our reference for us! */
693 TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_
);
704 NtUserFindExistingCursorIcon(
710 PCURICON_OBJECT CurIcon
;
711 HANDLE Ret
= (HANDLE
)0;
712 DECLARE_RETURN(HICON
);
714 TRACE("Enter NtUserFindExistingCursorIcon\n");
715 UserEnterExclusive();
717 CurIcon
= IntFindExistingCurIconObject(hModule
, hRsrc
, cx
, cy
);
722 // IntReleaseCurIconObject(CurIcon); // FIXME: Is this correct? Does IntFindExistingCurIconObject add a ref?
726 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
730 TRACE("Leave NtUserFindExistingCursorIcon, ret=%p\n",_ret_
);
744 /* FIXME: Check if process has WINSTA_READATTRIBUTES */
745 PSYSTEM_CURSORINFO CurInfo
;
748 DECLARE_RETURN(BOOL
);
750 TRACE("Enter NtUserGetClipCursor\n");
751 UserEnterExclusive();
756 CurInfo
= IntGetSysCursorInfo();
757 if (CurInfo
->bClipped
)
759 Rect
= CurInfo
->rcClip
;
765 Rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
766 Rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
769 Status
= MmCopyToCaller(lpRect
, &Rect
, sizeof(RECT
));
770 if (!NT_SUCCESS(Status
))
772 SetLastNtError(Status
);
779 TRACE("Leave NtUserGetClipCursor, ret=%i\n",_ret_
);
793 PCURICON_OBJECT pcurOld
, pcurNew
;
794 HCURSOR hOldCursor
= NULL
;
796 TRACE("Enter NtUserSetCursor\n");
797 UserEnterExclusive();
801 pcurNew
= UserGetCurIconObject(hCursor
);
804 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
813 pcurOld
= UserSetCursor(pcurNew
, FALSE
);
816 hOldCursor
= (HCURSOR
)pcurOld
->Self
;
817 UserDereferenceObject(pcurOld
);
831 NtUserSetCursorContents(
833 PICONINFO UnsafeIconInfo
)
835 PCURICON_OBJECT CurIcon
;
840 DECLARE_RETURN(BOOL
);
842 TRACE("Enter NtUserSetCursorContents\n");
843 UserEnterExclusive();
845 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
851 Status
= MmCopyFromCaller(&IconInfo
, UnsafeIconInfo
, sizeof(ICONINFO
));
852 if (!NT_SUCCESS(Status
))
854 SetLastNtError(Status
);
858 /* Delete old bitmaps */
859 if ((CurIcon
->IconInfo
.hbmColor
)
860 && (CurIcon
->IconInfo
.hbmColor
!= IconInfo
.hbmColor
))
862 GreDeleteObject(CurIcon
->IconInfo
.hbmColor
);
864 if ((CurIcon
->IconInfo
.hbmMask
)
865 && CurIcon
->IconInfo
.hbmMask
!= IconInfo
.hbmMask
)
867 GreDeleteObject(CurIcon
->IconInfo
.hbmMask
);
870 /* Copy new IconInfo field */
871 CurIcon
->IconInfo
= IconInfo
;
873 if (CurIcon
->IconInfo
.hbmColor
)
875 psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->IconInfo
.hbmColor
);
879 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
880 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
881 SURFACE_ShareUnlockSurface(psurfBmp
);
882 GreSetObjectOwner(CurIcon
->IconInfo
.hbmColor
, GDI_OBJ_HMGR_PUBLIC
);
886 psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->IconInfo
.hbmMask
);
890 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
891 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
/ 2;
893 SURFACE_ShareUnlockSurface(psurfBmp
);
895 GreSetObjectOwner(CurIcon
->IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
903 UserDereferenceObject(CurIcon
);
908 TRACE("Leave NtUserSetCursorContents, ret=%i\n",_ret_
);
920 NtUserSetCursorIconData(
923 PUNICODE_STRING pstrResName
,
926 PCURICON_OBJECT CurIcon
;
928 NTSTATUS Status
= STATUS_SUCCESS
;
930 DECLARE_RETURN(BOOL
);
932 TRACE("Enter NtUserSetCursorIconData\n");
933 UserEnterExclusive();
935 if (!(CurIcon
= UserGetCurIconObject(Handle
)))
940 CurIcon
->hModule
= hModule
;
941 CurIcon
->hRsrc
= NULL
; //hRsrc;
942 CurIcon
->hGroupRsrc
= NULL
; //hGroupRsrc;
946 ProbeForRead(pIconInfo
, sizeof(ICONINFO
), 1);
947 RtlCopyMemory(&CurIcon
->IconInfo
, pIconInfo
, sizeof(ICONINFO
));
949 CurIcon
->IconInfo
.hbmMask
= BITMAP_CopyBitmap(pIconInfo
->hbmMask
);
950 CurIcon
->IconInfo
.hbmColor
= BITMAP_CopyBitmap(pIconInfo
->hbmColor
);
952 if (CurIcon
->IconInfo
.hbmColor
)
954 if ((psurfBmp
= SURFACE_LockSurface(CurIcon
->IconInfo
.hbmColor
)))
956 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
957 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
958 SURFACE_UnlockSurface(psurfBmp
);
959 GreSetObjectOwner(CurIcon
->IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
962 if (CurIcon
->IconInfo
.hbmMask
)
964 if (CurIcon
->IconInfo
.hbmColor
== NULL
)
966 if ((psurfBmp
= SURFACE_LockSurface(CurIcon
->IconInfo
.hbmMask
)))
968 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
969 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
970 SURFACE_UnlockSurface(psurfBmp
);
973 GreSetObjectOwner(CurIcon
->IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
976 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
978 Status
= _SEH2_GetExceptionCode();
982 if (!NT_SUCCESS(Status
))
983 SetLastNtError(Status
);
987 UserDereferenceObject(CurIcon
);
991 TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_
);
998 NtUserSetCursorIconData(
1006 PCURICON_OBJECT CurIcon
;
1010 DECLARE_RETURN(BOOL
);
1012 TRACE("Enter NtUserSetCursorIconData\n");
1013 UserEnterExclusive();
1015 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
1020 CurIcon
->hModule
= hModule
;
1021 CurIcon
->hRsrc
= hRsrc
;
1022 CurIcon
->hGroupRsrc
= hGroupRsrc
;
1027 Status
= MmCopyFromCaller(&CurIcon
->IconInfo
.fIcon
, fIcon
, sizeof(BOOL
));
1028 if (!NT_SUCCESS(Status
))
1030 SetLastNtError(Status
);
1042 Status
= MmCopyFromCaller(&SafeHotspot
, Hotspot
, sizeof(POINT
));
1043 if (NT_SUCCESS(Status
))
1045 CurIcon
->IconInfo
.xHotspot
= SafeHotspot
.x
;
1046 CurIcon
->IconInfo
.yHotspot
= SafeHotspot
.y
;
1051 SetLastNtError(Status
);
1054 if (!fIcon
&& !Hotspot
)
1062 /* This icon is shared now */
1063 GreSetObjectOwner(CurIcon
->IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
1064 if(CurIcon
->IconInfo
.hbmColor
)
1066 GreSetObjectOwner(CurIcon
->IconInfo
.hbmColor
, GDI_OBJ_HMGR_PUBLIC
);
1069 UserDereferenceObject(CurIcon
);
1074 TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_
);
1080 /* Mostly inspired from wine code.
1081 * We use low level functions because:
1082 * - at this point, the icon bitmap could have a different bit depth than the DC,
1083 * making it thus impossible to use NtCreateCompatibleDC and selecting the bitmap.
1084 * This happens after a mode setting change.
1085 * - it avoids massive GDI objects locking when only the destination surface needs it.
1086 * - It makes (small) performance gains.
1093 PCURICON_OBJECT pIcon
,
1097 HBRUSH hbrFlickerFreeDraw
,
1100 PSURFACE psurfDest
, psurfMask
, psurfColor
, psurfOffScreen
;
1103 HBITMAP hbmMask
, hbmColor
;
1104 BOOL bOffScreen
, bAlpha
= FALSE
;
1105 RECTL rcDest
, rcSrc
;
1106 CLIPOBJ
* pdcClipObj
= NULL
;
1110 if((diFlags
& DI_NORMAL
) == 0)
1112 ERR("DrawIconEx called without mask or color bitmap to draw.\n");
1116 hbmMask
= pIcon
->IconInfo
.hbmMask
;
1117 hbmColor
= pIcon
->IconInfo
.hbmColor
;
1120 ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1124 * Shared locks are enough, we are only reading those bitmaps
1126 psurfMask
= SURFACE_ShareLockSurface(hbmMask
);
1127 if(psurfMask
== NULL
)
1129 ERR("Unable to lock the mask surface.\n");
1133 /* Color bitmap is not mandatory */
1134 if(hbmColor
== NULL
)
1136 /* But then the mask bitmap must have the information in it's bottom half */
1137 ASSERT(psurfMask
->SurfObj
.sizlBitmap
.cy
== 2*pIcon
->Size
.cy
);
1140 else if ((psurfColor
= SURFACE_ShareLockSurface(hbmColor
)) == NULL
)
1142 ERR("Unable to lock the color bitmap.\n");
1143 SURFACE_ShareUnlockSurface(psurfMask
);
1147 /* Set source rect */
1148 RECTL_vSetRect(&rcSrc
, 0, 0, pIcon
->Size
.cx
, pIcon
->Size
.cy
);
1150 /* Check for alpha */
1152 (psurfColor
->SurfObj
.iBitmapFormat
== BMF_32BPP
) &&
1153 (diFlags
& DI_IMAGE
))
1155 PFN_DIB_GetPixel fnSource_GetPixel
= NULL
;
1158 /* In order to correctly display 32 bit icons Windows first scans the image,
1159 because information about transparency is not stored in any image's headers */
1160 fnSource_GetPixel
= DibFunctionsForBitmapFormat
[BMF_32BPP
].DIB_GetPixel
;
1161 for (i
= 0; i
< psurfColor
->SurfObj
.sizlBitmap
.cx
; i
++)
1163 for (j
= 0; j
< psurfColor
->SurfObj
.sizlBitmap
.cy
; j
++)
1165 bAlpha
= ((BYTE
)(fnSource_GetPixel(&psurfColor
->SurfObj
, i
, j
) >> 24) & 0xff);
1174 /* Fix width parameter, if needed */
1177 if(diFlags
& DI_DEFAULTSIZE
)
1178 cxWidth
= pIcon
->IconInfo
.fIcon
?
1179 UserGetSystemMetrics(SM_CXICON
) : UserGetSystemMetrics(SM_CXCURSOR
);
1181 cxWidth
= pIcon
->Size
.cx
;
1184 /* Fix height parameter, if needed */
1187 if(diFlags
& DI_DEFAULTSIZE
)
1188 cyHeight
= pIcon
->IconInfo
.fIcon
?
1189 UserGetSystemMetrics(SM_CYICON
) : UserGetSystemMetrics(SM_CYCURSOR
);
1191 cyHeight
= pIcon
->Size
.cy
;
1194 /* Should we render off-screen? */
1195 bOffScreen
= hbrFlickerFreeDraw
&& (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw
) == GDI_OBJECT_TYPE_BRUSH
);
1199 /* Yes: Allocate and paint the offscreen surface */
1201 PBRUSH pbrush
= BRUSH_ShareLockBrush(hbrFlickerFreeDraw
);
1203 TRACE("Performing off-screen rendering.\n");
1207 ERR("Failed to get brush object.\n");
1208 SURFACE_ShareUnlockSurface(psurfMask
);
1209 if(psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1215 ERR("Attention HAX FIX API DrawIconEx TEST Line 37: psurfColor is NULL going with Mask!\n");
1216 psurfColor
= SURFACE_ShareLockSurface(hbmMask
);
1219 psurfOffScreen
= SURFACE_AllocSurface(STYPE_BITMAP
,
1220 cxWidth
, cyHeight
, psurfColor
->SurfObj
.iBitmapFormat
,
1224 ERR("Failed to allocate the off-screen surface.\n");
1225 SURFACE_ShareUnlockSurface(psurfMask
);
1226 if(psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1227 BRUSH_ShareUnlockBrush(pbrush
);
1231 /* Paint the brush */
1232 EBRUSHOBJ_vInit(&eboFill
, pbrush
, psurfOffScreen
, 0x00FFFFFF, 0, NULL
);
1233 RECTL_vSetRect(&rcDest
, 0, 0, cxWidth
, cyHeight
);
1235 Ret
= IntEngBitBlt(&psurfOffScreen
->SurfObj
,
1243 &eboFill
.BrushObject
,
1247 /* Clean up everything */
1248 EBRUSHOBJ_vCleanup(&eboFill
);
1249 BRUSH_ShareUnlockBrush(pbrush
);
1253 ERR("Failed to paint the off-screen surface.\n");
1254 SURFACE_ShareUnlockSurface(psurfMask
);
1255 if(psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1256 GDIOBJ_vDeleteObject(&psurfOffScreen
->BaseObject
);
1260 /* We now have our destination surface */
1261 psurfDest
= psurfOffScreen
;
1265 /* We directly draw to the DC */
1266 TRACE("Performing on screen rendering.\n");
1268 psurfOffScreen
= NULL
;
1269 pdc
= DC_LockDc(hDc
);
1272 ERR("Could not lock the destination DC.\n");
1273 SURFACE_ShareUnlockSurface(psurfMask
);
1274 if(psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1277 /* Calculate destination rectangle */
1278 RECTL_vSetRect(&rcDest
, xLeft
, yTop
, xLeft
+ cxWidth
, yTop
+ cyHeight
);
1279 IntLPtoDP(pdc
, (LPPOINT
)&rcDest
, 2);
1280 RECTL_vOffsetRect(&rcDest
, pdc
->ptlDCOrig
.x
, pdc
->ptlDCOrig
.y
);
1282 /* Prepare the underlying surface */
1283 DC_vPrepareDCsForBlit(pdc
, &rcDest
, NULL
, NULL
);
1285 /* Get the clip object */
1286 pdcClipObj
= &pdc
->co
.ClipObj
;
1288 /* We now have our destination surface and rectangle */
1289 psurfDest
= pdc
->dclevel
.pSurface
;
1291 if(psurfDest
== NULL
)
1294 DC_vFinishBlit(pdc
, NULL
);
1296 SURFACE_ShareUnlockSurface(psurfMask
);
1297 if(psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1302 /* Now do the rendering */
1303 if(bAlpha
&& (diFlags
& DI_IMAGE
))
1305 BLENDOBJ blendobj
= { {AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
} };
1308 PSURFACE psurf
= NULL
;
1310 HBITMAP hsurfCopy
= NULL
;
1312 hsurfCopy
= BITMAP_CopyBitmap(hbmColor
);
1315 ERR("BITMAP_CopyBitmap failed!");
1319 psurf
= SURFACE_ShareLockSurface(hsurfCopy
);
1322 ERR("SURFACE_LockSurface failed!\n");
1326 /* Premultiply with the alpha channel value */
1327 for (i
= 0; i
< psurf
->SurfObj
.sizlBitmap
.cy
; i
++)
1329 ptr
= (PBYTE
)psurf
->SurfObj
.pvScan0
+ i
*psurf
->SurfObj
.lDelta
;
1330 for (j
= 0; j
< psurf
->SurfObj
.sizlBitmap
.cx
; j
++)
1333 ptr
[0] = (ptr
[0] * Alpha
) / 0xff;
1334 ptr
[1] = (ptr
[1] * Alpha
) / 0xff;
1335 ptr
[2] = (ptr
[2] * Alpha
) / 0xff;
1341 /* Initialize color translation object */
1342 EXLATEOBJ_vInitialize(&exlo
, psurf
->ppal
, psurfDest
->ppal
, 0xFFFFFFFF, 0xFFFFFFFF, 0);
1345 Ret
= IntEngAlphaBlend(&psurfDest
->SurfObj
,
1353 EXLATEOBJ_vCleanup(&exlo
);
1356 if(psurf
) SURFACE_ShareUnlockSurface(psurf
);
1357 if(hsurfCopy
) NtGdiDeleteObjectApp(hsurfCopy
);
1359 ERR("NtGdiAlphaBlend failed!\n");
1362 if (diFlags
& DI_MASK
)
1364 DWORD rop4
= (diFlags
& DI_IMAGE
) ? ROP4_SRCAND
: ROP4_SRCCOPY
;
1366 EXLATEOBJ_vInitSrcMonoXlate(&exlo
, psurfDest
->ppal
, 0x00FFFFFF, 0);
1368 Ret
= IntEngStretchBlt(&psurfDest
->SurfObj
,
1369 &psurfMask
->SurfObj
,
1381 EXLATEOBJ_vCleanup(&exlo
);
1385 ERR("Failed to mask the bitmap data.\n");
1390 if(diFlags
& DI_IMAGE
)
1394 DWORD rop4
= (diFlags
& DI_MASK
) ? ROP4_SRCINVERT
: ROP4_SRCCOPY
;
1396 EXLATEOBJ_vInitialize(&exlo
, psurfColor
->ppal
, psurfDest
->ppal
, 0x00FFFFFF, 0x00FFFFFF, 0);
1398 Ret
= IntEngStretchBlt(&psurfDest
->SurfObj
,
1399 &psurfColor
->SurfObj
,
1411 EXLATEOBJ_vCleanup(&exlo
);
1415 ERR("Failed to render the icon bitmap.\n");
1421 /* Mask bitmap holds the information in its bottom half */
1422 DWORD rop4
= (diFlags
& DI_MASK
) ? ROP4_SRCINVERT
: ROP4_SRCCOPY
;
1423 RECTL_vOffsetRect(&rcSrc
, 0, pIcon
->Size
.cy
);
1425 EXLATEOBJ_vInitSrcMonoXlate(&exlo
, psurfDest
->ppal
, 0x00FFFFFF, 0);
1427 Ret
= IntEngStretchBlt(&psurfDest
->SurfObj
,
1428 &psurfMask
->SurfObj
,
1440 EXLATEOBJ_vCleanup(&exlo
);
1444 ERR("Failed to render the icon bitmap.\n");
1451 /* We're done. Was it a double buffered draw ? */
1454 /* Yes. Draw it back to our DC */
1455 POINTL ptSrc
= {0, 0};
1456 pdc
= DC_LockDc(hDc
);
1459 ERR("Could not lock the destination DC.\n");
1462 /* Calculate destination rectangle */
1463 RECTL_vSetRect(&rcDest
, xLeft
, yTop
, xLeft
+ cxWidth
, yTop
+ cyHeight
);
1464 IntLPtoDP(pdc
, (LPPOINT
)&rcDest
, 2);
1465 RECTL_vOffsetRect(&rcDest
, pdc
->ptlDCOrig
.x
, pdc
->ptlDCOrig
.y
);
1467 /* Prepare the underlying surface */
1468 DC_vPrepareDCsForBlit(pdc
, &rcDest
, NULL
, NULL
);
1470 /* Get the clip object */
1471 pdcClipObj
= &pdc
->co
.ClipObj
;
1473 /* We now have our destination surface and rectangle */
1474 psurfDest
= pdc
->dclevel
.pSurface
;
1477 /* So, you did all of this for an empty DC. */
1482 /* Color translation */
1483 EXLATEOBJ_vInitialize(&exlo
, psurfOffScreen
->ppal
, psurfDest
->ppal
, 0x00FFFFFF, 0x00FFFFFF, 0);
1486 Ret
= IntEngBitBlt(&psurfDest
->SurfObj
,
1487 &psurfOffScreen
->SurfObj
,
1498 EXLATEOBJ_vCleanup(&exlo
);
1503 DC_vFinishBlit(pdc
, NULL
);
1508 /* Delete off screen rendering surface */
1510 GDIOBJ_vDeleteObject(&psurfOffScreen
->BaseObject
);
1512 /* Unlock other surfaces */
1513 SURFACE_ShareUnlockSurface(psurfMask
);
1514 if(psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1532 HBRUSH hbrFlickerFreeDraw
,
1534 BOOL bMetaHDC
, // When TRUE, GDI functions need to be handled in User32!
1537 PCURICON_OBJECT pIcon
;
1540 TRACE("Enter NtUserDrawIconEx\n");
1541 UserEnterExclusive();
1543 if (!(pIcon
= UserGetCurIconObject(hIcon
)))
1545 ERR("UserGetCurIconObject() failed!\n");
1550 Ret
= UserDrawIconEx(hdc
,
1560 UserDereferenceObject(pIcon
);
1571 NtUserGetCursorFrameInfo(