* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: Cursor and icon functions
- * FILE: subsystems/win32/win32k/ntuser/cursoricon.c
+ * FILE: win32ss/user/ntuser/cursoricon.c
* PROGRAMER: ReactOS Team
*/
/*
* Possibly shared by multiple processes
* Immune to NtDestroyCursorIcon()
* CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
- * There's a M:N relationship between processes and (shared) cursor/icons.
- * A process can have multiple cursor/icons and a cursor/icon can be used
- * by multiple processes. To keep track of this we keep a list of all
- * cursor/icons (CurIconList) and per cursor/icon we keep a list of
- * CURICON_PROCESS structs starting at CurIcon->ProcessList.
*/
#include <win32k.h>
DBG_DEFAULT_CHANNEL(UserIcon);
-static LIST_ENTRY gCurIconList;
-static PAGED_LOOKASIDE_LIST *pgProcessLookasideList;
-
SYSTEM_CURSORINFO gSysCursorInfo;
BOOL
-InitCursorImpl()
+InitCursorImpl(VOID)
{
- pgProcessLookasideList = ExAllocatePool(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST));
- if(!pgProcessLookasideList)
- return FALSE;
-
- ExInitializePagedLookasideList(pgProcessLookasideList,
- NULL,
- NULL,
- 0,
- sizeof(CURICON_PROCESS),
- TAG_DIB,
- 128);
- InitializeListHead(&gCurIconList);
-
gSysCursorInfo.Enabled = FALSE;
gSysCursorInfo.ButtonsDown = 0;
gSysCursorInfo.bClipped = FALSE;
return NULL;
}
+ if (UserObjectInDestroy(hCurIcon))
+ {
+ WARN("Requesting invalid/destroyed cursor.\n");
+ EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
+ return NULL;
+ }
+
CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR);
if (!CurIcon)
{
return TRUE;
}
-/*
- * We have to register that this object is in use by the current
- * process. The only way to do that seems to be to walk the list
- * of cursor/icon objects starting at W32Process->CursorIconListHead.
- * If the object is already present in the list, we don't have to do
- * anything, if it's not present we add it and inc the ProcessCount
- * in the object. Having to walk the list kind of sucks, but that's
- * life...
- */
-static BOOLEAN FASTCALL
-ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
+HANDLE
+IntCreateCurIconHandle(BOOLEAN Animated)
{
- PPROCESSINFO Win32Process;
- PCURICON_PROCESS Current;
-
- Win32Process = PsGetCurrentProcessWin32Process();
+ PCURICON_OBJECT CurIcon;
+ HANDLE hCurIcon;
- LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
- {
- if (Current->Process == Win32Process)
- {
- /* Already registered for this process */
- return TRUE;
- }
- }
+ CurIcon = UserCreateObject(
+ gHandleTable,
+ NULL,
+ GetW32ThreadInfo(),
+ &hCurIcon,
+ TYPE_CURSOR,
+ Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT));
- /* Not registered yet */
- Current = ExAllocateFromPagedLookasideList(pgProcessLookasideList);
- if (NULL == Current)
+ if (!CurIcon)
{
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
- InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
- Current->Process = Win32Process;
- return TRUE;
+ UserDereferenceObject(CurIcon);
+
+ return hCurIcon;
}
-static
-PCURICON_OBJECT
-FASTCALL
-IntFindExistingCurIconObject(
- PUNICODE_STRING pustrModule,
- PUNICODE_STRING pustrRsrc,
- FINDEXISTINGCURICONPARAM* param)
+BOOLEAN
+IntDestroyCurIconObject(
+ _In_ PVOID Object)
{
- PCURICON_OBJECT CurIcon;
+ PCURICON_OBJECT CurIcon = Object;
- LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
+ /* Try finding it in its process cache */
+ if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
{
- /* See if we are looking for an icon or a cursor */
- if(MAKEINTRESOURCE(CurIcon->rt) != (param->bIcon ? RT_ICON : RT_CURSOR))
- continue;
- /* See if module names match */
- if(RtlCompareUnicodeString(pustrModule, &CurIcon->ustrModule, TRUE) == 0)
+ PPROCESSINFO ppi;
+
+ ppi = CurIcon->head.ppi;
+ if (ppi->pCursorCache == CurIcon)
{
- /* They do. Now see if this is the same resource */
- if(IS_INTRESOURCE(CurIcon->strName.Buffer) && IS_INTRESOURCE(pustrRsrc->Buffer))
- {
- if(CurIcon->strName.Buffer != pustrRsrc->Buffer)
- continue;
- }
- else if(IS_INTRESOURCE(CurIcon->strName.Buffer) || IS_INTRESOURCE(pustrRsrc->Buffer))
- continue;
- else if(RtlCompareUnicodeString(pustrRsrc, &CurIcon->strName, TRUE) != 0)
- continue;
-
- if ((param->cx == CurIcon->cx) && (param->cy == CurIcon->cy))
+ ppi->pCursorCache = CurIcon->pcurNext;
+ UserDereferenceObject(CurIcon);
+ }
+ else
+ {
+ PCURICON_OBJECT CacheCurIcon = ppi->pCursorCache;
+ while (CacheCurIcon)
{
- if (! ReferenceCurIconByProcess(CurIcon))
+ if (CacheCurIcon->pcurNext == CurIcon)
{
- return NULL;
+ CacheCurIcon->pcurNext = CurIcon->pcurNext;
+ break;
}
-
- return CurIcon;
+ CacheCurIcon = CacheCurIcon->pcurNext;
}
- }
- }
-
- return NULL;
-}
-
-PCURICON_OBJECT
-IntCreateCurIconHandle(DWORD dwNumber)
-{
- PCURICON_OBJECT CurIcon;
- HANDLE hCurIcon;
-
- if(dwNumber == 0)
- dwNumber = 1;
-
- CurIcon = UserCreateObject(gHandleTable, NULL, NULL, &hCurIcon, TYPE_CURSOR, sizeof(CURICON_OBJECT));
-
- if (!CurIcon)
- {
- EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
-
- CurIcon->Self = hCurIcon;
- InitializeListHead(&CurIcon->ProcessList);
- if (! ReferenceCurIconByProcess(CurIcon))
- {
- ERR("Failed to add process\n");
- UserDereferenceObject(CurIcon);
- UserDeleteObject(hCurIcon, TYPE_CURSOR);
- return NULL;
+ /* We must have found it! */
+ ASSERT(CacheCurIcon != NULL);
+ UserDereferenceObject(CurIcon);
+ }
}
- InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
-
- return CurIcon;
+ /* We just mark the handle as being destroyed.
+ * Deleting all the stuff will be deferred to the actual struct free. */
+ return UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
}
-BOOLEAN FASTCALL
-IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi, BOOLEAN bForce)
+void
+FreeCurIconObject(
+ _In_ PVOID Object)
{
- HBITMAP bmpMask, bmpColor, bmpAlpha;
- BOOLEAN Ret, bListEmpty, bFound = FALSE;
- PCURICON_PROCESS Current = NULL;
+ PCURICON_OBJECT CurIcon = Object;
- /* Check if this is the current cursor */
- if(CurIcon->CURSORF_flags & CURSORF_CURRENT)
+ if(!(CurIcon->CURSORF_flags & CURSORF_ACON))
{
- UserDereferenceObject(CurIcon);
- return FALSE;
- }
-
- /* For handles created without any data (error handling) */
- if(IsListEmpty(&CurIcon->ProcessList))
- goto emptyList;
+ HBITMAP bmpMask = CurIcon->hbmMask;
+ HBITMAP bmpColor = CurIcon->hbmColor;
+ HBITMAP bmpAlpha = CurIcon->hbmAlpha;
- /* Now find this process in the list of processes referencing this object and
- remove it from that list */
- LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
- {
- if (Current->Process == ppi)
+ /* Delete bitmaps */
+ if (bmpMask)
{
- bFound = TRUE;
- bListEmpty = RemoveEntryList(&Current->ListEntry);
- break;
+ GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(bmpMask);
+ CurIcon->hbmMask = NULL;
}
- }
-
- if(!bFound)
- {
- /* This object doesn't belong to this process */
- EngSetLastError(ERROR_INVALID_HANDLE);
- /* Caller expects us to dereference! */
- UserDereferenceObject(CurIcon);
- return FALSE;
- }
-
- /* We found our process, but we're told to not destroy it in case it is shared */
- if((CurIcon->ustrModule.Buffer != NULL) && !bForce)
- {
- /* Tests show this is a valid call */
- UserDereferenceObject(CurIcon);
- return TRUE;
- }
-
- ExFreeToPagedLookasideList(pgProcessLookasideList, Current);
-
- /* If there are still processes referencing this object we can't destroy it yet */
- if (!bListEmpty)
- {
- if(CurIcon->head.ppi == ppi)
+ if (bmpColor)
{
- /* Set the first process of the list as owner */
- Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
- UserSetObjectOwner(CurIcon, TYPE_CURSOR, Current->Process);
+ GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(bmpColor);
+ CurIcon->hbmColor = NULL;
+ }
+ if (bmpAlpha)
+ {
+ GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(bmpAlpha);
+ CurIcon->hbmAlpha = NULL;
}
- UserDereferenceObject(CurIcon);
- return TRUE;
- }
-
-emptyList:
- /* Remove it from the list */
- RemoveEntryList(&CurIcon->ListEntry);
-
- bmpMask = CurIcon->hbmMask;
- bmpColor = CurIcon->hbmColor;
- bmpAlpha = CurIcon->hbmAlpha;
-
- /* Delete bitmaps */
- if (bmpMask)
- {
- GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(bmpMask);
- CurIcon->hbmMask = NULL;
}
- if (bmpColor)
+ else
{
- GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(bmpColor);
- CurIcon->hbmColor = NULL;
+ PACON AniCurIcon = (PACON)CurIcon;
+ UINT i;
+
+ for(i = 0; i < AniCurIcon->cpcur; i++)
+ IntDestroyCurIconObject(AniCurIcon->aspcur[i]);
+ ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
}
- if (bmpAlpha)
+
+ if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
{
- GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(bmpAlpha);
- CurIcon->hbmAlpha = NULL;
+ if (!IS_INTRESOURCE(CurIcon->strName.Buffer))
+ ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
+ if (CurIcon->atomModName)
+ RtlDeleteAtomFromAtomTable(gAtomTable, CurIcon->atomModName);
+ CurIcon->strName.Buffer = NULL;
+ CurIcon->atomModName = 0;
}
-
- if(!IS_INTRESOURCE(CurIcon->strName.Buffer))
- ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
- if(CurIcon->ustrModule.Buffer)
- ReleaseCapturedUnicodeString(&CurIcon->ustrModule, UserMode);
- /* We were given a pointer, no need to keep the reference anylonger! */
- UserDereferenceObject(CurIcon);
- Ret = UserDeleteObject(CurIcon->Self, TYPE_CURSOR);
-
- return Ret;
+ /* Finally free the thing */
+ FreeProcMarkObject(CurIcon);
}
VOID FASTCALL
-IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
+IntCleanupCurIconCache(PPROCESSINFO Win32Process)
{
- PCURICON_OBJECT CurIcon, tmp;
+ PCURICON_OBJECT CurIcon;
/* Run through the list of icon objects */
- LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
+ while (Win32Process->pCursorCache)
{
- UserReferenceObject(CurIcon);
- IntDestroyCurIconObject(CurIcon, Win32Process, TRUE);
+ CurIcon = Win32Process->pCursorCache;
+ Win32Process->pCursorCache = CurIcon->pcurNext;
+ UserDereferenceObject(CurIcon);
}
}
-
/*
* @implemented
*/
/* Give back the icon information */
if(IconInfo)
{
+ PCURICON_OBJECT FrameCurIcon = CurIcon;
+ if(CurIcon->CURSORF_flags & CURSORF_ACON)
+ {
+ /* Get information from first frame. */
+ FrameCurIcon = ((PACON)CurIcon)->aspcur[0];
+ }
+
/* Fill data */
- ii.fIcon = is_icon(CurIcon);
- ii.xHotspot = CurIcon->xHotspot;
- ii.yHotspot = CurIcon->yHotspot;
+ ii.fIcon = is_icon(FrameCurIcon);
+ ii.xHotspot = FrameCurIcon->xHotspot;
+ ii.yHotspot = FrameCurIcon->yHotspot;
/* Copy bitmaps */
- ii.hbmMask = BITMAP_CopyBitmap(CurIcon->hbmMask);
+ ii.hbmMask = BITMAP_CopyBitmap(FrameCurIcon->hbmMask);
GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED);
- ii.hbmColor = BITMAP_CopyBitmap(CurIcon->hbmColor);
+ ii.hbmColor = BITMAP_CopyBitmap(FrameCurIcon->hbmColor);
GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED);
- colorBpp = CurIcon->bpp;
+ colorBpp = FrameCurIcon->bpp;
/* Copy fields */
_SEH2_TRY
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
- }
- if (!NT_SUCCESS(Status))
- {
- WARN("Status: 0x%08x.\n", Status);
- SetLastNtError(Status);
- goto leave;
+ if (!NT_SUCCESS(Status))
+ {
+ WARN("Status: 0x%08x.\n", Status);
+ SetLastNtError(Status);
+ goto leave;
+ }
}
/* Give back the module name */
if(lpModule)
{
- if(!CurIcon->ustrModule.Buffer)
- {
- EngSetLastError(ERROR_INVALID_HANDLE);
+ ULONG BufLen = 0;
+ if (!CurIcon->atomModName)
goto leave;
- }
- /* Copy what we can */
+
+ RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, NULL, &BufLen);
+ /* Get the module name from the atom table */
_SEH2_TRY
{
- ProbeForWrite(lpModule, sizeof(UNICODE_STRING), 1);
- ProbeForWrite(lpModule->Buffer, lpModule->MaximumLength, 1);
- lpModule->Length = min(lpModule->MaximumLength, CurIcon->ustrModule.Length);
- RtlCopyMemory(lpModule->Buffer, CurIcon->ustrModule.Buffer, lpModule->Length);
+ if (BufLen > (lpModule->MaximumLength * sizeof(WCHAR)))
+ {
+ lpModule->Length = 0;
+ }
+ else
+ {
+ ProbeForWrite(lpModule->Buffer, lpModule->MaximumLength, 1);
+ BufLen = lpModule->MaximumLength * sizeof(WCHAR);
+ RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, lpModule->Buffer, &BufLen);
+ lpModule->Length = BufLen/sizeof(WCHAR);
+ }
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
- }
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- goto leave;
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ goto leave;
+ }
}
- if(lpResName)
+ if (lpResName)
{
- if(!CurIcon->strName.Buffer)
- {
- EngSetLastError(ERROR_INVALID_HANDLE);
+ if (!CurIcon->strName.Buffer)
goto leave;
- }
+
/* Copy it */
_SEH2_TRY
{
ProbeForWrite(lpResName, sizeof(UNICODE_STRING), 1);
- if(IS_INTRESOURCE(CurIcon->strName.Buffer))
+ if (IS_INTRESOURCE(CurIcon->strName.Buffer))
{
lpResName->Buffer = CurIcon->strName.Buffer;
lpResName->Length = 0;
}
+ else if (lpResName->MaximumLength < CurIcon->strName.Length)
+ {
+ lpResName->Length = 0;
+ }
else
{
- lpResName->Length = min(lpResName->MaximumLength, CurIcon->strName.Length);
+ ProbeForWrite(lpResName->Buffer, lpResName->MaximumLength * sizeof(WCHAR), 1);
RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, lpResName->Length);
}
}
goto cleanup;
}
+ if(CurIcon->CURSORF_flags & CURSORF_ACON)
+ {
+ /* Use first frame for animated cursors */
+ PACON AniCurIcon = (PACON)CurIcon;
+ CurIcon = AniCurIcon->aspcur[0];
+ UserDereferenceObject(AniCurIcon);
+ UserReferenceObject(CurIcon);
+ }
+
_SEH2_TRY
{
ProbeForWrite(plcx, sizeof(LONG), 1);
SafeCi.cbSize = sizeof(CURSORINFO);
SafeCi.flags = ((CurIcon && CurInfo->ShowingCursor >= 0) ? CURSOR_SHOWING : 0);
- SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
+ SafeCi.hCursor = (CurIcon ? CurIcon->head.h : NULL);
SafeCi.ptScreenPos = gpsi->ptCursor;
prcl = &rclLocal;
}
- UserEnterExclusive();
+ UserEnterExclusive();
/* Call the internal function */
bResult = UserClipCursor(prcl);
_In_ HANDLE hCurIcon,
_In_ BOOL bForce)
{
- PCURICON_OBJECT CurIcon;
BOOL ret;
- DECLARE_RETURN(BOOL);
+ PCURICON_OBJECT CurIcon = NULL;
- TRACE("Enter NtUserDestroyCursorIcon\n");
+ TRACE("Enter NtUserDestroyCursorIcon (%p, %u)\n", hCurIcon, bForce);
UserEnterExclusive();
- if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ CurIcon = UserGetCurIconObject(hCurIcon);
+ if (!CurIcon)
{
- RETURN(FALSE);
+ ret = FALSE;
+ goto leave;
}
- ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process(), bForce);
- /* Note: IntDestroyCurIconObject will remove our reference for us! */
+ if (!bForce)
+ {
+ /* Maybe we have good reasons not to destroy this object */
+ if (CurIcon->head.ppi != PsGetCurrentProcessWin32Process())
+ {
+ /* No way, you're not touching my cursor */
+ ret = FALSE;
+ goto leave;
+ }
+
+ if (CurIcon->CURSORF_flags & CURSORF_CURRENT)
+ {
+ WARN("Trying to delete current cursor!\n");
+ ret = FALSE;
+ goto leave;
+ }
+
+ if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
+ {
+ WARN("Trying to delete shared cursor.\n");
+ /* This one is not an error */
+ ret = TRUE;
+ goto leave;
+ }
+ }
- RETURN(ret);
+ /* Destroy the handle */
+ ret = IntDestroyCurIconObject(CurIcon);
-CLEANUP:
- TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
+leave:
+ if (CurIcon)
+ UserDereferenceObject(CurIcon);
+ TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n", ret);
UserLeave();
- END_CLEANUP;
+ return ret;
}
UNICODE_STRING ustrModuleSafe, ustrRsrcSafe;
FINDEXISTINGCURICONPARAM paramSafe;
NTSTATUS Status;
+ PPROCESSINFO pProcInfo = PsGetCurrentProcessWin32Process();
+ RTL_ATOM atomModName;
TRACE("Enter NtUserFindExistingCursorIcon\n");
- /* Capture resource name (it can be an INTRESOURCE == ATOM) */
- Status = ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrcSafe, pustrRsrc);
- if(!NT_SUCCESS(Status))
- return NULL;
- Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
- if(!NT_SUCCESS(Status))
- goto done;
_SEH2_TRY
{
}
_SEH2_END
+ /* Capture resource name (it can be an INTRESOURCE == ATOM) */
+ Status = ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrcSafe, pustrRsrc);
+ if(!NT_SUCCESS(Status))
+ return NULL;
+ Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
+ if(!NT_SUCCESS(Status))
+ goto done;
+ Status = RtlLookupAtomInAtomTable(gAtomTable, ustrModuleSafe.Buffer, &atomModName);
+ ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode);
+ if(!NT_SUCCESS(Status))
+ {
+ /* The module is not in the atom table. No chance to find the cursor */
+ goto done;
+ }
+
UserEnterExclusive();
- CurIcon = IntFindExistingCurIconObject(&ustrModuleSafe, &ustrRsrcSafe, ¶mSafe);
- if (CurIcon)
- Ret = CurIcon->Self;
+ CurIcon = pProcInfo->pCursorCache;
+ while(CurIcon)
+ {
+ /* Icon/cursor */
+ if (paramSafe.bIcon != is_icon(CurIcon))
+ {
+ CurIcon = CurIcon->pcurNext;
+ continue;
+ }
+ /* See if module names match */
+ if (atomModName == CurIcon->atomModName)
+ {
+ /* They do. Now see if this is the same resource */
+ if (IS_INTRESOURCE(CurIcon->strName.Buffer) != IS_INTRESOURCE(ustrRsrcSafe.Buffer))
+ {
+ /* One is an INT resource and the other is not -> no match */
+ CurIcon = CurIcon->pcurNext;
+ continue;
+ }
+
+ if (IS_INTRESOURCE(CurIcon->strName.Buffer))
+ {
+ if (CurIcon->strName.Buffer == ustrRsrcSafe.Buffer)
+ {
+ /* INT resources match */
+ break;
+ }
+ }
+ else if (RtlCompareUnicodeString(&ustrRsrcSafe, &CurIcon->strName, TRUE) == 0)
+ {
+ /* Resource name strings match */
+ break;
+ }
+ }
+ CurIcon = CurIcon->pcurNext;
+ }
+ if(CurIcon)
+ Ret = CurIcon->head.h;
UserLeave();
done:
if(!IS_INTRESOURCE(ustrRsrcSafe.Buffer))
ExFreePoolWithTag(ustrRsrcSafe.Buffer, TAG_STRING);
- ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode);
return Ret;
}
PCURICON_OBJECT pcurOld, pcurNew;
HCURSOR hOldCursor = NULL;
- TRACE("Enter NtUserSetCursor\n");
+ TRACE("Enter NtUserSetCursor: %p\n", hCursor);
UserEnterExclusive();
if (hCursor)
pcurOld = UserSetCursor(pcurNew, FALSE);
if (pcurOld)
{
- hOldCursor = (HCURSOR)pcurOld->Self;
+ hOldCursor = pcurOld->head.h;
+ /* See if it was destroyed in the meantime */
+ if (UserObjectInDestroy(hOldCursor))
+ hOldCursor = NULL;
pcurOld->CURSORF_flags &= ~CURSORF_CURRENT;
UserDereferenceObject(pcurOld);
}
_In_ HCURSOR Handle,
_In_opt_ PUNICODE_STRING pustrModule,
_In_opt_ PUNICODE_STRING pustrRsrc,
- _In_ PCURSORDATA pCursorData)
+ _In_ const CURSORDATA* pCursorData)
{
PCURICON_OBJECT CurIcon;
NTSTATUS Status = STATUS_SUCCESS;
- BOOL Ret = FALSE;
+ BOOLEAN Ret = FALSE;
+ BOOLEAN IsShared = FALSE, IsAnim = FALSE;
+ DWORD numFrames;
+ UINT i = 0;
TRACE("Enter NtUserSetCursorIconData\n");
- /* If a module name is provided, we need a resource name, and vice versa */
- if((pustrModule && !pustrRsrc) || (!pustrModule && pustrRsrc))
- return FALSE;
-
UserEnterExclusive();
if (!(CurIcon = UserGetCurIconObject(Handle)))
_SEH2_TRY
{
ProbeForRead(pCursorData, sizeof(*pCursorData), 1);
- CurIcon->xHotspot = pCursorData->xHotspot;
- CurIcon->yHotspot = pCursorData->yHotspot;
- CurIcon->cx = pCursorData->cx;
- CurIcon->cy = pCursorData->cy;
- CurIcon->rt = pCursorData->rt;
- CurIcon->bpp = pCursorData->bpp;
- CurIcon->hbmMask = pCursorData->hbmMask;
- CurIcon->hbmColor = pCursorData->hbmColor;
- CurIcon->hbmAlpha = pCursorData->hbmAlpha;
+ if(pCursorData->CURSORF_flags & CURSORF_ACON)
+ {
+ /* This is an animated cursor */
+ PACON AniCurIcon = (PACON)CurIcon;
+ DWORD numSteps;
+
+ numFrames = AniCurIcon->cpcur = pCursorData->cpcur;
+ numSteps = AniCurIcon->cicur = pCursorData->cicur;
+ AniCurIcon->iicur = pCursorData->iicur;
+ AniCurIcon->rt = pCursorData->rt;
+
+ /* Calculate size: one cursor object for each frame, and a frame index and jiffies for each "step" */
+ AniCurIcon->aspcur = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, /* Let SEH catch allocation failures */
+ numFrames * sizeof(CURICON_OBJECT*) + numSteps * (sizeof(DWORD) + sizeof(INT)),
+ USERTAG_CURSOR);
+ AniCurIcon->aicur = (DWORD*)(AniCurIcon->aspcur + numFrames);
+ AniCurIcon->ajifRate = (INT*)(AniCurIcon->aicur + numSteps);
+
+ RtlZeroMemory(AniCurIcon->aspcur, numFrames * sizeof(CURICON_OBJECT*));
+
+ ProbeForRead(pCursorData->aicur, numSteps * sizeof(DWORD), 1);
+ RtlCopyMemory(AniCurIcon->aicur, pCursorData->aicur, numSteps * sizeof(DWORD));
+ ProbeForRead(pCursorData->ajifRate, numSteps * sizeof(INT), 1);
+ RtlCopyMemory(AniCurIcon->ajifRate, pCursorData->ajifRate, numSteps * sizeof(INT));
+
+ AniCurIcon->CURSORF_flags = pCursorData->CURSORF_flags;
+ pCursorData = pCursorData->aspcur;
+
+ IsAnim = TRUE;
+ }
+ else
+ {
+ CurIcon->xHotspot = pCursorData->xHotspot;
+ CurIcon->yHotspot = pCursorData->yHotspot;
+ CurIcon->cx = pCursorData->cx;
+ CurIcon->cy = pCursorData->cy;
+ CurIcon->rt = pCursorData->rt;
+ CurIcon->bpp = pCursorData->bpp;
+ CurIcon->hbmMask = pCursorData->hbmMask;
+ CurIcon->hbmColor = pCursorData->hbmColor;
+ CurIcon->hbmAlpha = pCursorData->hbmAlpha;
+ CurIcon->CURSORF_flags = pCursorData->CURSORF_flags;
+ }
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastNtError(Status);
goto done;
}
+
+ if(IsAnim)
+ {
+ PACON AniCurIcon = (PACON)CurIcon;
+ /* This is an animated cursor. Create a cursor object for each frame and set up the data */
+ for(i = 0; i < numFrames; i++)
+ {
+ HANDLE hCurFrame = IntCreateCurIconHandle(FALSE);
+ if(!NtUserSetCursorIconData(hCurFrame, NULL, NULL, pCursorData))
+ goto done;
+ AniCurIcon->aspcur[i] = UserGetCurIconObject(hCurFrame);
+ if(!AniCurIcon->aspcur[i])
+ goto done;
+ pCursorData++;
+ }
+ }
- if(pustrModule)
+ if(CurIcon->CURSORF_flags & CURSORF_LRSHARED)
{
- /* We use this convenient function, because INTRESOURCEs and ATOMs are the same */
- Status = ProbeAndCaptureUnicodeStringOrAtom(&CurIcon->strName, pustrRsrc);
- if(!NT_SUCCESS(Status))
- goto done;
- Status = ProbeAndCaptureUnicodeString(&CurIcon->ustrModule, UserMode, pustrModule);
- if(!NT_SUCCESS(Status))
- goto done;
+ IsShared = TRUE;
+ if(pustrRsrc && pustrModule)
+ {
+ UNICODE_STRING ustrModuleSafe;
+ /* We use this convenient function, because INTRESOURCEs and ATOMs are the same */
+ Status = ProbeAndCaptureUnicodeStringOrAtom(&CurIcon->strName, pustrRsrc);
+ if(!NT_SUCCESS(Status))
+ goto done;
+ Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
+ if(!NT_SUCCESS(Status))
+ goto done;
+ Status = RtlAddAtomToAtomTable(gAtomTable, ustrModuleSafe.Buffer, &CurIcon->atomModName);
+ ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode);
+ if(!NT_SUCCESS(Status))
+ goto done;
+ }
}
-
if(!CurIcon->hbmMask)
{
ERR("NtUserSetCursorIconData was got no hbmMask.\n");
if(CurIcon->hbmAlpha)
GreSetObjectOwner(CurIcon->hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
+
+ if(IsShared)
+ {
+ /* Update process cache in case of shared cursor */
+ PPROCESSINFO ppi = CurIcon->head.ppi;
+ UserReferenceObject(CurIcon);
+ CurIcon->pcurNext = ppi->pCursorCache;
+ ppi->pCursorCache = CurIcon;
+ }
Ret = TRUE;
done:
- if(!Ret)
+ if(!Ret && IsShared)
{
if(!IS_INTRESOURCE(CurIcon->strName.Buffer))
ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
- if(CurIcon->ustrModule.Buffer)
- ReleaseCapturedUnicodeString(&CurIcon->ustrModule, UserMode);
}
+
+ if(!Ret && IsAnim)
+ {
+ PACON AniCurIcon = (PACON)CurIcon;
+ for(i = 0; i < numFrames; i++)
+ {
+ if(AniCurIcon->aspcur[i])
+ IntDestroyCurIconObject(AniCurIcon->aspcur[i]);
+ }
+ AniCurIcon->cicur = 0;
+ AniCurIcon->cpcur = 0;
+ ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
+ AniCurIcon->aspcur = NULL;
+ AniCurIcon->aicur = NULL;
+ AniCurIcon->ajifRate = NULL;
+ }
+
UserDereferenceObject(CurIcon);
TRACE("Leave NtUserSetCursorIconData, ret=%i\n",Ret);
UserLeave();
-
+
return Ret;
}
return FALSE;
}
+ if (pIcon->CURSORF_flags & CURSORF_ACON)
+ {
+ ACON* pAcon = (ACON*)pIcon;
+ if(istepIfAniCur >= pAcon->cicur)
+ {
+ ERR("NtUserDrawIconEx: istepIfAniCur too big!\n");
+ return FALSE;
+ }
+ pIcon = pAcon->aspcur[pAcon->aicur[istepIfAniCur]];
+ }
+
hbmMask = pIcon->hbmMask;
hbmColor = pIcon->hbmColor;
hbmAlpha = pIcon->hbmAlpha;
- if (istepIfAniCur)
- ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
-
/*
* Get our objects.
* Shared locks are enough, we are only reading those bitmaps
RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
/* Prepare the underlying surface */
- DC_vPrepareDCsForBlit(pdc, rcDest, NULL, rcDest);
+ DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
/* We now have our destination surface and rectangle */
psurfDest = pdc->dclevel.pSurface;
/* We now have our destination surface */
psurfDest = psurfOffScreen;
#else
- pdcClipObj = pdc->rosdc.CombinedClip;
+ pdcClipObj = &pdc->co.ClipObj;
/* Paint the brush */
EBRUSHOBJ_vInit(&eboFill, pbrush, psurfDest, 0x00FFFFFF, 0, NULL);
{
/* We directly draw to the DC */
TRACE("Performing on screen rendering.\n");
- pdcClipObj = pdc->rosdc.CombinedClip;
+ pdcClipObj = &pdc->co.ClipObj;
// psurfOffScreen = NULL;
}
/* Now do the rendering */
- if(hbmAlpha && ((diFlags & DI_NORMAL) == DI_NORMAL))
- {
- BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
+ if(hbmAlpha && ((diFlags & DI_NORMAL) == DI_NORMAL))
+ {
+ BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
PSURFACE psurf = NULL;
psurf = SURFACE_ShareLockSurface(hbmAlpha);
EXLATEOBJ_vCleanup(&exlo);
SURFACE_ShareUnlockSurface(psurf);
if(Ret) goto done;
- ERR("NtGdiAlphaBlend failed!\n");
+ ERR("NtGdiAlphaBlend failed!\n");
}
NoAlpha:
if (diFlags & DI_MASK)
if(diFlags & DI_IMAGE)
{
- if (psurfColor)
+ if (psurfColor)
{
DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ;
return Ret;
}
+/*
+ * @unimplemented
+ */
+HCURSOR
+NTAPI
+NtUserGetCursorFrameInfo(
+ HCURSOR hCursor,
+ DWORD istep,
+ INT* rate_jiffies,
+ DWORD* num_steps)
+{
+ PCURICON_OBJECT CurIcon;
+ HCURSOR ret;
+ INT jiffies = 0;
+ DWORD steps = 1;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ TRACE("Enter NtUserGetCursorFrameInfo\n");
+ UserEnterExclusive();
+
+ if (!(CurIcon = UserGetCurIconObject(hCursor)))
+ {
+ UserLeave();
+ return NULL;
+ }
+
+ ret = CurIcon->head.h;
+
+ if(CurIcon->CURSORF_flags & CURSORF_ACON)
+ {
+ PACON AniCurIcon = (PACON)CurIcon;
+ if(istep >= AniCurIcon->cicur)
+ {
+ UserDereferenceObject(CurIcon);
+ UserLeave();
+ return NULL;
+ }
+ jiffies = AniCurIcon->ajifRate[istep];
+ steps = AniCurIcon->cicur;
+ ret = AniCurIcon->aspcur[AniCurIcon->aicur[istep]]->head.h;
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(rate_jiffies, sizeof(INT), 1);
+ ProbeForWrite(num_steps, sizeof(DWORD), 1);
+ *rate_jiffies = jiffies;
+ *num_steps = steps;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (!NT_SUCCESS(Status))
+ {
+ WARN("Status: 0x%08x.\n", Status);
+ SetLastNtError(Status);
+ ret = NULL;
+ }
+
+ UserDereferenceObject(CurIcon);
+ UserLeave();
+
+ TRACE("Leaving NtUserGetCursorFrameInfo, ret = 0x%08x\n", ret);
+
+ return ret;
+}
+
/* EOF */