2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * We handle two types of cursors/icons:
23 * Loaded without LR_SHARED flag
24 * Private to a process
25 * Can be deleted by calling NtDestroyCursorIcon()
26 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
28 * Loaded with LR_SHARED flag
29 * Possibly shared by multiple processes
30 * Immune to NtDestroyCursorIcon()
31 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
32 * There's a M:N relationship between processes and (shared) cursor/icons.
33 * A process can have multiple cursor/icons and a cursor/icon can be used
34 * by multiple processes. To keep track of this we keep a list of all
35 * cursor/icons (CurIconList) and per cursor/icon we keep a list of
36 * CURICON_PROCESS structs starting at CurIcon->ProcessList.
41 DBG_DEFAULT_CHANNEL(UserIcon
);
43 static PAGED_LOOKASIDE_LIST gProcessLookasideList
;
44 static LIST_ENTRY gCurIconList
;
46 SYSTEM_CURSORINFO gSysCursorInfo
;
51 ExInitializePagedLookasideList(&gProcessLookasideList
,
55 sizeof(CURICON_PROCESS
),
58 InitializeListHead(&gCurIconList
);
60 gSysCursorInfo
.Enabled
= FALSE
;
61 gSysCursorInfo
.ButtonsDown
= 0;
62 gSysCursorInfo
.bClipped
= FALSE
;
63 gSysCursorInfo
.LastBtnDown
= 0;
64 gSysCursorInfo
.CurrentCursorObject
= NULL
;
65 gSysCursorInfo
.ShowingCursor
= -1;
66 gSysCursorInfo
.ClickLockActive
= FALSE
;
67 gSysCursorInfo
.ClickLockTime
= 0;
75 return &gSysCursorInfo
;
78 /* This function creates a reference for the object! */
79 PCURICON_OBJECT FASTCALL
UserGetCurIconObject(HCURSOR hCurIcon
)
81 PCURICON_OBJECT CurIcon
;
85 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
89 CurIcon
= (PCURICON_OBJECT
)UserReferenceObjectByHandle(hCurIcon
, otCursorIcon
);
92 /* we never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
93 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
97 ASSERT(CurIcon
->head
.cLockObj
>= 1);
101 BOOL
UserSetCursorPos( INT x
, INT y
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
104 PSYSTEM_CURSORINFO CurInfo
;
109 if(!(DesktopWindow
= UserGetDesktopWindow()))
114 CurInfo
= IntGetSysCursorInfo();
116 /* Clip cursor position */
117 if (!CurInfo
->bClipped
)
118 rcClip
= DesktopWindow
->rcClient
;
120 rcClip
= CurInfo
->rcClip
;
122 if(x
>= rcClip
.right
) x
= rcClip
.right
- 1;
123 if(x
< rcClip
.left
) x
= rcClip
.left
;
124 if(y
>= rcClip
.bottom
) y
= rcClip
.bottom
- 1;
125 if(y
< rcClip
.top
) y
= rcClip
.top
;
130 /* 1. Generate a mouse move message, this sets the htEx and Track Window too. */
131 Msg
.message
= WM_MOUSEMOVE
;
132 Msg
.wParam
= CurInfo
->ButtonsDown
;
133 Msg
.lParam
= MAKELPARAM(x
, y
);
135 co_MsqInsertMouseMessage(&Msg
, flags
, dwExtraInfo
, Hook
);
137 /* 2. Store the new cursor position */
144 * We have to register that this object is in use by the current
145 * process. The only way to do that seems to be to walk the list
146 * of cursor/icon objects starting at W32Process->CursorIconListHead.
147 * If the object is already present in the list, we don't have to do
148 * anything, if it's not present we add it and inc the ProcessCount
149 * in the object. Having to walk the list kind of sucks, but that's
152 static BOOLEAN FASTCALL
153 ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon
)
155 PPROCESSINFO Win32Process
;
156 PCURICON_PROCESS Current
;
158 Win32Process
= PsGetCurrentProcessWin32Process();
160 LIST_FOR_EACH(Current
, &CurIcon
->ProcessList
, CURICON_PROCESS
, ListEntry
)
162 if (Current
->Process
== Win32Process
)
164 /* Already registered for this process */
169 /* Not registered yet */
170 Current
= ExAllocateFromPagedLookasideList(&gProcessLookasideList
);
175 InsertHeadList(&CurIcon
->ProcessList
, &Current
->ListEntry
);
176 Current
->Process
= Win32Process
;
181 PCURICON_OBJECT FASTCALL
182 IntFindExistingCurIconObject(HMODULE hModule
,
183 HRSRC hRsrc
, LONG cx
, LONG cy
)
185 PCURICON_OBJECT CurIcon
;
187 LIST_FOR_EACH(CurIcon
, &gCurIconList
, CURICON_OBJECT
, ListEntry
)
190 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
191 // UserReferenceObject( CurIcon);
193 if ((CurIcon
->hModule
== hModule
) && (CurIcon
->hRsrc
== hRsrc
))
195 if (cx
&& ((cx
!= CurIcon
->Size
.cx
) || (cy
!= CurIcon
->Size
.cy
)))
197 // UserDereferenceObject(CurIcon);
200 if (! ReferenceCurIconByProcess(CurIcon
))
208 // UserDereferenceObject(CurIcon);
216 IntCreateCurIconHandle()
218 PCURICON_OBJECT CurIcon
;
221 CurIcon
= UserCreateObject(gHandleTable
, NULL
, &hCurIcon
, otCursorIcon
, sizeof(CURICON_OBJECT
));
225 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
229 CurIcon
->Self
= hCurIcon
;
230 InitializeListHead(&CurIcon
->ProcessList
);
232 if (! ReferenceCurIconByProcess(CurIcon
))
234 ERR("Failed to add process\n");
235 UserDeleteObject(hCurIcon
, otCursorIcon
);
236 UserDereferenceObject(CurIcon
);
240 InsertHeadList(&gCurIconList
, &CurIcon
->ListEntry
);
246 IntDestroyCurIconObject(PCURICON_OBJECT CurIcon
, BOOL ProcessCleanup
)
248 PSYSTEM_CURSORINFO CurInfo
;
249 HBITMAP bmpMask
, bmpColor
;
251 PCURICON_PROCESS Current
= NULL
;
252 PPROCESSINFO W32Process
= PsGetCurrentProcessWin32Process();
254 /* Private objects can only be destroyed by their own process */
255 if (NULL
== CurIcon
->hModule
)
257 ASSERT(CurIcon
->ProcessList
.Flink
->Flink
== &CurIcon
->ProcessList
);
258 Current
= CONTAINING_RECORD(CurIcon
->ProcessList
.Flink
, CURICON_PROCESS
, ListEntry
);
259 if (Current
->Process
!= W32Process
)
261 ERR("Trying to destroy private icon/cursor of another process\n");
265 else if (! ProcessCleanup
)
267 TRACE("Trying to destroy shared icon/cursor\n");
271 /* Now find this process in the list of processes referencing this object and
272 remove it from that list */
273 LIST_FOR_EACH(Current
, &CurIcon
->ProcessList
, CURICON_PROCESS
, ListEntry
)
275 if (Current
->Process
== W32Process
)
277 RemoveEntryList(&Current
->ListEntry
);
282 ExFreeToPagedLookasideList(&gProcessLookasideList
, Current
);
284 /* If there are still processes referencing this object we can't destroy it yet */
285 if (! IsListEmpty(&CurIcon
->ProcessList
))
291 if (! ProcessCleanup
)
293 RemoveEntryList(&CurIcon
->ListEntry
);
296 CurInfo
= IntGetSysCursorInfo();
298 if (CurInfo
->CurrentCursorObject
== CurIcon
)
300 /* Hide the cursor if we're destroying the current cursor */
301 UserSetCursor(NULL
, TRUE
);
304 bmpMask
= CurIcon
->IconInfo
.hbmMask
;
305 bmpColor
= CurIcon
->IconInfo
.hbmColor
;
310 GreSetObjectOwner(bmpMask
, GDI_OBJ_HMGR_POWNED
);
311 GreDeleteObject(bmpMask
);
312 CurIcon
->IconInfo
.hbmMask
= NULL
;
316 GreSetObjectOwner(bmpColor
, GDI_OBJ_HMGR_POWNED
);
317 GreDeleteObject(bmpColor
);
318 CurIcon
->IconInfo
.hbmColor
= NULL
;
321 /* We were given a pointer, no need to keep the reference anylonger! */
322 UserDereferenceObject(CurIcon
);
323 Ret
= UserDeleteObject(CurIcon
->Self
, otCursorIcon
);
329 IntCleanupCurIcons(struct _EPROCESS
*Process
, PPROCESSINFO Win32Process
)
331 PCURICON_OBJECT CurIcon
, tmp
;
332 PCURICON_PROCESS ProcessData
;
334 LIST_FOR_EACH_SAFE(CurIcon
, tmp
, &gCurIconList
, CURICON_OBJECT
, ListEntry
)
336 UserReferenceObject(CurIcon
);
337 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon)))
339 LIST_FOR_EACH(ProcessData
, &CurIcon
->ProcessList
, CURICON_PROCESS
, ListEntry
)
341 if (Win32Process
== ProcessData
->Process
)
343 RemoveEntryList(&CurIcon
->ListEntry
);
344 IntDestroyCurIconObject(CurIcon
, TRUE
);
350 // UserDereferenceObject(Object);
355 UserDereferenceObject(CurIcon
);
370 PUNICODE_STRING lpInstName
, // optional
371 PUNICODE_STRING lpResName
, // optional
372 LPDWORD pbpp
, // optional
376 PCURICON_OBJECT CurIcon
;
377 NTSTATUS Status
= STATUS_SUCCESS
;
381 TRACE("Enter NtUserGetIconInfo\n");
382 UserEnterExclusive();
386 EngSetLastError(ERROR_INVALID_PARAMETER
);
390 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
395 RtlCopyMemory(&ii
, &CurIcon
->IconInfo
, sizeof(ICONINFO
));
398 ii
.hbmMask
= BITMAP_CopyBitmap(CurIcon
->IconInfo
.hbmMask
);
399 ii
.hbmColor
= BITMAP_CopyBitmap(CurIcon
->IconInfo
.hbmColor
);
405 psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->IconInfo
.hbmColor
);
408 colorBpp
= BitsPerFormat(psurfBmp
->SurfObj
.iBitmapFormat
);
409 SURFACE_ShareUnlockSurface(psurfBmp
);
416 ProbeForWrite(IconInfo
, sizeof(ICONINFO
), 1);
417 RtlCopyMemory(IconInfo
, &ii
, sizeof(ICONINFO
));
421 ProbeForWrite(pbpp
, sizeof(DWORD
), 1);
425 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
427 Status
= _SEH2_GetExceptionCode();
431 if (NT_SUCCESS(Status
))
434 SetLastNtError(Status
);
436 UserDereferenceObject(CurIcon
);
439 TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret
);
454 PLONG plcx
, // &size.cx
455 PLONG plcy
) // &size.cy
457 PCURICON_OBJECT CurIcon
;
458 NTSTATUS Status
= STATUS_SUCCESS
;
461 TRACE("Enter NtUserGetIconSize\n");
462 UserEnterExclusive();
464 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
471 ProbeForWrite(plcx
, sizeof(LONG
), 1);
472 RtlCopyMemory(plcx
, &CurIcon
->Size
.cx
, sizeof(LONG
));
473 ProbeForWrite(plcy
, sizeof(LONG
), 1);
474 RtlCopyMemory(plcy
, &CurIcon
->Size
.cy
, sizeof(LONG
));
476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
478 Status
= _SEH2_GetExceptionCode();
482 if (NT_SUCCESS(Status
))
485 SetLastNtError(Status
); // maybe not, test this
487 UserDereferenceObject(CurIcon
);
490 TRACE("Leave NtUserGetIconSize, ret=%i\n", bRet
);
505 PSYSTEM_CURSORINFO CurInfo
;
506 NTSTATUS Status
= STATUS_SUCCESS
;
507 PCURICON_OBJECT CurIcon
;
509 DECLARE_RETURN(BOOL
);
511 TRACE("Enter NtUserGetCursorInfo\n");
512 UserEnterExclusive();
514 CurInfo
= IntGetSysCursorInfo();
515 CurIcon
= (PCURICON_OBJECT
)CurInfo
->CurrentCursorObject
;
517 SafeCi
.cbSize
= sizeof(CURSORINFO
);
518 SafeCi
.flags
= ((CurIcon
&& CurInfo
->ShowingCursor
>= 0) ? CURSOR_SHOWING
: 0);
519 SafeCi
.hCursor
= (CurIcon
? (HCURSOR
)CurIcon
->Self
: (HCURSOR
)0);
521 SafeCi
.ptScreenPos
= gpsi
->ptCursor
;
525 if (pci
->cbSize
== sizeof(CURSORINFO
))
527 ProbeForWrite(pci
, sizeof(CURSORINFO
), 1);
528 RtlCopyMemory(pci
, &SafeCi
, sizeof(CURSORINFO
));
533 EngSetLastError(ERROR_INVALID_PARAMETER
);
536 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
538 Status
= _SEH2_GetExceptionCode();
541 if (!NT_SUCCESS(Status
))
543 SetLastNtError(Status
);
549 TRACE("Leave NtUserGetCursorInfo, ret=%i\n",_ret_
);
559 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
560 PSYSTEM_CURSORINFO CurInfo
;
561 PWND DesktopWindow
= NULL
;
563 CurInfo
= IntGetSysCursorInfo();
565 DesktopWindow
= UserGetDesktopWindow();
567 if (prcl
!= NULL
&& DesktopWindow
!= NULL
)
569 if (prcl
->right
< prcl
->left
|| prcl
->bottom
< prcl
->top
)
571 EngSetLastError(ERROR_INVALID_PARAMETER
);
575 CurInfo
->bClipped
= TRUE
;
577 /* Set nw cliping region. Note: we can't use RECTL_bIntersectRect because
578 it sets rect to 0 0 0 0 when it's empty. For more info see monitor winetest */
579 CurInfo
->rcClip
.left
= max(prcl
->left
, DesktopWindow
->rcWindow
.left
);
580 CurInfo
->rcClip
.right
= min(prcl
->right
, DesktopWindow
->rcWindow
.right
);
581 if (CurInfo
->rcClip
.right
< CurInfo
->rcClip
.left
)
582 CurInfo
->rcClip
.right
= CurInfo
->rcClip
.left
;
584 CurInfo
->rcClip
.top
= max(prcl
->top
, DesktopWindow
->rcWindow
.top
);
585 CurInfo
->rcClip
.bottom
= min(prcl
->bottom
, DesktopWindow
->rcWindow
.bottom
);
586 if (CurInfo
->rcClip
.bottom
< CurInfo
->rcClip
.top
)
587 CurInfo
->rcClip
.bottom
= CurInfo
->rcClip
.top
;
589 /* Make sure cursor is in clipping region */
590 UserSetCursorPos(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
, 0, 0, FALSE
);
594 CurInfo
->bClipped
= FALSE
;
615 /* Probe and copy rect */
616 ProbeForRead(prcl
, sizeof(RECTL
), 1);
619 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
621 EngSetLastError(ERROR_INVALID_PARAMETER
);
622 _SEH2_YIELD(return FALSE
;)
629 UserEnterExclusive();
631 /* Call the internal function */
632 bResult
= UserClipCursor(prcl
);
649 PCURICON_OBJECT CurIcon
;
651 DECLARE_RETURN(BOOL
);
653 TRACE("Enter NtUserDestroyCursorIcon\n");
654 UserEnterExclusive();
656 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
661 ret
= IntDestroyCurIconObject(CurIcon
, FALSE
);
662 /* Note: IntDestroyCurIconObject will remove our reference for us! */
667 TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_
);
678 NtUserFindExistingCursorIcon(
684 PCURICON_OBJECT CurIcon
;
685 HANDLE Ret
= (HANDLE
)0;
686 DECLARE_RETURN(HICON
);
688 TRACE("Enter NtUserFindExistingCursorIcon\n");
689 UserEnterExclusive();
691 CurIcon
= IntFindExistingCurIconObject(hModule
, hRsrc
, cx
, cy
);
696 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
700 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
704 TRACE("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_
);
718 /* FIXME - check if process has WINSTA_READATTRIBUTES */
719 PSYSTEM_CURSORINFO CurInfo
;
722 DECLARE_RETURN(BOOL
);
724 TRACE("Enter NtUserGetClipCursor\n");
725 UserEnterExclusive();
730 CurInfo
= IntGetSysCursorInfo();
731 if (CurInfo
->bClipped
)
733 Rect
= CurInfo
->rcClip
;
739 Rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
740 Rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
743 Status
= MmCopyToCaller(lpRect
, &Rect
, sizeof(RECT
));
744 if (!NT_SUCCESS(Status
))
746 SetLastNtError(Status
);
753 TRACE("Leave NtUserGetClipCursor, ret=%i\n",_ret_
);
767 PCURICON_OBJECT pcurOld
, pcurNew
;
768 HCURSOR hOldCursor
= NULL
;
770 TRACE("Enter NtUserSetCursor\n");
771 UserEnterExclusive();
775 pcurNew
= UserGetCurIconObject(hCursor
);
778 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
787 pcurOld
= UserSetCursor(pcurNew
, FALSE
);
790 hOldCursor
= (HCURSOR
)pcurOld
->Self
;
791 UserDereferenceObject(pcurOld
);
805 NtUserSetCursorContents(
807 PICONINFO UnsafeIconInfo
)
809 PCURICON_OBJECT CurIcon
;
814 DECLARE_RETURN(BOOL
);
816 TRACE("Enter NtUserSetCursorContents\n");
817 UserEnterExclusive();
819 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
825 Status
= MmCopyFromCaller(&IconInfo
, UnsafeIconInfo
, sizeof(ICONINFO
));
826 if (!NT_SUCCESS(Status
))
828 SetLastNtError(Status
);
832 /* Delete old bitmaps */
833 if ((CurIcon
->IconInfo
.hbmColor
)
834 && (CurIcon
->IconInfo
.hbmColor
!= IconInfo
.hbmColor
))
836 GreDeleteObject(CurIcon
->IconInfo
.hbmColor
);
838 if ((CurIcon
->IconInfo
.hbmMask
)
839 && CurIcon
->IconInfo
.hbmMask
!= IconInfo
.hbmMask
)
841 GreDeleteObject(CurIcon
->IconInfo
.hbmMask
);
844 /* Copy new IconInfo field */
845 CurIcon
->IconInfo
= IconInfo
;
847 if (CurIcon
->IconInfo
.hbmColor
)
849 psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->IconInfo
.hbmColor
);
853 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
854 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
855 SURFACE_ShareUnlockSurface(psurfBmp
);
856 GreSetObjectOwner(CurIcon
->IconInfo
.hbmColor
, GDI_OBJ_HMGR_PUBLIC
);
860 psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->IconInfo
.hbmMask
);
864 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
865 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
/ 2;
867 SURFACE_ShareUnlockSurface(psurfBmp
);
869 GreSetObjectOwner(CurIcon
->IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
877 UserDereferenceObject(CurIcon
);
882 TRACE("Leave NtUserSetCursorContents, ret=%i\n",_ret_
);
894 NtUserSetCursorIconData(
897 PUNICODE_STRING pstrResName
,
900 PCURICON_OBJECT CurIcon
;
902 NTSTATUS Status
= STATUS_SUCCESS
;
904 DECLARE_RETURN(BOOL
);
906 TRACE("Enter NtUserSetCursorIconData\n");
907 UserEnterExclusive();
909 if (!(CurIcon
= UserGetCurIconObject(Handle
)))
914 CurIcon
->hModule
= hModule
;
915 CurIcon
->hRsrc
= NULL
; //hRsrc;
916 CurIcon
->hGroupRsrc
= NULL
; //hGroupRsrc;
920 ProbeForRead(pIconInfo
, sizeof(ICONINFO
), 1);
921 RtlCopyMemory(&CurIcon
->IconInfo
, pIconInfo
, sizeof(ICONINFO
));
923 CurIcon
->IconInfo
.hbmMask
= BITMAP_CopyBitmap(pIconInfo
->hbmMask
);
924 CurIcon
->IconInfo
.hbmColor
= BITMAP_CopyBitmap(pIconInfo
->hbmColor
);
926 if (CurIcon
->IconInfo
.hbmColor
)
928 if ((psurfBmp
= SURFACE_LockSurface(CurIcon
->IconInfo
.hbmColor
)))
930 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
931 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
932 SURFACE_UnlockSurface(psurfBmp
);
933 GreSetObjectOwner(CurIcon
->IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
936 if (CurIcon
->IconInfo
.hbmMask
)
938 if (CurIcon
->IconInfo
.hbmColor
== NULL
)
940 if ((psurfBmp
= SURFACE_LockSurface(CurIcon
->IconInfo
.hbmMask
)))
942 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
943 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
944 SURFACE_UnlockSurface(psurfBmp
);
947 GreSetObjectOwner(CurIcon
->IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
950 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
952 Status
= _SEH2_GetExceptionCode();
956 if (!NT_SUCCESS(Status
))
957 SetLastNtError(Status
);
961 UserDereferenceObject(CurIcon
);
965 TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_
);
972 NtUserSetCursorIconData(
980 PCURICON_OBJECT CurIcon
;
984 DECLARE_RETURN(BOOL
);
986 TRACE("Enter NtUserSetCursorIconData\n");
987 UserEnterExclusive();
989 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
994 CurIcon
->hModule
= hModule
;
995 CurIcon
->hRsrc
= hRsrc
;
996 CurIcon
->hGroupRsrc
= hGroupRsrc
;
1001 Status
= MmCopyFromCaller(&CurIcon
->IconInfo
.fIcon
, fIcon
, sizeof(BOOL
));
1002 if (!NT_SUCCESS(Status
))
1004 SetLastNtError(Status
);
1016 Status
= MmCopyFromCaller(&SafeHotspot
, Hotspot
, sizeof(POINT
));
1017 if (NT_SUCCESS(Status
))
1019 CurIcon
->IconInfo
.xHotspot
= SafeHotspot
.x
;
1020 CurIcon
->IconInfo
.yHotspot
= SafeHotspot
.y
;
1025 SetLastNtError(Status
);
1028 if (!fIcon
&& !Hotspot
)
1036 /* This icon is shared now */
1037 GreSetObjectOwner(CurIcon
->IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
1038 if(CurIcon
->IconInfo
.hbmColor
)
1040 GreSetObjectOwner(CurIcon
->IconInfo
.hbmColor
, GDI_OBJ_HMGR_PUBLIC
);
1043 UserDereferenceObject(CurIcon
);
1048 TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_
);
1054 /* Mostly inspired from wine code */
1060 PCURICON_OBJECT pIcon
,
1064 HBRUSH hbrFlickerFreeDraw
,
1068 HBITMAP hbmMask
, hbmColor
;
1069 BITMAP bmpColor
, bm
;
1071 INT iOldBkColor
= 0, iOldTxtColor
= 0;
1073 HDC hMemDC
, hDestDC
= hDc
;
1074 HGDIOBJ hOldOffBrush
= 0;
1075 HGDIOBJ hOldOffBmp
= 0;
1076 HBITMAP hTmpBmp
= 0, hOffBmp
= 0;
1077 BOOL bAlpha
= FALSE
;
1078 INT x
=xLeft
, y
=yTop
;
1080 hbmMask
= pIcon
->IconInfo
.hbmMask
;
1081 hbmColor
= pIcon
->IconInfo
.hbmColor
;
1084 ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1086 if (!hbmMask
|| !GreGetObject(hbmMask
, sizeof(BITMAP
), (PVOID
)&bm
))
1091 if (hbmColor
&& !GreGetObject(hbmColor
, sizeof(BITMAP
), (PVOID
)&bmpColor
))
1096 if(!(hMemDC
= NtGdiCreateCompatibleDC(hDc
)))
1098 ERR("NtGdiCreateCompatibleDC failed!\n");
1102 /* Check for alpha */
1104 && (bmpColor
.bmBitsPixel
== 32)
1105 && (diFlags
& DI_IMAGE
))
1107 SURFACE
*psurfOff
= NULL
;
1108 PFN_DIB_GetPixel fnSource_GetPixel
= NULL
;
1111 /* In order to correctly display 32 bit icons Windows first scans the image,
1112 because information about transparency is not stored in any image's headers */
1113 psurfOff
= SURFACE_ShareLockSurface(hbmColor
);
1116 fnSource_GetPixel
= DibFunctionsForBitmapFormat
[psurfOff
->SurfObj
.iBitmapFormat
].DIB_GetPixel
;
1117 if (fnSource_GetPixel
)
1119 for (i
= 0; i
< psurfOff
->SurfObj
.sizlBitmap
.cx
; i
++)
1121 for (j
= 0; j
< psurfOff
->SurfObj
.sizlBitmap
.cy
; j
++)
1123 bAlpha
= ((BYTE
)(fnSource_GetPixel(&psurfOff
->SurfObj
, i
, j
) >> 24) & 0xff);
1131 SURFACE_ShareUnlockSurface(psurfOff
);
1136 cxWidth
= ((diFlags
& DI_DEFAULTSIZE
) ?
1137 UserGetSystemMetrics(SM_CXICON
) : pIcon
->Size
.cx
);
1140 cyHeight
= ((diFlags
& DI_DEFAULTSIZE
) ?
1141 UserGetSystemMetrics(SM_CYICON
) : pIcon
->Size
.cy
);
1143 DoFlickerFree
= (hbrFlickerFreeDraw
&&
1144 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw
) == GDI_OBJECT_TYPE_BRUSH
));
1148 hDestDC
= NtGdiCreateCompatibleDC(hDc
);
1151 ERR("NtGdiCreateCompatibleDC failed!\n");
1155 hOffBmp
= NtGdiCreateCompatibleBitmap(hDc
, cxWidth
, cyHeight
);
1158 ERR("NtGdiCreateCompatibleBitmap failed!\n");
1161 hOldOffBmp
= NtGdiSelectBitmap(hDestDC
, hOffBmp
);
1162 hOldOffBrush
= NtGdiSelectBrush(hDestDC
, hbrFlickerFreeDraw
);
1163 NtGdiPatBlt(hDestDC
, 0, 0, cxWidth
, cyHeight
, PATCOPY
);
1164 NtGdiSelectBrush(hDestDC
, hOldOffBrush
);
1168 /* Set Background/foreground colors */
1169 iOldTxtColor
= IntGdiSetTextColor(hDc
, 0); //black
1170 iOldBkColor
= IntGdiSetBkColor(hDc
, 0x00FFFFFF); //white
1172 if(bAlpha
&& (diFlags
& DI_IMAGE
))
1174 BLENDFUNCTION pixelblend
= { AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
1179 HBITMAP hMemBmp
= NULL
;
1181 hMemBmp
= BITMAP_CopyBitmap(hbmColor
);
1184 ERR("BITMAP_CopyBitmap failed!");
1188 psurf
= SURFACE_ShareLockSurface(hMemBmp
);
1191 ERR("SURFACE_LockSurface failed!\n");
1195 /* premultiply with the alpha channel value */
1196 for (i
= 0; i
< psurf
->SurfObj
.sizlBitmap
.cy
; i
++)
1198 ptr
= (PBYTE
)psurf
->SurfObj
.pvScan0
+ i
*psurf
->SurfObj
.lDelta
;
1199 for (j
= 0; j
< psurf
->SurfObj
.sizlBitmap
.cx
; j
++)
1202 ptr
[0] = (ptr
[0] * Alpha
) / 0xff;
1203 ptr
[1] = (ptr
[1] * Alpha
) / 0xff;
1204 ptr
[2] = (ptr
[2] * Alpha
) / 0xff;
1210 SURFACE_ShareUnlockSurface(psurf
);
1212 hTmpBmp
= NtGdiSelectBitmap(hMemDC
, hMemBmp
);
1214 Ret
= NtGdiAlphaBlend(hDestDC
,
1226 NtGdiSelectBitmap(hMemDC
, hTmpBmp
);
1228 if(hMemBmp
) NtGdiDeleteObjectApp(hMemBmp
);
1232 if (diFlags
& DI_MASK
)
1234 hTmpBmp
= NtGdiSelectBitmap(hMemDC
, hbmMask
);
1235 NtGdiStretchBlt(hDestDC
,
1247 NtGdiSelectBitmap(hMemDC
, hTmpBmp
);
1250 if(diFlags
& DI_IMAGE
)
1254 DWORD rop
= (diFlags
& DI_MASK
) ? SRCINVERT
: SRCCOPY
;
1255 hTmpBmp
= NtGdiSelectBitmap(hMemDC
, hbmColor
);
1256 NtGdiStretchBlt(hDestDC
,
1268 NtGdiSelectBitmap(hMemDC
, hTmpBmp
);
1272 /* Mask bitmap holds the information in its second half */
1273 DWORD rop
= (diFlags
& DI_MASK
) ? SRCINVERT
: SRCCOPY
;
1274 hTmpBmp
= NtGdiSelectBitmap(hMemDC
, hbmMask
);
1275 NtGdiStretchBlt(hDestDC
,
1287 NtGdiSelectBitmap(hMemDC
, hTmpBmp
);
1294 NtGdiBitBlt(hDc
, xLeft
, yTop
, cxWidth
, cyHeight
, hDestDC
, 0, 0, SRCCOPY
, 0, 0);
1297 /* Restore foreground and background colors */
1298 IntGdiSetBkColor(hDc
, iOldBkColor
);
1299 IntGdiSetTextColor(hDc
, iOldTxtColor
);
1304 NtGdiDeleteObjectApp(hMemDC
);
1307 if(hOldOffBmp
) NtGdiSelectBitmap(hDestDC
, hOldOffBmp
);
1308 NtGdiDeleteObjectApp(hDestDC
);
1309 if(hOffBmp
) NtGdiDeleteObjectApp(hOffBmp
);
1328 HBRUSH hbrFlickerFreeDraw
,
1330 BOOL bMetaHDC
, // When TRUE, GDI functions need to be handled in User32!
1333 PCURICON_OBJECT pIcon
;
1336 TRACE("Enter NtUserDrawIconEx\n");
1337 UserEnterExclusive();
1339 if (!(pIcon
= UserGetCurIconObject(hIcon
)))
1341 ERR("UserGetCurIconObject() failed!\n");
1346 Ret
= UserDrawIconEx(hdc
,
1356 UserDereferenceObject(pIcon
);