* 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 PPAGED_LOOKASIDE_LIST pgProcessLookasideList;
-static LIST_ENTRY gCurIconList;
-
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;
- gSysCursorInfo.LastBtnDown = 0;
- gSysCursorInfo.CurrentCursorObject = NULL;
- gSysCursorInfo.ShowingCursor = -1;
- gSysCursorInfo.ClickLockActive = FALSE;
- gSysCursorInfo.ClickLockTime = 0;
+ gSysCursorInfo.Enabled = FALSE;
+ gSysCursorInfo.ButtonsDown = 0;
+ gSysCursorInfo.bClipped = FALSE;
+ gSysCursorInfo.LastBtnDown = 0;
+ gSysCursorInfo.CurrentCursorObject = NULL;
+ gSysCursorInfo.ShowingCursor = -1;
+ gSysCursorInfo.ClickLockActive = FALSE;
+ gSysCursorInfo.ClickLockTime = 0;
return TRUE;
}
return &gSysCursorInfo;
}
+FORCEINLINE
+BOOL
+is_icon(PCURICON_OBJECT object)
+{
+ return MAKEINTRESOURCE(object->rt) == RT_ICON;
+}
+
/* This function creates a reference for the object! */
PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
{
return NULL;
}
- CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, otCursorIcon);
+ if(UserObjectInDestroy(hCurIcon))
+ {
+ ERR("Requesting destroyed cursor.\n");
+ EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
+ return NULL;
+ }
+
+ CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR);
if (!CurIcon)
{
/* We never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
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)
-{
- PPROCESSINFO Win32Process;
- PCURICON_PROCESS Current;
-
- Win32Process = PsGetCurrentProcessWin32Process();
-
- LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
- {
- if (Current->Process == Win32Process)
- {
- /* Already registered for this process */
- return TRUE;
- }
- }
-
- /* Not registered yet */
- Current = ExAllocateFromPagedLookasideList(pgProcessLookasideList);
- if (NULL == Current)
- {
- return FALSE;
- }
- InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
- Current->Process = Win32Process;
-
- return TRUE;
-}
-
-static
-PCURICON_OBJECT
-FASTCALL
-IntFindExistingCurIconObject(
- PUNICODE_STRING pustrModule,
- PUNICODE_STRING pustrRsrc,
- FINDEXISTINGCURICONPARAM* param)
-{
- PCURICON_OBJECT CurIcon;
-
- LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
- {
- /* See if we are looking for an icon or a cursor */
- if(CurIcon->bIcon != param->bIcon)
- continue;
- /* See if module names match */
- if(RtlCompareUnicodeString(pustrModule, &CurIcon->ustrModule, TRUE) == 0)
- {
- /* They do. Now see if this is the same resource */
- if(IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer) && IS_INTRESOURCE(pustrRsrc->Buffer))
- {
- if(CurIcon->ustrRsrc.Buffer != pustrRsrc->Buffer)
- continue;
- }
- else if(IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer) || IS_INTRESOURCE(pustrRsrc->Buffer))
- continue;
- else if(RtlCompareUnicodeString(pustrRsrc, &CurIcon->ustrRsrc, TRUE) != 0)
- continue;
-
- if ((param->cx == CurIcon->Size.cx) &&(param->cy == CurIcon->Size.cy))
- {
- if (! ReferenceCurIconByProcess(CurIcon))
- {
- return NULL;
- }
-
- return CurIcon;
- }
- }
- }
-
- return NULL;
-}
-
-PCURICON_OBJECT
-IntCreateCurIconHandle(DWORD dwNumber)
+HANDLE
+IntCreateCurIconHandle(BOOLEAN Animated)
{
PCURICON_OBJECT CurIcon;
- BOOLEAN bIcon = dwNumber == 0;
HANDLE hCurIcon;
-
- if(dwNumber == 0)
- dwNumber = 1;
- CurIcon = UserCreateObject(gHandleTable, NULL, NULL, &hCurIcon, otCursorIcon, FIELD_OFFSET(CURICON_OBJECT, aFrame[dwNumber]));
+ CurIcon = UserCreateObject(
+ gHandleTable,
+ NULL,
+ NULL,
+ &hCurIcon,
+ TYPE_CURSOR,
+ Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT));
if (!CurIcon)
{
return FALSE;
}
- CurIcon->Self = hCurIcon;
- CurIcon->bIcon = bIcon;
- InitializeListHead(&CurIcon->ProcessList);
-
- if (! ReferenceCurIconByProcess(CurIcon))
- {
- ERR("Failed to add process\n");
- UserDeleteObject(hCurIcon, otCursorIcon);
- UserDereferenceObject(CurIcon);
- return NULL;
- }
-
- InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
+ UserDereferenceObject(CurIcon);
- return CurIcon;
+ return hCurIcon;
}
BOOLEAN FASTCALL
-IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi, BOOLEAN bForce)
+IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, BOOLEAN bForce)
{
- PSYSTEM_CURSORINFO CurInfo;
- HBITMAP bmpMask, bmpColor, bmpAlpha;
- BOOLEAN Ret, bListEmpty, bFound = FALSE;
- PCURICON_PROCESS Current = NULL;
-
- /* For handles created without any data (error handling) */
- if(IsListEmpty(&CurIcon->ProcessList))
- goto emptyList;
-
- /* 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(CurIcon->CURSORF_flags & CURSORF_CURRENT)
{
- if (Current->Process == ppi)
- {
- bFound = TRUE;
- bListEmpty = RemoveEntryList(&Current->ListEntry);
- break;
- }
+ /* Mark the object as destroyed, and fail, as per tests */
+ TRACE("Cursor is current, marking as destroyed.\n");
+ UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
+ return FALSE;
}
-
- if(!bFound)
+
+ if(CurIcon->head.ppi != PsGetCurrentProcessWin32Process())
{
- /* This object doesn't belong to this process */
- EngSetLastError(ERROR_INVALID_HANDLE);
- /* Caller expects us to dereference! */
+ /* This object doesn't belong to the current process */
+ WARN("Trying to delete foreign cursor!\n");
UserDereferenceObject(CurIcon);
+ EngSetLastError(ERROR_DESTROY_OBJECT_OF_OTHER_THREAD);
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)
+ /* Do not destroy it if it is shared. (And we're not forced to) */
+ if((CurIcon->CURSORF_flags & CURSORF_LRSHARED) && !bForce)
{
/* Tests show this is a valid call */
+ WARN("Trying to destroy shared cursor!\n");
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->CURSORF_flags & CURSORF_ACON))
{
- if(CurIcon->head.ppi == ppi)
+ HBITMAP bmpMask = CurIcon->hbmMask;
+ HBITMAP bmpColor = CurIcon->hbmColor;
+ HBITMAP bmpAlpha = CurIcon->hbmAlpha;
+
+ /* Delete bitmaps */
+ if (bmpMask)
{
- /* Set the first process of the list as owner */
- Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
- UserSetObjectOwner(CurIcon, otCursorIcon, Current->Process);
+ GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(bmpMask);
+ CurIcon->hbmMask = NULL;
+ }
+ if (bmpColor)
+ {
+ 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);
-
- CurInfo = IntGetSysCursorInfo();
-
- if (CurInfo->CurrentCursorObject == CurIcon)
+ else
{
- /* Hide the cursor if we're destroying the current cursor */
- UserSetCursor(NULL, TRUE);
- }
+ PACON AniCurIcon = (PACON)CurIcon;
+ UINT i;
- bmpMask = CurIcon->aFrame[0].hbmMask;
- bmpColor = CurIcon->aFrame[0].hbmColor;
- bmpAlpha = CurIcon->aFrame[0].hbmAlpha;
-
- /* Delete bitmaps */
- if (bmpMask)
- {
- GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(bmpMask);
- CurIcon->aFrame[0].hbmMask = NULL;
+ for(i = 0; i < AniCurIcon->cpcur; i++)
+ IntDestroyCurIconObject(AniCurIcon->aspcur[i], TRUE);
+ ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
}
- if (bmpColor)
- {
- GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(bmpColor);
- CurIcon->aFrame[0].hbmColor = NULL;
- }
- if (bmpAlpha)
+
+ if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
{
- GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(bmpAlpha);
- CurIcon->aFrame[0].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->ustrRsrc.Buffer))
- ExFreePoolWithTag(CurIcon->ustrRsrc.Buffer, TAG_STRING);
- if(CurIcon->ustrModule.Buffer)
- ReleaseCapturedUnicodeString(&CurIcon->ustrModule, UserMode);
- /* We were given a pointer, no need to keep the reference anylonger! */
+ /* We were given a pointer, no need to keep the reference any longer! */
UserDereferenceObject(CurIcon);
- Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
-
- return Ret;
+ return UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
}
VOID FASTCALL
IntCleanupCurIcons(struct _EPROCESS *Process, 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;
+ /* One ref for the handle, one for the list,
+ * and potentially one from an other process via SetCursor */
+ ASSERT(CurIcon->head.cLockObj <= 3);
+ IntDestroyCurIconObject(CurIcon, TRUE);
}
}
/* 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 = CurIcon->bIcon;
- ii.xHotspot = CurIcon->ptlHotspot.x;
- ii.yHotspot = CurIcon->ptlHotspot.y;
+ ii.fIcon = is_icon(FrameCurIcon);
+ ii.xHotspot = FrameCurIcon->xHotspot;
+ ii.yHotspot = FrameCurIcon->yHotspot;
/* Copy bitmaps */
- ii.hbmMask = BITMAP_CopyBitmap(CurIcon->aFrame[0].hbmMask);
+ ii.hbmMask = BITMAP_CopyBitmap(FrameCurIcon->hbmMask);
GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED);
- ii.hbmColor = BITMAP_CopyBitmap(CurIcon->aFrame[0].hbmColor);
+ ii.hbmColor = BITMAP_CopyBitmap(FrameCurIcon->hbmColor);
GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED);
-
- if (pbpp)
- {
- PSURFACE psurfBmp;
-
- psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmColor);
- if (psurfBmp)
- {
- colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
- SURFACE_ShareUnlockSurface(psurfBmp);
- }
- }
+ 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->ustrRsrc.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->ustrRsrc.Buffer))
+ if (IS_INTRESOURCE(CurIcon->strName.Buffer))
+ {
+ lpResName->Buffer = CurIcon->strName.Buffer;
+ lpResName->Length = 0;
+ }
+ else if (lpResName->MaximumLength < CurIcon->strName.Length)
{
- lpResName->Buffer = CurIcon->ustrRsrc.Buffer;
lpResName->Length = 0;
}
else
{
- lpResName->Length = min(lpResName->MaximumLength, CurIcon->ustrRsrc.Length);
- RtlCopyMemory(lpResName->Buffer, CurIcon->ustrRsrc.Buffer, lpResName->Length);
+ ProbeForWrite(lpResName->Buffer, lpResName->MaximumLength * sizeof(WCHAR), 1);
+ RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, lpResName->Length);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
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);
- RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
+ *plcx = CurIcon->cx;
ProbeForWrite(plcy, sizeof(LONG), 1);
- RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
+ *plcy = CurIcon->cy;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
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;
RETURN(FALSE);
}
- ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process(), bForce);
+ ret = IntDestroyCurIconObject(CurIcon, bForce);
/* Note: IntDestroyCurIconObject will remove our reference for us! */
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
{
ProbeForRead(param, sizeof(*param), 1);
- paramSafe = *param;
+ RtlCopyMemory(¶mSafe, param, sizeof(paramSafe));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
}
_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;
}
EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
goto leave;
}
+ pcurNew->CURSORF_flags |= CURSORF_CURRENT;
}
else
{
pcurOld = UserSetCursor(pcurNew, FALSE);
if (pcurOld)
{
- hOldCursor = (HCURSOR)pcurOld->Self;
- UserDereferenceObject(pcurOld);
+ hOldCursor = pcurOld->head.h;
+ pcurOld->CURSORF_flags &= ~CURSORF_CURRENT;
+ if(UserObjectInDestroy(hOldCursor))
+ {
+ /* Destroy it once and for all */
+ IntDestroyCurIconObject(pcurOld, TRUE);
+ hOldCursor = NULL;
+ }
+ else
+ {
+ UserDereferenceObject(pcurOld);
+ }
}
leave:
/*
- * @implemented
+ * @unimplemented
*/
BOOL
APIENTRY
HANDLE hCurIcon,
PICONINFO UnsafeIconInfo)
{
- PCURICON_OBJECT CurIcon;
- ICONINFO IconInfo;
- PSURFACE psurfBmp;
- NTSTATUS Status;
- BOOL Ret = FALSE;
- DECLARE_RETURN(BOOL);
-
- TRACE("Enter NtUserSetCursorContents\n");
- UserEnterExclusive();
-
- if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
- {
- RETURN(FALSE);
- }
-
- /* Copy fields */
- Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- goto done;
- }
-
-#if 0
- /* Check if we get valid information */
- if(IconInfo.fIcon != CurInfo->bIcon)
- {
- EngSetLastError(ERROR_INVALID_PARAMETER);
- goto done;
- }
-#endif
-
- /* Delete old bitmaps */
- if (CurIcon->aFrame[0].hbmColor)
- GreDeleteObject(CurIcon->aFrame[0].hbmColor);
- if (CurIcon->aFrame[0].hbmMask)
- GreDeleteObject(CurIcon->aFrame[0].hbmMask);
- if(CurIcon->aFrame[0].hbmAlpha)
- GreDeleteObject(CurIcon->aFrame[0].hbmAlpha);
-
- /* Set fields */
- CurIcon->bIcon = IconInfo.fIcon;
- CurIcon->ptlHotspot.x = IconInfo.xHotspot;
- CurIcon->ptlHotspot.y = IconInfo.yHotspot;
- CurIcon->aFrame[0].hbmMask = IconInfo.hbmMask;
- CurIcon->aFrame[0].hbmColor = IconInfo.hbmColor;
- CurIcon->aFrame[0].hbmAlpha = NULL;
-
- if (IconInfo.hbmColor)
- {
- BOOLEAN bAlpha = FALSE;
- psurfBmp = SURFACE_ShareLockSurface(IconInfo.hbmColor);
- if (!psurfBmp)
- goto done;
- CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
- CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
-
- /* 32bpp bitmap is likely to have an alpha channel */
- if(psurfBmp->SurfObj.iBitmapFormat == BMF_32BPP)
- {
- PFN_DIB_GetPixel fn_GetPixel = DibFunctionsForBitmapFormat[BMF_32BPP].DIB_GetPixel;
- INT i, j;
-
- fn_GetPixel = DibFunctionsForBitmapFormat[BMF_32BPP].DIB_GetPixel;
- for (i = 0; i < psurfBmp->SurfObj.sizlBitmap.cx; i++)
- {
- for (j = 0; j < psurfBmp->SurfObj.sizlBitmap.cy; j++)
- {
- bAlpha = ((BYTE)(fn_GetPixel(&psurfBmp->SurfObj, i, j) >> 24)) != 0;
- if (bAlpha)
- break;
- }
- if (bAlpha)
- break;
- }
- }
- /* We're done with this one */
- SURFACE_ShareUnlockSurface(psurfBmp);
- GreSetObjectOwner(IconInfo.hbmColor, GDI_OBJ_HMGR_PUBLIC);
-
- if(bAlpha)
- {
- UCHAR Alpha;
- PUCHAR ptr;
- INT i, j;
- /* Copy the bitmap */
- CurIcon->aFrame[0].hbmAlpha = BITMAP_CopyBitmap(IconInfo.hbmColor);
- if(!CurIcon->aFrame[0].hbmAlpha)
- {
- ERR("BITMAP_CopyBitmap failed!");
- goto done;
- }
-
- psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmAlpha);
- if(!psurfBmp)
- {
- ERR("SURFACE_LockSurface failed!\n");
- goto done;
- }
-
- /* Premultiply with the alpha channel value */
- for (i = 0; i < psurfBmp->SurfObj.sizlBitmap.cy; i++)
- {
- ptr = (PBYTE)psurfBmp->SurfObj.pvScan0 + i*psurfBmp->SurfObj.lDelta;
- for (j = 0; j < psurfBmp->SurfObj.sizlBitmap.cx; j++)
- {
- Alpha = ptr[3];
- ptr[0] = (ptr[0] * Alpha) / 0xff;
- ptr[1] = (ptr[1] * Alpha) / 0xff;
- ptr[2] = (ptr[2] * Alpha) / 0xff;
- ptr += 4;
- }
- }
- SURFACE_ShareUnlockSurface(psurfBmp);
- GreSetObjectOwner(CurIcon->aFrame[0].hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
- }
- }
- else
- {
- psurfBmp = SURFACE_ShareLockSurface(IconInfo.hbmMask);
- if (!psurfBmp)
- goto done;
-
- CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
- CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
-
- SURFACE_ShareUnlockSurface(psurfBmp);
- }
- GreSetObjectOwner(IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
-
- Ret = TRUE;
-
-done:
-
- if (CurIcon)
- {
- UserDereferenceObject(CurIcon);
- }
- RETURN(Ret);
-
-CLEANUP:
- TRACE("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
- UserLeave();
- END_CLEANUP;
+ FIXME(" is UNIMPLEMENTED.\n");
+ return FALSE;
}
_In_ HCURSOR Handle,
_In_opt_ PUNICODE_STRING pustrModule,
_In_opt_ PUNICODE_STRING pustrRsrc,
- _In_ PICONINFO pIconInfo)
+ _In_ const CURSORDATA* pCursorData)
{
PCURICON_OBJECT CurIcon;
- PSURFACE psurfBmp;
NTSTATUS Status = STATUS_SUCCESS;
- BOOL Ret = FALSE;
- ICONINFO ii;
+ 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(pIconInfo, sizeof(ICONINFO), 1);
- ii = *pIconInfo;
+ ProbeForRead(pCursorData, sizeof(*pCursorData), 1);
+ 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;
}
-
- /* This is probably not what windows does, but consistency checks can't hurt */
- if(CurIcon->bIcon != ii.fIcon)
+
+ if(IsAnim)
{
- EngSetLastError(ERROR_INVALID_PARAMETER);
- goto done;
+ 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++;
+ }
}
- CurIcon->ptlHotspot.x = ii.xHotspot;
- CurIcon->ptlHotspot.y = ii.yHotspot;
- if(!ii.hbmMask)
+ if(CurIcon->CURSORF_flags & CURSORF_LRSHARED)
{
- EngSetLastError(ERROR_INVALID_PARAMETER);
- 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;
+ }
}
-
- CurIcon->aFrame[0].hbmMask = BITMAP_CopyBitmap(ii.hbmMask);
- if(!CurIcon->aFrame[0].hbmMask)
- goto done;
- if(ii.hbmColor)
+ if(!CurIcon->hbmMask)
{
- CurIcon->aFrame[0].hbmColor = BITMAP_CopyBitmap(ii.hbmColor);
- if(!CurIcon->aFrame[0].hbmColor)
- goto done;
+ ERR("NtUserSetCursorIconData was got no hbmMask.\n");
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
}
- if (CurIcon->aFrame[0].hbmColor)
- {
- psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmColor);
- if(!psurfBmp)
- goto done;
-
- CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
- CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
- SURFACE_ShareUnlockSurface(psurfBmp);
- GreSetObjectOwner(CurIcon->aFrame[0].hbmColor, GDI_OBJ_HMGR_PUBLIC);
- }
- else
- {
- psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmMask);
- if(!psurfBmp)
- goto done;
+ GreSetObjectOwner(CurIcon->hbmMask, GDI_OBJ_HMGR_PUBLIC);
- CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
- CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy/2;
- SURFACE_ShareUnlockSurface(psurfBmp);
- }
- GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_PUBLIC);
+ if(CurIcon->hbmColor)
+ GreSetObjectOwner(CurIcon->hbmColor, GDI_OBJ_HMGR_PUBLIC);
- if(pustrModule)
+ if(CurIcon->hbmAlpha)
+ GreSetObjectOwner(CurIcon->hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
+
+ if(IsShared)
{
- /* We use this convenient function, because INTRESOURCEs and ATOMs are the same */
- Status = ProbeAndCaptureUnicodeStringOrAtom(&CurIcon->ustrRsrc, pustrRsrc);
- if(!NT_SUCCESS(Status))
- goto done;
- Status = ProbeAndCaptureUnicodeString(&CurIcon->ustrModule, UserMode, pustrModule);
- if(!NT_SUCCESS(Status))
- goto done;
+ /* 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:
- UserDereferenceObject(CurIcon);
- if(!Ret)
+ if(!Ret && IsShared)
{
- if (CurIcon->aFrame[0].hbmMask)
- {
- GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(CurIcon->aFrame[0].hbmMask);
- CurIcon->aFrame[0].hbmMask = NULL;
- }
- if (CurIcon->aFrame[0].hbmColor)
+ if(!IS_INTRESOURCE(CurIcon->strName.Buffer))
+ ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
+ }
+
+ if(!Ret && IsAnim)
+ {
+ PACON AniCurIcon = (PACON)CurIcon;
+ for(i = 0; i < numFrames; i++)
{
- GreSetObjectOwner(CurIcon->aFrame[0].hbmColor, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(CurIcon->aFrame[0].hbmColor);
- CurIcon->aFrame[0].hbmColor = NULL;
+ if(AniCurIcon->aspcur[i])
+ IntDestroyCurIconObject(AniCurIcon->aspcur[i], TRUE);
}
- if(!IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer))
- ExFreePoolWithTag(CurIcon->ustrRsrc.Buffer, TAG_STRING);
- if(CurIcon->ustrModule.Buffer)
- ReleaseCapturedUnicodeString(&CurIcon->ustrModule, UserMode);
+ 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;
}
- hbmMask = pIcon->aFrame[0].hbmMask;
- hbmColor = pIcon->aFrame[0].hbmColor;
- hbmAlpha = pIcon->aFrame[0].hbmAlpha;
-
- if (istepIfAniCur)
- ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
+ 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;
/*
* Get our objects.
if(hbmColor == NULL)
{
/* But then the mask bitmap must have the information in it's bottom half */
- ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->Size.cy);
+ ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->cy);
psurfColor = NULL;
}
else if ((psurfColor = SURFACE_ShareLockSurface(hbmColor)) == NULL)
}
/* Set source rect */
- RECTL_vSetRect(&rcSrc, 0, 0, pIcon->Size.cx, pIcon->Size.cy);
+ RECTL_vSetRect(&rcSrc, 0, 0, pIcon->cx, pIcon->cy);
/* Fix width parameter, if needed */
if (!cxWidth)
{
if(diFlags & DI_DEFAULTSIZE)
- cxWidth = pIcon->bIcon ?
+ cxWidth = is_icon(pIcon) ?
UserGetSystemMetrics(SM_CXICON) : UserGetSystemMetrics(SM_CXCURSOR);
else
- cxWidth = pIcon->Size.cx;
+ cxWidth = pIcon->cx;
}
/* Fix height parameter, if needed */
if (!cyHeight)
{
if(diFlags & DI_DEFAULTSIZE)
- cyHeight = pIcon->bIcon ?
+ cyHeight = is_icon(pIcon) ?
UserGetSystemMetrics(SM_CYICON) : UserGetSystemMetrics(SM_CYCURSOR);
else
- cyHeight = pIcon->Size.cy;
+ cyHeight = pIcon->cy;
}
/* Should we render off-screen? */
}
/* Now do the rendering */
- if(hbmAlpha && (diFlags & DI_IMAGE))
+ if(hbmAlpha && ((diFlags & DI_NORMAL) == DI_NORMAL))
{
BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
PSURFACE psurf = NULL;
{
/* Mask bitmap holds the information in its bottom half */
DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY;
- RECTL_vOffsetRect(&rcSrc, 0, pIcon->Size.cy);
+ RECTL_vOffsetRect(&rcSrc, 0, pIcon->cy);
EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
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 */