2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Cursor and icon functions
5 * FILE: subsystem/win32/win32k/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
, otCursorIcon
);
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, otCursorIcon))) //<- 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()
209 PCURICON_OBJECT CurIcon
;
212 CurIcon
= UserCreateObject(gHandleTable
, NULL
, &hCurIcon
, otCursorIcon
, sizeof(CURICON_OBJECT
));
216 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
220 CurIcon
->Self
= hCurIcon
;
221 InitializeListHead(&CurIcon
->ProcessList
);
223 if (! ReferenceCurIconByProcess(CurIcon
))
225 ERR("Failed to add process\n");
226 UserDeleteObject(hCurIcon
, otCursorIcon
);
227 UserDereferenceObject(CurIcon
);
231 InsertHeadList(&gCurIconList
, &CurIcon
->ListEntry
);
237 IntDestroyCurIconObject(PCURICON_OBJECT CurIcon
, BOOL ProcessCleanup
)
239 PSYSTEM_CURSORINFO CurInfo
;
240 HBITMAP bmpMask
, bmpColor
;
242 PCURICON_PROCESS Current
= NULL
;
243 PPROCESSINFO W32Process
= PsGetCurrentProcessWin32Process();
245 /* Private objects can only be destroyed by their own process */
246 if (NULL
== CurIcon
->hModule
)
248 ASSERT(CurIcon
->ProcessList
.Flink
->Flink
== &CurIcon
->ProcessList
);
249 Current
= CONTAINING_RECORD(CurIcon
->ProcessList
.Flink
, CURICON_PROCESS
, ListEntry
);
250 if (Current
->Process
!= W32Process
)
252 ERR("Trying to destroy private icon/cursor of another process\n");
256 else if (! ProcessCleanup
)
258 TRACE("Trying to destroy shared icon/cursor\n");
262 /* Now find this process in the list of processes referencing this object and
263 remove it from that list */
264 LIST_FOR_EACH(Current
, &CurIcon
->ProcessList
, CURICON_PROCESS
, ListEntry
)
266 if (Current
->Process
== W32Process
)
268 RemoveEntryList(&Current
->ListEntry
);
273 ExFreeToPagedLookasideList(pgProcessLookasideList
, Current
);
275 /* If there are still processes referencing this object we can't destroy it yet */
276 if (! IsListEmpty(&CurIcon
->ProcessList
))
282 if (! ProcessCleanup
)
284 RemoveEntryList(&CurIcon
->ListEntry
);
287 CurInfo
= IntGetSysCursorInfo();
289 if (CurInfo
->CurrentCursorObject
== CurIcon
)
291 /* Hide the cursor if we're destroying the current cursor */
292 UserSetCursor(NULL
, TRUE
);
295 bmpMask
= CurIcon
->IconInfo
.hbmMask
;
296 bmpColor
= CurIcon
->IconInfo
.hbmColor
;
301 GreSetObjectOwner(bmpMask
, GDI_OBJ_HMGR_POWNED
);
302 GreDeleteObject(bmpMask
);
303 CurIcon
->IconInfo
.hbmMask
= NULL
;
307 GreSetObjectOwner(bmpColor
, GDI_OBJ_HMGR_POWNED
);
308 GreDeleteObject(bmpColor
);
309 CurIcon
->IconInfo
.hbmColor
= NULL
;
312 /* We were given a pointer, no need to keep the reference anylonger! */
313 UserDereferenceObject(CurIcon
);
314 Ret
= UserDeleteObject(CurIcon
->Self
, otCursorIcon
);
320 IntCleanupCurIcons(struct _EPROCESS
*Process
, PPROCESSINFO Win32Process
)
322 PCURICON_OBJECT CurIcon
, tmp
;
323 PCURICON_PROCESS ProcessData
;
325 LIST_FOR_EACH_SAFE(CurIcon
, tmp
, &gCurIconList
, CURICON_OBJECT
, ListEntry
)
327 UserReferenceObject(CurIcon
);
328 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon)))
330 LIST_FOR_EACH(ProcessData
, &CurIcon
->ProcessList
, CURICON_PROCESS
, ListEntry
)
332 if (Win32Process
== ProcessData
->Process
)
334 RemoveEntryList(&CurIcon
->ListEntry
);
335 IntDestroyCurIconObject(CurIcon
, TRUE
);
341 // UserDereferenceObject(Object);
346 UserDereferenceObject(CurIcon
);
361 PUNICODE_STRING lpInstName
, // optional
362 PUNICODE_STRING lpResName
, // optional
363 LPDWORD pbpp
, // optional
367 PCURICON_OBJECT CurIcon
;
368 NTSTATUS Status
= STATUS_SUCCESS
;
372 TRACE("Enter NtUserGetIconInfo\n");
373 UserEnterExclusive();
377 EngSetLastError(ERROR_INVALID_PARAMETER
);
381 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
386 RtlCopyMemory(&ii
, &CurIcon
->IconInfo
, sizeof(ICONINFO
));
389 ii
.hbmMask
= BITMAP_CopyBitmap(CurIcon
->IconInfo
.hbmMask
);
390 ii
.hbmColor
= BITMAP_CopyBitmap(CurIcon
->IconInfo
.hbmColor
);
396 psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->IconInfo
.hbmColor
);
399 colorBpp
= BitsPerFormat(psurfBmp
->SurfObj
.iBitmapFormat
);
400 SURFACE_ShareUnlockSurface(psurfBmp
);
407 ProbeForWrite(IconInfo
, sizeof(ICONINFO
), 1);
408 RtlCopyMemory(IconInfo
, &ii
, sizeof(ICONINFO
));
412 ProbeForWrite(pbpp
, sizeof(DWORD
), 1);
416 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
418 Status
= _SEH2_GetExceptionCode();
422 if (NT_SUCCESS(Status
))
425 SetLastNtError(Status
);
427 UserDereferenceObject(CurIcon
);
430 TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret
);
445 PLONG plcx
, // &size.cx
446 PLONG plcy
) // &size.cy
448 PCURICON_OBJECT CurIcon
;
449 NTSTATUS Status
= STATUS_SUCCESS
;
452 TRACE("Enter NtUserGetIconSize\n");
453 UserEnterExclusive();
455 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
462 ProbeForWrite(plcx
, sizeof(LONG
), 1);
463 RtlCopyMemory(plcx
, &CurIcon
->Size
.cx
, sizeof(LONG
));
464 ProbeForWrite(plcy
, sizeof(LONG
), 1);
465 RtlCopyMemory(plcy
, &CurIcon
->Size
.cy
, sizeof(LONG
));
467 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
469 Status
= _SEH2_GetExceptionCode();
473 if (NT_SUCCESS(Status
))
476 SetLastNtError(Status
); // maybe not, test this
478 UserDereferenceObject(CurIcon
);
481 TRACE("Leave NtUserGetIconSize, ret=%i\n", bRet
);
496 PSYSTEM_CURSORINFO CurInfo
;
497 NTSTATUS Status
= STATUS_SUCCESS
;
498 PCURICON_OBJECT CurIcon
;
500 DECLARE_RETURN(BOOL
);
502 TRACE("Enter NtUserGetCursorInfo\n");
503 UserEnterExclusive();
505 CurInfo
= IntGetSysCursorInfo();
506 CurIcon
= (PCURICON_OBJECT
)CurInfo
->CurrentCursorObject
;
508 SafeCi
.cbSize
= sizeof(CURSORINFO
);
509 SafeCi
.flags
= ((CurIcon
&& CurInfo
->ShowingCursor
>= 0) ? CURSOR_SHOWING
: 0);
510 SafeCi
.hCursor
= (CurIcon
? (HCURSOR
)CurIcon
->Self
: (HCURSOR
)0);
512 SafeCi
.ptScreenPos
= gpsi
->ptCursor
;
516 if (pci
->cbSize
== sizeof(CURSORINFO
))
518 ProbeForWrite(pci
, sizeof(CURSORINFO
), 1);
519 RtlCopyMemory(pci
, &SafeCi
, sizeof(CURSORINFO
));
524 EngSetLastError(ERROR_INVALID_PARAMETER
);
527 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
529 Status
= _SEH2_GetExceptionCode();
532 if (!NT_SUCCESS(Status
))
534 SetLastNtError(Status
);
540 TRACE("Leave NtUserGetCursorInfo, ret=%i\n",_ret_
);
550 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
551 PSYSTEM_CURSORINFO CurInfo
;
552 PWND DesktopWindow
= NULL
;
554 CurInfo
= IntGetSysCursorInfo();
556 DesktopWindow
= UserGetDesktopWindow();
558 if (prcl
!= NULL
&& DesktopWindow
!= NULL
)
560 if (prcl
->right
< prcl
->left
|| prcl
->bottom
< prcl
->top
)
562 EngSetLastError(ERROR_INVALID_PARAMETER
);
566 CurInfo
->bClipped
= TRUE
;
568 /* Set nw cliping region. Note: we can't use RECTL_bIntersectRect because
569 it sets rect to 0 0 0 0 when it's empty. For more info see monitor winetest */
570 CurInfo
->rcClip
.left
= max(prcl
->left
, DesktopWindow
->rcWindow
.left
);
571 CurInfo
->rcClip
.right
= min(prcl
->right
, DesktopWindow
->rcWindow
.right
);
572 if (CurInfo
->rcClip
.right
< CurInfo
->rcClip
.left
)
573 CurInfo
->rcClip
.right
= CurInfo
->rcClip
.left
;
575 CurInfo
->rcClip
.top
= max(prcl
->top
, DesktopWindow
->rcWindow
.top
);
576 CurInfo
->rcClip
.bottom
= min(prcl
->bottom
, DesktopWindow
->rcWindow
.bottom
);
577 if (CurInfo
->rcClip
.bottom
< CurInfo
->rcClip
.top
)
578 CurInfo
->rcClip
.bottom
= CurInfo
->rcClip
.top
;
580 /* Make sure cursor is in clipping region */
581 UserSetCursorPos(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
, 0, 0, FALSE
);
585 CurInfo
->bClipped
= FALSE
;
606 /* Probe and copy rect */
607 ProbeForRead(prcl
, sizeof(RECTL
), 1);
610 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
612 EngSetLastError(ERROR_INVALID_PARAMETER
);
613 _SEH2_YIELD(return FALSE
;)
620 UserEnterExclusive();
622 /* Call the internal function */
623 bResult
= UserClipCursor(prcl
);
640 PCURICON_OBJECT CurIcon
;
642 DECLARE_RETURN(BOOL
);
644 TRACE("Enter NtUserDestroyCursorIcon\n");
645 UserEnterExclusive();
647 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
652 ret
= IntDestroyCurIconObject(CurIcon
, FALSE
);
653 /* Note: IntDestroyCurIconObject will remove our reference for us! */
658 TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_
);
669 NtUserFindExistingCursorIcon(
675 PCURICON_OBJECT CurIcon
;
676 HANDLE Ret
= (HANDLE
)0;
677 DECLARE_RETURN(HICON
);
679 TRACE("Enter NtUserFindExistingCursorIcon\n");
680 UserEnterExclusive();
682 CurIcon
= IntFindExistingCurIconObject(hModule
, hRsrc
, cx
, cy
);
687 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
691 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
695 TRACE("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_
);
709 /* FIXME - check if process has WINSTA_READATTRIBUTES */
710 PSYSTEM_CURSORINFO CurInfo
;
713 DECLARE_RETURN(BOOL
);
715 TRACE("Enter NtUserGetClipCursor\n");
716 UserEnterExclusive();
721 CurInfo
= IntGetSysCursorInfo();
722 if (CurInfo
->bClipped
)
724 Rect
= CurInfo
->rcClip
;
730 Rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
731 Rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
734 Status
= MmCopyToCaller(lpRect
, &Rect
, sizeof(RECT
));
735 if (!NT_SUCCESS(Status
))
737 SetLastNtError(Status
);
744 TRACE("Leave NtUserGetClipCursor, ret=%i\n",_ret_
);
758 PCURICON_OBJECT pcurOld
, pcurNew
;
759 HCURSOR hOldCursor
= NULL
;
761 TRACE("Enter NtUserSetCursor\n");
762 UserEnterExclusive();
766 pcurNew
= UserGetCurIconObject(hCursor
);
769 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
778 pcurOld
= UserSetCursor(pcurNew
, FALSE
);
781 hOldCursor
= (HCURSOR
)pcurOld
->Self
;
782 UserDereferenceObject(pcurOld
);
796 NtUserSetCursorContents(
798 PICONINFO UnsafeIconInfo
)
800 PCURICON_OBJECT CurIcon
;
805 DECLARE_RETURN(BOOL
);
807 TRACE("Enter NtUserSetCursorContents\n");
808 UserEnterExclusive();
810 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
816 Status
= MmCopyFromCaller(&IconInfo
, UnsafeIconInfo
, sizeof(ICONINFO
));
817 if (!NT_SUCCESS(Status
))
819 SetLastNtError(Status
);
823 /* Delete old bitmaps */
824 if ((CurIcon
->IconInfo
.hbmColor
)
825 && (CurIcon
->IconInfo
.hbmColor
!= IconInfo
.hbmColor
))
827 GreDeleteObject(CurIcon
->IconInfo
.hbmColor
);
829 if ((CurIcon
->IconInfo
.hbmMask
)
830 && CurIcon
->IconInfo
.hbmMask
!= IconInfo
.hbmMask
)
832 GreDeleteObject(CurIcon
->IconInfo
.hbmMask
);
835 /* Copy new IconInfo field */
836 CurIcon
->IconInfo
= IconInfo
;
838 if (CurIcon
->IconInfo
.hbmColor
)
840 psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->IconInfo
.hbmColor
);
844 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
845 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
846 SURFACE_ShareUnlockSurface(psurfBmp
);
847 GreSetObjectOwner(CurIcon
->IconInfo
.hbmColor
, GDI_OBJ_HMGR_PUBLIC
);
851 psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->IconInfo
.hbmMask
);
855 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
856 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
/ 2;
858 SURFACE_ShareUnlockSurface(psurfBmp
);
860 GreSetObjectOwner(CurIcon
->IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
868 UserDereferenceObject(CurIcon
);
873 TRACE("Leave NtUserSetCursorContents, ret=%i\n",_ret_
);
885 NtUserSetCursorIconData(
888 PUNICODE_STRING pstrResName
,
891 PCURICON_OBJECT CurIcon
;
893 NTSTATUS Status
= STATUS_SUCCESS
;
895 DECLARE_RETURN(BOOL
);
897 TRACE("Enter NtUserSetCursorIconData\n");
898 UserEnterExclusive();
900 if (!(CurIcon
= UserGetCurIconObject(Handle
)))
905 CurIcon
->hModule
= hModule
;
906 CurIcon
->hRsrc
= NULL
; //hRsrc;
907 CurIcon
->hGroupRsrc
= NULL
; //hGroupRsrc;
911 ProbeForRead(pIconInfo
, sizeof(ICONINFO
), 1);
912 RtlCopyMemory(&CurIcon
->IconInfo
, pIconInfo
, sizeof(ICONINFO
));
914 CurIcon
->IconInfo
.hbmMask
= BITMAP_CopyBitmap(pIconInfo
->hbmMask
);
915 CurIcon
->IconInfo
.hbmColor
= BITMAP_CopyBitmap(pIconInfo
->hbmColor
);
917 if (CurIcon
->IconInfo
.hbmColor
)
919 if ((psurfBmp
= SURFACE_LockSurface(CurIcon
->IconInfo
.hbmColor
)))
921 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
922 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
923 SURFACE_UnlockSurface(psurfBmp
);
924 GreSetObjectOwner(CurIcon
->IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
927 if (CurIcon
->IconInfo
.hbmMask
)
929 if (CurIcon
->IconInfo
.hbmColor
== NULL
)
931 if ((psurfBmp
= SURFACE_LockSurface(CurIcon
->IconInfo
.hbmMask
)))
933 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
934 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
935 SURFACE_UnlockSurface(psurfBmp
);
938 GreSetObjectOwner(CurIcon
->IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
941 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
943 Status
= _SEH2_GetExceptionCode();
947 if (!NT_SUCCESS(Status
))
948 SetLastNtError(Status
);
952 UserDereferenceObject(CurIcon
);
956 TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_
);
963 NtUserSetCursorIconData(
971 PCURICON_OBJECT CurIcon
;
975 DECLARE_RETURN(BOOL
);
977 TRACE("Enter NtUserSetCursorIconData\n");
978 UserEnterExclusive();
980 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
985 CurIcon
->hModule
= hModule
;
986 CurIcon
->hRsrc
= hRsrc
;
987 CurIcon
->hGroupRsrc
= hGroupRsrc
;
992 Status
= MmCopyFromCaller(&CurIcon
->IconInfo
.fIcon
, fIcon
, sizeof(BOOL
));
993 if (!NT_SUCCESS(Status
))
995 SetLastNtError(Status
);
1007 Status
= MmCopyFromCaller(&SafeHotspot
, Hotspot
, sizeof(POINT
));
1008 if (NT_SUCCESS(Status
))
1010 CurIcon
->IconInfo
.xHotspot
= SafeHotspot
.x
;
1011 CurIcon
->IconInfo
.yHotspot
= SafeHotspot
.y
;
1016 SetLastNtError(Status
);
1019 if (!fIcon
&& !Hotspot
)
1027 /* This icon is shared now */
1028 GreSetObjectOwner(CurIcon
->IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
1029 if(CurIcon
->IconInfo
.hbmColor
)
1031 GreSetObjectOwner(CurIcon
->IconInfo
.hbmColor
, GDI_OBJ_HMGR_PUBLIC
);
1034 UserDereferenceObject(CurIcon
);
1039 TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_
);
1045 /* Mostly inspired from wine code */
1051 PCURICON_OBJECT pIcon
,
1055 HBRUSH hbrFlickerFreeDraw
,
1059 HBITMAP hbmMask
, hbmColor
;
1060 BITMAP bmpColor
, bm
;
1062 INT iOldBkColor
= 0, iOldTxtColor
= 0;
1064 HDC hMemDC
, hDestDC
= hDc
;
1065 HGDIOBJ hOldOffBrush
= 0;
1066 HGDIOBJ hOldOffBmp
= 0;
1067 HBITMAP hTmpBmp
= 0, hOffBmp
= 0;
1068 BOOL bAlpha
= FALSE
;
1069 INT x
=xLeft
, y
=yTop
;
1071 hbmMask
= pIcon
->IconInfo
.hbmMask
;
1072 hbmColor
= pIcon
->IconInfo
.hbmColor
;
1075 ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1077 if (!hbmMask
|| !GreGetObject(hbmMask
, sizeof(BITMAP
), (PVOID
)&bm
))
1082 if (hbmColor
&& !GreGetObject(hbmColor
, sizeof(BITMAP
), (PVOID
)&bmpColor
))
1087 if(!(hMemDC
= NtGdiCreateCompatibleDC(hDc
)))
1089 ERR("NtGdiCreateCompatibleDC failed!\n");
1093 /* Check for alpha */
1095 && (bmpColor
.bmBitsPixel
== 32)
1096 && (diFlags
& DI_IMAGE
))
1098 SURFACE
*psurfOff
= NULL
;
1099 PFN_DIB_GetPixel fnSource_GetPixel
= NULL
;
1102 /* In order to correctly display 32 bit icons Windows first scans the image,
1103 because information about transparency is not stored in any image's headers */
1104 psurfOff
= SURFACE_ShareLockSurface(hbmColor
);
1107 fnSource_GetPixel
= DibFunctionsForBitmapFormat
[psurfOff
->SurfObj
.iBitmapFormat
].DIB_GetPixel
;
1108 if (fnSource_GetPixel
)
1110 for (i
= 0; i
< psurfOff
->SurfObj
.sizlBitmap
.cx
; i
++)
1112 for (j
= 0; j
< psurfOff
->SurfObj
.sizlBitmap
.cy
; j
++)
1114 bAlpha
= ((BYTE
)(fnSource_GetPixel(&psurfOff
->SurfObj
, i
, j
) >> 24) & 0xff);
1122 SURFACE_ShareUnlockSurface(psurfOff
);
1127 cxWidth
= ((diFlags
& DI_DEFAULTSIZE
) ?
1128 UserGetSystemMetrics(SM_CXICON
) : pIcon
->Size
.cx
);
1131 cyHeight
= ((diFlags
& DI_DEFAULTSIZE
) ?
1132 UserGetSystemMetrics(SM_CYICON
) : pIcon
->Size
.cy
);
1134 DoFlickerFree
= (hbrFlickerFreeDraw
&&
1135 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw
) == GDI_OBJECT_TYPE_BRUSH
));
1139 hDestDC
= NtGdiCreateCompatibleDC(hDc
);
1142 ERR("NtGdiCreateCompatibleDC failed!\n");
1146 hOffBmp
= NtGdiCreateCompatibleBitmap(hDc
, cxWidth
, cyHeight
);
1149 ERR("NtGdiCreateCompatibleBitmap failed!\n");
1152 hOldOffBmp
= NtGdiSelectBitmap(hDestDC
, hOffBmp
);
1153 hOldOffBrush
= NtGdiSelectBrush(hDestDC
, hbrFlickerFreeDraw
);
1154 NtGdiPatBlt(hDestDC
, 0, 0, cxWidth
, cyHeight
, PATCOPY
);
1155 NtGdiSelectBrush(hDestDC
, hOldOffBrush
);
1159 /* Set Background/foreground colors */
1160 iOldTxtColor
= IntGdiSetTextColor(hDc
, 0); //black
1161 iOldBkColor
= IntGdiSetBkColor(hDc
, 0x00FFFFFF); //white
1163 if(bAlpha
&& (diFlags
& DI_IMAGE
))
1165 BLENDFUNCTION pixelblend
= { AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
1170 HBITMAP hMemBmp
= NULL
;
1172 hMemBmp
= BITMAP_CopyBitmap(hbmColor
);
1175 ERR("BITMAP_CopyBitmap failed!");
1179 psurf
= SURFACE_ShareLockSurface(hMemBmp
);
1182 ERR("SURFACE_LockSurface failed!\n");
1186 /* premultiply with the alpha channel value */
1187 for (i
= 0; i
< psurf
->SurfObj
.sizlBitmap
.cy
; i
++)
1189 ptr
= (PBYTE
)psurf
->SurfObj
.pvScan0
+ i
*psurf
->SurfObj
.lDelta
;
1190 for (j
= 0; j
< psurf
->SurfObj
.sizlBitmap
.cx
; j
++)
1193 ptr
[0] = (ptr
[0] * Alpha
) / 0xff;
1194 ptr
[1] = (ptr
[1] * Alpha
) / 0xff;
1195 ptr
[2] = (ptr
[2] * Alpha
) / 0xff;
1201 SURFACE_ShareUnlockSurface(psurf
);
1203 hTmpBmp
= NtGdiSelectBitmap(hMemDC
, hMemBmp
);
1205 Ret
= NtGdiAlphaBlend(hDestDC
,
1217 NtGdiSelectBitmap(hMemDC
, hTmpBmp
);
1219 if(hMemBmp
) NtGdiDeleteObjectApp(hMemBmp
);
1223 if (diFlags
& DI_MASK
)
1225 hTmpBmp
= NtGdiSelectBitmap(hMemDC
, hbmMask
);
1226 NtGdiStretchBlt(hDestDC
,
1238 NtGdiSelectBitmap(hMemDC
, hTmpBmp
);
1241 if(diFlags
& DI_IMAGE
)
1245 DWORD rop
= (diFlags
& DI_MASK
) ? SRCINVERT
: SRCCOPY
;
1246 hTmpBmp
= NtGdiSelectBitmap(hMemDC
, hbmColor
);
1247 NtGdiStretchBlt(hDestDC
,
1259 NtGdiSelectBitmap(hMemDC
, hTmpBmp
);
1263 /* Mask bitmap holds the information in its second half */
1264 DWORD rop
= (diFlags
& DI_MASK
) ? SRCINVERT
: SRCCOPY
;
1265 hTmpBmp
= NtGdiSelectBitmap(hMemDC
, hbmMask
);
1266 NtGdiStretchBlt(hDestDC
,
1278 NtGdiSelectBitmap(hMemDC
, hTmpBmp
);
1285 NtGdiBitBlt(hDc
, xLeft
, yTop
, cxWidth
, cyHeight
, hDestDC
, 0, 0, SRCCOPY
, 0, 0);
1288 /* Restore foreground and background colors */
1289 IntGdiSetBkColor(hDc
, iOldBkColor
);
1290 IntGdiSetTextColor(hDc
, iOldTxtColor
);
1295 NtGdiDeleteObjectApp(hMemDC
);
1298 if(hOldOffBmp
) NtGdiSelectBitmap(hDestDC
, hOldOffBmp
);
1299 NtGdiDeleteObjectApp(hDestDC
);
1300 if(hOffBmp
) NtGdiDeleteObjectApp(hOffBmp
);
1319 HBRUSH hbrFlickerFreeDraw
,
1321 BOOL bMetaHDC
, // When TRUE, GDI functions need to be handled in User32!
1324 PCURICON_OBJECT pIcon
;
1327 TRACE("Enter NtUserDrawIconEx\n");
1328 UserEnterExclusive();
1330 if (!(pIcon
= UserGetCurIconObject(hIcon
)))
1332 ERR("UserGetCurIconObject() failed!\n");
1337 Ret
= UserDrawIconEx(hdc
,
1347 UserDereferenceObject(pIcon
);