Author: jgardou
Date: Wed Nov 13 20:06:01 2013
New Revision: 60978
URL:
http://svn.reactos.org/svn/reactos?rev=60978&view=rev
Log:
[WIN32SS]
- Commit everything I got on new cursor/icon implementation
- Implement loading animated cursors (no display yet)
- Get rid of this m:n relation between cursors and processes. (ie. proper implementation
of LR_SHARED)
- Get rid of the global linked list of cursors (ditto)
- Use atoms instead of copying the module name into the object. (aka stop using non paged
pool for nothing)
- Misc fixes
Modified:
trunk/reactos/win32ss/include/ntuser.h
trunk/reactos/win32ss/include/ntusrtyp.h
trunk/reactos/win32ss/user/ntuser/class.c
trunk/reactos/win32ss/user/ntuser/cursoricon.c
trunk/reactos/win32ss/user/ntuser/cursoricon.h
trunk/reactos/win32ss/user/ntuser/cursoricon_new.c
trunk/reactos/win32ss/user/ntuser/ntstubs.c
trunk/reactos/win32ss/user/ntuser/simplecall.c
trunk/reactos/win32ss/user/ntuser/win32.h
trunk/reactos/win32ss/user/user32/misc/stubs.c
trunk/reactos/win32ss/user/user32/windows/cursoricon.c
trunk/reactos/win32ss/user/user32/windows/cursoricon_new.c
Modified: trunk/reactos/win32ss/include/ntuser.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/include/ntuser.h?r…
==============================================================================
--- trunk/reactos/win32ss/include/ntuser.h [iso-8859-1] (original)
+++ trunk/reactos/win32ss/include/ntuser.h [iso-8859-1] Wed Nov 13 20:06:01 2013
@@ -2000,8 +2000,8 @@
NtUserGetCursorFrameInfo(
HCURSOR hCursor,
DWORD istep,
- PDWORD rate_jiffies,
- INT *num_steps);
+ INT* rate_jiffies,
+ DWORD* num_steps);
BOOL
NTAPI
@@ -2791,7 +2791,7 @@
_In_ HCURSOR hCursor,
_In_ PUNICODE_STRING pustrModule,
_In_ PUNICODE_STRING puSrcName,
- _In_ PCURSORDATA pCursorData);
+ _In_ const CURSORDATA* pCursorData);
typedef struct _tagFINDEXISTINGCURICONPARAM
{
Modified: trunk/reactos/win32ss/include/ntusrtyp.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/include/ntusrtyp.h…
==============================================================================
--- trunk/reactos/win32ss/include/ntusrtyp.h [iso-8859-1] (original)
+++ trunk/reactos/win32ss/include/ntusrtyp.h [iso-8859-1] Wed Nov 13 20:06:01 2013
@@ -90,7 +90,7 @@
{ union
{
ICONRESDIR icon;
- CURSORDIR cursor;
+ CURSORRESDIR cursor;
} ResInfo;
WORD wPlanes;
WORD wBitCount;
Modified: trunk/reactos/win32ss/user/ntuser/class.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/class.…
==============================================================================
--- trunk/reactos/win32ss/user/ntuser/class.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/ntuser/class.c [iso-8859-1] Wed Nov 13 20:06:01 2013
@@ -1728,7 +1728,11 @@
}
//// Do this for now in anticipation of new cursor icon code.
+#ifndef NEW_CURSORICON
BOOLEAN FASTCALL IntDestroyCurIconObject(PCURICON_OBJECT, PPROCESSINFO);
+#else
+BOOLEAN FASTCALL IntDestroyCurIconObject(PCURICON_OBJECT, BOOLEAN);
+#endif
BOOL FASTCALL
IntClassDestroyIcon(HANDLE hCurIcon)
@@ -1742,8 +1746,13 @@
ERR("hCurIcon was not found!\n");
return FALSE;
}
+#ifndef NEW_CURSORICON
Ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process());
/* Note: IntDestroyCurIconObject will remove our reference for us! */
+#else
+ /* Note: IntDestroyCurIconObject will remove our reference for us! */
+ Ret = IntDestroyCurIconObject(CurIcon, TRUE);
+#endif
if (!Ret)
{
ERR("hCurIcon was not Destroyed!\n");
Modified: trunk/reactos/win32ss/user/ntuser/cursoricon.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/cursor…
==============================================================================
--- trunk/reactos/win32ss/user/ntuser/cursoricon.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/ntuser/cursoricon.c [iso-8859-1] Wed Nov 13 20:06:01 2013
@@ -203,7 +203,7 @@
return NULL;
}
-PCURICON_OBJECT
+HANDLE
IntCreateCurIconHandle(DWORD dwNumber)
{
PCURICON_OBJECT CurIcon;
@@ -220,7 +220,7 @@
CurIcon->Self = hCurIcon;
InitializeListHead(&CurIcon->ProcessList);
- if (! ReferenceCurIconByProcess(CurIcon))
+ if (!ReferenceCurIconByProcess(CurIcon))
{
ERR("Failed to add process\n");
UserDeleteObject(hCurIcon, TYPE_CURSOR);
@@ -230,7 +230,9 @@
InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
- return CurIcon;
+ UserDereferenceObject(CurIcon);
+
+ return hCurIcon;
}
BOOLEAN FASTCALL
@@ -1519,4 +1521,20 @@
return Ret;
}
+/*
+ * @unimplemented
+ */
+HCURSOR
+NTAPI
+NtUserGetCursorFrameInfo(
+ HCURSOR hCursor,
+ DWORD istep,
+ INT* rate_jiffies,
+ DWORD* num_steps)
+{
+ STUB
+
+ return 0;
+}
+
/* EOF */
Modified: trunk/reactos/win32ss/user/ntuser/cursoricon.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/cursor…
==============================================================================
--- trunk/reactos/win32ss/user/ntuser/cursoricon.h [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/ntuser/cursoricon.h [iso-8859-1] Wed Nov 13 20:06:01 2013
@@ -1,40 +1,53 @@
#pragma once
#define MAXCURICONHANDLES 4096
+
+#ifdef NEW_CURSORICON
+typedef struct _CURICON_OBJECT
+{
+ PROCMARKHEAD head;
+ struct _CURICON_OBJECT* pcurNext;
+ UNICODE_STRING strName;
+ USHORT atomModName;
+ USHORT rt;
+ ULONG CURSORF_flags;
+ SHORT xHotspot;
+ SHORT yHotspot;
+ HBITMAP hbmMask;
+ HBITMAP hbmColor;
+ HBITMAP hbmAlpha;
+ RECT rcBounds;
+ HBITMAP hbmUserAlpha;
+ ULONG bpp;
+ ULONG cx;
+ ULONG cy;
+} CURICON_OBJECT, *PCURICON_OBJECT;
+
+typedef struct tagACON
+{
+ PROCMARKHEAD head;
+ struct _CURICON_OBJECT* pcurNext;
+ UNICODE_STRING strName;
+ USHORT atomModName;
+ USHORT rt;
+ ULONG CURSORF_flags;
+ INT cpcur;
+ INT cicur;
+ PCURICON_OBJECT * aspcur;
+ DWORD * aicur;
+ INT * ajifRate;
+ INT iicur;
+} ACON, *PACON;
+
+C_ASSERT(FIELD_OFFSET(ACON, cpcur) == FIELD_OFFSET(CURICON_OBJECT, xHotspot));
+
+#else
typedef struct tagCURICON_PROCESS
{
LIST_ENTRY ListEntry;
PPROCESSINFO Process;
} CURICON_PROCESS, *PCURICON_PROCESS;
-
-#ifdef NEW_CURSORICON
-typedef struct _CURICON_OBJECT
-{
- PROCMARKHEAD head;
- struct _tagCURSOR* pcurNext;
- UNICODE_STRING strName;
- USHORT atomModName;
- USHORT rt;
- ULONG CURSORF_flags;
- SHORT xHotspot;
- SHORT yHotspot;
- HBITMAP hbmMask;
- HBITMAP hbmColor;
- HBITMAP hbmAlpha;
- RECT rcBounds;
- HBITMAP hbmUserAlpha;
- ULONG bpp;
- ULONG cx;
- ULONG cy;
-/* ReactOS specific, to be deleted */
- LIST_ENTRY ListEntry;
- HANDLE Self;
- LIST_ENTRY ProcessList;
- UNICODE_STRING ustrModule;
-} CURICON_OBJECT, *PCURICON_OBJECT;
-
-#else
typedef struct _CURICON_OBJECT
{
@@ -91,7 +104,7 @@
} SYSTEM_CURSORINFO, *PSYSTEM_CURSORINFO;
BOOL InitCursorImpl(VOID);
-PCURICON_OBJECT IntCreateCurIconHandle(DWORD dwNumber);
+HANDLE IntCreateCurIconHandle(BOOLEAN Anim);
VOID FASTCALL IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process);
BOOL UserDrawIconEx(HDC hDc, INT xLeft, INT yTop, PCURICON_OBJECT pIcon, INT cxWidth,
Modified: trunk/reactos/win32ss/user/ntuser/cursoricon_new.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/cursor…
==============================================================================
--- trunk/reactos/win32ss/user/ntuser/cursoricon_new.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/ntuser/cursoricon_new.c [iso-8859-1] Wed Nov 13 20:06:01
2013
@@ -17,37 +17,16 @@
* 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()
{
- 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;
@@ -84,6 +63,13 @@
return NULL;
}
+ if(UserObjectInDestroy(hCurIcon))
+ {
+ ERR("Requesting destroyed cursor.\n");
+ EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
+ return NULL;
+ }
+
CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR);
if (!CurIcon)
{
@@ -138,98 +124,19 @@
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(MAKEINTRESOURCE(CurIcon->rt) != (param->bIcon ? RT_ICON : RT_CURSOR))
- 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->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))
- {
- if (! ReferenceCurIconByProcess(CurIcon))
- {
- return NULL;
- }
-
- return CurIcon;
- }
- }
- }
-
- return NULL;
-}
-
-PCURICON_OBJECT
-IntCreateCurIconHandle(DWORD dwNumber)
+HANDLE
+IntCreateCurIconHandle(BOOLEAN Animated)
{
PCURICON_OBJECT CurIcon;
HANDLE hCurIcon;
-
- if(dwNumber == 0)
- dwNumber = 1;
-
- CurIcon = UserCreateObject(gHandleTable, NULL, NULL, &hCurIcon, TYPE_CURSOR,
sizeof(CURICON_OBJECT));
+
+ CurIcon = UserCreateObject(
+ gHandleTable,
+ NULL,
+ NULL,
+ &hCurIcon,
+ TYPE_CURSOR,
+ Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT));
if (!CurIcon)
{
@@ -237,134 +144,102 @@
return FALSE;
}
- CurIcon->Self = hCurIcon;
- InitializeListHead(&CurIcon->ProcessList);
-
- if (! ReferenceCurIconByProcess(CurIcon))
- {
- ERR("Failed to add process\n");
+ UserDereferenceObject(CurIcon);
+
+ return hCurIcon;
+}
+
+BOOLEAN FASTCALL
+IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, BOOLEAN bForce)
+{
+ if(CurIcon->CURSORF_flags & CURSORF_CURRENT)
+ {
+ /* Mark the object as destroyed, and fail, as per wine tests */
+ UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
+ return FALSE;
+ }
+
+ if(CurIcon->head.ppi != PsGetCurrentProcessWin32Process())
+ {
+ /* This object doesn't belong to the current process */
+ WARN("Trying to delete foreign cursor!\n");
UserDereferenceObject(CurIcon);
- UserDeleteObject(hCurIcon, TYPE_CURSOR);
- return NULL;
- }
-
- InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
-
- return CurIcon;
-}
-
-BOOLEAN FASTCALL
-IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi, BOOLEAN bForce)
-{
- HBITMAP bmpMask, bmpColor, bmpAlpha;
- BOOLEAN Ret, bListEmpty, bFound = FALSE;
- PCURICON_PROCESS Current = NULL;
-
- /* Check if this is the current cursor */
- if(CurIcon->CURSORF_flags & CURSORF_CURRENT)
- {
- UserDereferenceObject(CurIcon);
+ EngSetLastError(ERROR_DESTROY_OBJECT_OF_OTHER_THREAD);
return FALSE;
}
- /* 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 (Current->Process == ppi)
- {
- bFound = TRUE;
- bListEmpty = RemoveEntryList(&Current->ListEntry);
- break;
- }
- }
-
- 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)
+ /* 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->head.ppi == ppi)
- {
- /* Set the first process of the list as owner */
- Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS,
ListEntry);
- UserSetObjectOwner(CurIcon, TYPE_CURSOR, Current->Process);
- }
- 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)
- {
- GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(bmpColor);
- CurIcon->hbmColor = NULL;
- }
- if (bmpAlpha)
- {
- 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->ustrModule.Buffer)
- ReleaseCapturedUnicodeString(&CurIcon->ustrModule, UserMode);
-
- /* We were given a pointer, no need to keep the reference anylonger! */
+ if(!(CurIcon->CURSORF_flags & CURSORF_ACON))
+ {
+ HBITMAP bmpMask = CurIcon->hbmMask;
+ HBITMAP bmpColor = CurIcon->hbmColor;
+ HBITMAP bmpAlpha = CurIcon->hbmAlpha;
+
+ /* Delete bitmaps */
+ if (bmpMask)
+ {
+ 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;
+ }
+ }
+ else
+ {
+ PACON AniCurIcon = (PACON)CurIcon;
+ UINT i;
+
+ for(i = 0; i < AniCurIcon->cpcur; i++)
+ IntDestroyCurIconObject(AniCurIcon->aspcur[i], TRUE);
+ ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
+ }
+
+ if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
+ {
+ 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;
+ }
+
+ /* We were given a pointer, no need to keep the reference any longer! */
UserDereferenceObject(CurIcon);
- Ret = UserDeleteObject(CurIcon->Self, TYPE_CURSOR);
-
- 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)
- {
- UserReferenceObject(CurIcon);
- IntDestroyCurIconObject(CurIcon, Win32Process, TRUE);
+ while(Win32Process->pCursorCache)
+ {
+ CurIcon = Win32Process->pCursorCache;
+ Win32Process->pCursorCache = CurIcon->pcurNext;
+ ASSERT(CurIcon->head.cLockObj == 2);
+ IntDestroyCurIconObject(CurIcon, TRUE);
}
}
@@ -410,17 +285,24 @@
/* 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
@@ -439,63 +321,72 @@
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(lpResName)
- {
- if(!CurIcon->strName.Buffer)
- {
- EngSetLastError(ERROR_INVALID_HANDLE);
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
goto leave;
}
+ }
+
+ if (lpResName)
+ {
+ 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);
}
}
@@ -547,6 +438,15 @@
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);
@@ -597,7 +497,7 @@
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;
@@ -739,7 +639,7 @@
RETURN(FALSE);
}
- ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process(), bForce);
+ ret = IntDestroyCurIconObject(CurIcon, bForce);
/* Note: IntDestroyCurIconObject will remove our reference for us! */
RETURN(ret);
@@ -766,9 +666,23 @@
UNICODE_STRING ustrModuleSafe, ustrRsrcSafe;
FINDEXISTINGCURICONPARAM paramSafe;
NTSTATUS Status;
+ PPROCESSINFO pProcInfo = PsGetCurrentProcessWin32Process();
+ RTL_ATOM atomModName;
TRACE("Enter NtUserFindExistingCursorIcon\n");
+
+ _SEH2_TRY
+ {
+ ProbeForRead(param, sizeof(*param), 1);
+ RtlCopyMemory(¶mSafe, param, sizeof(paramSafe));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
/* Capture resource name (it can be an INTRESOURCE == ATOM) */
Status = ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrcSafe, pustrRsrc);
if(!NT_SUCCESS(Status))
@@ -776,28 +690,58 @@
Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
if(!NT_SUCCESS(Status))
goto done;
-
- _SEH2_TRY
- {
- ProbeForRead(param, sizeof(*param), 1);
- RtlCopyMemory(¶mSafe, param, sizeof(paramSafe));
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END
+ 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;
}
@@ -884,9 +828,18 @@
pcurOld = UserSetCursor(pcurNew, FALSE);
if (pcurOld)
{
- hOldCursor = (HCURSOR)pcurOld->Self;
+ hOldCursor = pcurOld->head.h;
pcurOld->CURSORF_flags &= ~CURSORF_CURRENT;
- UserDereferenceObject(pcurOld);
+ if(UserObjectInDestroy(hOldCursor))
+ {
+ /* Destroy it once and for all */
+ IntDestroyCurIconObject(pcurOld, TRUE);
+ hOldCursor = NULL;
+ }
+ else
+ {
+ UserDereferenceObject(pcurOld);
+ }
}
leave:
@@ -918,17 +871,16 @@
_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();
@@ -942,15 +894,49 @@
_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)
{
@@ -963,18 +949,42 @@
SetLastNtError(Status);
goto done;
}
-
- if(pustrModule)
- {
- /* 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;
- }
-
+
+ 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(CurIcon->CURSORF_flags & CURSORF_LRSHARED)
+ {
+ 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)
{
@@ -990,17 +1000,41 @@
if(CurIcon->hbmAlpha)
GreSetObjectOwner(CurIcon->hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
+
+ if(IsShared)
+ {
+ /* Update process cache in case of shared cursor */
+ UserReferenceObject(CurIcon);
+ PPROCESSINFO ppi = CurIcon->head.ppi;
+ 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], TRUE);
+ }
+ 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();
@@ -1044,12 +1078,20 @@
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.
@@ -1445,4 +1487,74 @@
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 */
Modified: trunk/reactos/win32ss/user/ntuser/ntstubs.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/ntstub…
==============================================================================
--- trunk/reactos/win32ss/user/ntuser/ntstubs.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/ntuser/ntstubs.c [iso-8859-1] Wed Nov 13 20:06:01 2013
@@ -1250,22 +1250,6 @@
/*
* @unimplemented
*/
-HCURSOR
-NTAPI
-NtUserGetCursorFrameInfo(
- HCURSOR hCursor,
- DWORD istep,
- PDWORD rate_jiffies,
- INT *num_steps)
-{
- STUB
-
- return 0;
-}
-
-/*
- * @unimplemented
- */
BOOL
APIENTRY
NtUserSetSystemCursor(
Modified: trunk/reactos/win32ss/user/ntuser/simplecall.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/simple…
==============================================================================
--- trunk/reactos/win32ss/user/ntuser/simplecall.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/ntuser/simplecall.c [iso-8859-1] Wed Nov 13 20:06:01 2013
@@ -237,17 +237,13 @@
case ONEPARAM_ROUTINE_CREATEEMPTYCUROBJECT:
{
- PCURICON_OBJECT CurIcon;
DWORD_PTR Result ;
- if (!(CurIcon = IntCreateCurIconHandle((DWORD)Param)))
+ if (!(Result = (DWORD_PTR)IntCreateCurIconHandle((DWORD)Param)))
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
RETURN(0);
}
-
- Result = (DWORD_PTR)CurIcon->Self;
- UserDereferenceObject(CurIcon);
RETURN(Result);
}
Modified: trunk/reactos/win32ss/user/ntuser/win32.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/win32.…
==============================================================================
--- trunk/reactos/win32ss/user/ntuser/win32.h [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/ntuser/win32.h [iso-8859-1] Wed Nov 13 20:06:01 2013
@@ -235,6 +235,7 @@
ACCESS_MASK amwinsta;
DWORD dwHotkey;
HMONITOR hMonitor;
+ struct _CURICON_OBJECT* pCursorCache;
LUID luidSession;
USERSTARTUPINFO usi;
DWORD dwLayout;
Modified: trunk/reactos/win32ss/user/user32/misc/stubs.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/user32/misc/s…
==============================================================================
--- trunk/reactos/win32ss/user/user32/misc/stubs.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/user32/misc/stubs.c [iso-8859-1] Wed Nov 13 20:06:01 2013
@@ -538,15 +538,6 @@
{
UNIMPLEMENTED;
return FALSE;
-}
-
-HCURSOR
-WINAPI
-GetCursorFrameInfo(HCURSOR hCursor, LPCWSTR name, DWORD istep, PDWORD rate_jiffies, INT
*num_steps)
-{
- if (hCursor) return NtUserGetCursorFrameInfo(hCursor, istep, rate_jiffies,
num_steps);
-
- return LoadImageW( NULL, name, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE );
}
BOOL
Modified: trunk/reactos/win32ss/user/user32/windows/cursoricon.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/user32/window…
==============================================================================
--- trunk/reactos/win32ss/user/user32/windows/cursoricon.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/user32/windows/cursoricon.c [iso-8859-1] Wed Nov 13
20:06:01 2013
@@ -2207,3 +2207,10 @@
return ZwCallbackReturn(&Result, sizeof(HANDLE), STATUS_SUCCESS);
}
+HCURSOR
+WINAPI
+GetCursorFrameInfo(HCURSOR hCursor, DWORD reserved, DWORD istep, PINT rate_jiffies, DWORD
*num_steps)
+{
+ return NtUserGetCursorFrameInfo(hCursor, istep, rate_jiffies, num_steps);
+}
+
Modified: trunk/reactos/win32ss/user/user32/windows/cursoricon_new.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/user32/window…
==============================================================================
--- trunk/reactos/win32ss/user/user32/windows/cursoricon_new.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/user32/windows/cursoricon_new.c [iso-8859-1] Wed Nov 13
20:06:01 2013
@@ -14,6 +14,10 @@
WINE_DECLARE_DEBUG_CHANNEL(icon);
//WINE_DECLARE_DEBUG_CHANNEL(resource);
+/* We only use Wide string functions */
+#undef MAKEINTRESOURCE
+#define MAKEINTRESOURCE MAKEINTRESOURCEW
+
/************* USER32 INTERNAL FUNCTIONS **********/
/* This callback routine is called directly after switching to gui mode */
@@ -28,14 +32,14 @@
if(*DefaultCursor)
{
/* set default cursor */
- hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
+ hCursor = LoadCursorW(0, IDC_ARROW);
SetCursor(hCursor);
}
else
{
/* FIXME load system cursor scheme */
SetCursor(0);
- hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
+ hCursor = LoadCursorW(0, IDC_ARROW);
SetCursor(hCursor);
}
@@ -303,6 +307,113 @@
TRACE("Returning 0x%08x.\n", alpha);
return alpha;
}
+
+#include "pshpack1.h"
+
+typedef struct {
+ BYTE bWidth;
+ BYTE bHeight;
+ BYTE bColorCount;
+ BYTE bReserved;
+ WORD xHotspot;
+ WORD yHotspot;
+ DWORD dwDIBSize;
+ DWORD dwDIBOffset;
+} CURSORICONFILEDIRENTRY;
+
+typedef struct
+{
+ WORD idReserved;
+ WORD idType;
+ WORD idCount;
+ CURSORICONFILEDIRENTRY idEntries[1];
+} CURSORICONFILEDIR;
+
+#include "poppack.h"
+
+static
+const CURSORICONFILEDIRENTRY*
+get_best_icon_file_entry(
+ _In_ const CURSORICONFILEDIR* dir,
+ _In_ DWORD dwFileSize,
+ _In_ int cxDesired,
+ _In_ int cyDesired,
+ _In_ BOOL bIcon,
+ _In_ DWORD fuLoad
+)
+{
+ CURSORICONDIR* fakeDir;
+ CURSORICONDIRENTRY* fakeEntry;
+ WORD i;
+ const CURSORICONFILEDIRENTRY* entry;
+
+ if ( dwFileSize < sizeof(*dir) )
+ return NULL;
+
+ if ( dwFileSize < (sizeof(*dir) +
sizeof(dir->idEntries[0])*(dir->idCount-1)) )
+ return NULL;
+
+ /*
+ * Cute little hack:
+ * We allocate a buffer, fake it as if it was a pointer to a resource in a module,
+ * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
+ */
+ fakeDir = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR,
idEntries[dir->idCount]));
+ if(!fakeDir)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
+ }
+ fakeDir->idReserved = 0;
+ fakeDir->idType = dir->idType;
+ fakeDir->idCount = dir->idCount;
+ for(i = 0; i<dir->idCount; i++)
+ {
+ fakeEntry = &fakeDir->idEntries[i];
+ entry = &dir->idEntries[i];
+ /* Take this as an occasion to perform a size check */
+ if((entry->dwDIBOffset + entry->dwDIBSize) > dwFileSize)
+ {
+ ERR("Corrupted icon file?.\n");
+ HeapFree(GetProcessHeap(), 0, fakeDir);
+ return NULL;
+ }
+ /* File icon/cursors are not like resource ones */
+ if(bIcon)
+ {
+ fakeEntry->ResInfo.icon.bWidth = entry->bWidth;
+ fakeEntry->ResInfo.icon.bHeight = entry->bHeight;
+ fakeEntry->ResInfo.icon.bColorCount = 0;
+ fakeEntry->ResInfo.icon.bReserved = 0;
+ }
+ else
+ {
+ fakeEntry->ResInfo.cursor.wWidth = entry->bWidth;
+ fakeEntry->ResInfo.cursor.wHeight = entry->bHeight;
+ }
+ /* Let's assume there's always one plane */
+ fakeEntry->wPlanes = 1;
+ /* We must get the bitcount from the BITMAPINFOHEADER itself */
+ fakeEntry->wBitCount = ((BITMAPINFOHEADER *)((char *)dir +
entry->dwDIBOffset))->biBitCount;
+ fakeEntry->dwBytesInRes = entry->dwDIBSize;
+ fakeEntry->wResId = i + 1;
+ }
+
+ /* Now call LookupIconIdFromResourceEx */
+ i = LookupIconIdFromDirectoryEx((PBYTE)fakeDir, bIcon, cxDesired, cyDesired, fuLoad
& LR_MONOCHROME);
+ /* We don't need this anymore */
+ HeapFree(GetProcessHeap(), 0, fakeDir);
+ if(i == 0)
+ {
+ WARN("Unable to get a fit entry index.\n");
+ return NULL;
+ }
+
+ /* We found it */
+ return &dir->idEntries[i-1];
+}
+
+
/************* IMPLEMENTATION CORE ****************/
@@ -509,6 +620,257 @@
return TRUE;
}
+
+#define RIFF_FOURCC( c0, c1, c2, c3 ) \
+ ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
+ ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
+
+#define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
+#define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
+#define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
+#define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
+#define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
+#define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
+#define ANI_rate_ID RIFF_FOURCC('r', 'a', 't', 'e')
+
+#define ANI_FLAG_ICON 0x1
+#define ANI_FLAG_SEQUENCE 0x2
+
+#include <pshpack1.h>
+typedef struct {
+ DWORD header_size;
+ DWORD num_frames;
+ DWORD num_steps;
+ DWORD width;
+ DWORD height;
+ DWORD bpp;
+ DWORD num_planes;
+ DWORD display_rate;
+ DWORD flags;
+} ani_header;
+
+typedef struct {
+ DWORD data_size;
+ const unsigned char *data;
+} riff_chunk_t;
+#include <poppack.h>
+
+static void dump_ani_header( const ani_header *header )
+{
+ TRACE(" header size: %d\n", header->header_size);
+ TRACE(" frames: %d\n", header->num_frames);
+ TRACE(" steps: %d\n", header->num_steps);
+ TRACE(" width: %d\n", header->width);
+ TRACE(" height: %d\n", header->height);
+ TRACE(" bpp: %d\n", header->bpp);
+ TRACE(" planes: %d\n", header->num_planes);
+ TRACE(" display rate: %d\n", header->display_rate);
+ TRACE(" flags: 0x%08x\n", header->flags);
+}
+
+/* Find an animated cursor chunk, given its type and ID */
+static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_t
*parent_chunk, riff_chunk_t *chunk )
+{
+ const unsigned char *ptr = parent_chunk->data;
+ const unsigned char *end = parent_chunk->data + (parent_chunk->data_size - (2 *
sizeof(DWORD)));
+
+ if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) end -= sizeof(DWORD);
+
+ while (ptr < end)
+ {
+ if ((!chunk_type && *(const DWORD *)ptr == chunk_id )
+ || (chunk_type && *(const DWORD *)ptr == chunk_type &&
*((const DWORD *)ptr + 2) == chunk_id ))
+ {
+ ptr += sizeof(DWORD);
+ chunk->data_size = (*(const DWORD *)ptr + 1) & ~1;
+ ptr += sizeof(DWORD);
+ if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) ptr +=
sizeof(DWORD);
+ chunk->data = ptr;
+
+ return;
+ }
+
+ ptr += sizeof(DWORD);
+ ptr += (*(const DWORD *)ptr + 1) & ~1;
+ ptr += sizeof(DWORD);
+ }
+}
+
+static BOOL CURSORICON_GetCursorDataFromANI(
+ _Inout_ CURSORDATA* pCurData,
+ _In_ const BYTE *pData,
+ _In_ DWORD dwDataSize,
+ _In_ DWORD fuLoad
+)
+{
+ UINT i;
+ const ani_header *pHeader;
+ riff_chunk_t root_chunk = { dwDataSize, pData };
+ riff_chunk_t ACON_chunk = {0};
+ riff_chunk_t anih_chunk = {0};
+ riff_chunk_t fram_chunk = {0};
+ riff_chunk_t rate_chunk = {0};
+ riff_chunk_t seq_chunk = {0};
+ const unsigned char *icon_chunk;
+ const unsigned char *icon_data;
+
+ /* Find the root chunk */
+ riff_find_chunk( ANI_ACON_ID, ANI_RIFF_ID, &root_chunk, &ACON_chunk );
+ if (!ACON_chunk.data)
+ {
+ ERR("Failed to get root chunk.\n");
+ return FALSE;
+ }
+
+ /* Find the header chunk */
+ riff_find_chunk( ANI_anih_ID, 0, &ACON_chunk, &anih_chunk );
+ if (!ACON_chunk.data)
+ {
+ ERR("Failed to get header chunk.\n");
+ return FALSE;
+ }
+ pHeader = (ani_header*)anih_chunk.data;
+ dump_ani_header(pHeader);
+
+ /* Set up the master data */
+ pCurData->CURSORF_flags |= CURSORF_ACON;
+ pCurData->cpcur = pHeader->num_frames;
+ pCurData->cicur = pHeader->num_steps;
+ pCurData->iicur = pHeader->display_rate;
+
+ /* Get the sequences */
+ if (pHeader->flags & ANI_FLAG_SEQUENCE)
+ {
+ riff_find_chunk( ANI_seq__ID, 0, &ACON_chunk, &seq_chunk );
+ if (!seq_chunk.data)
+ {
+ ERR("No sequence data although the flag is set!\n");
+ return FALSE;
+ }
+ }
+
+ /* Get the frame rates */
+ riff_find_chunk( ANI_rate_ID, 0, &ACON_chunk, &rate_chunk );
+ if (rate_chunk.data)
+ pCurData->ajifRate = (INT*)rate_chunk.data;
+
+ /* Get the frames chunk */
+ riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk );
+ if (!fram_chunk.data)
+ {
+ ERR("Failed to get icon list.\n");
+ return 0;
+ }
+ icon_chunk = fram_chunk.data;
+ icon_data = fram_chunk.data + (2 * sizeof(DWORD));
+
+ if(pHeader->num_frames > 1)
+ {
+ /* Allocate frame descriptors, step indices and rates */
+ pCurData->aspcur = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ pHeader->num_frames * sizeof(CURSORDATA) + pHeader->num_steps *
(sizeof(DWORD) + sizeof(INT)));
+ if(!pCurData->aspcur)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ pCurData->aicur = (DWORD*)(pCurData->aspcur + pHeader->num_frames);
+ pCurData->ajifRate = (INT*)(pCurData->aicur + pHeader->num_steps);
+ }
+
+ for(i=0; i < pHeader->num_frames; i++)
+ {
+ CURSORDATA* pFrameData;
+ const DWORD chunk_size = *(const DWORD *)(icon_chunk + sizeof(DWORD));
+ const BITMAPINFO* pbmi;
+
+ if(pHeader->num_frames > 1)
+ pFrameData = &pCurData->aspcur[i];
+ else
+ pFrameData = pCurData;
+
+ pFrameData->rt = pCurData->rt;
+
+ if (pHeader->flags & ANI_FLAG_ICON)
+ {
+ /* The chunks describe an icon file */
+ const CURSORICONFILEDIRENTRY* pDirEntry = get_best_icon_file_entry(
+ (const CURSORICONFILEDIR *) icon_data,
+ chunk_size,
+ pCurData->cx,
+ pCurData->cy,
+ TRUE,
+ fuLoad);
+ if(!pDirEntry)
+ {
+ ERR("Unable to find the right file entry for frame %d.\n", i);
+ goto error;
+ }
+ pFrameData->xHotspot = pDirEntry->xHotspot;
+ pFrameData->yHotspot = pDirEntry->yHotspot;
+ if(!pHeader->width || !pHeader->height)
+ {
+ pFrameData->cx = pDirEntry->bWidth;
+ pFrameData->cy = pDirEntry->bHeight;
+ }
+ else
+ {
+ pFrameData->cx = pHeader->width;
+ pFrameData->cy = pHeader->height;
+ }
+ pbmi = (const BITMAPINFO *) (icon_data + pDirEntry->dwDIBOffset);
+ }
+ else
+ {
+ /* The chunks just describe bitmaps */
+ pbmi = (const BITMAPINFO *)icon_data;
+ pFrameData->xHotspot = pFrameData->yHotspot = 0;
+ }
+
+ /* Do the real work */
+ CURSORICON_GetCursorDataFromBMI(pFrameData, pbmi);
+
+ if(pHeader->num_frames > 1)
+ pFrameData->CURSORF_flags |= CURSORF_ACONFRAME;
+ else
+ pFrameData->CURSORF_flags &= ~CURSORF_ACON;
+
+
+ /* Next frame */
+ icon_chunk += chunk_size + (2 * sizeof(DWORD));
+ icon_data = icon_chunk + (2 * sizeof(DWORD));
+ }
+
+ if(pHeader->num_frames <= 1)
+ return TRUE;
+
+ if(rate_chunk.data)
+ CopyMemory(pCurData->ajifRate, rate_chunk.data, pHeader->num_steps *
sizeof(INT));
+ else
+ {
+ for(i=0; i < pHeader->num_steps; i++)
+ pCurData->ajifRate[i] = pHeader->display_rate;
+ }
+
+ if (pHeader->flags & ANI_FLAG_SEQUENCE)
+ {
+ CopyMemory(pCurData->aicur, seq_chunk.data, pHeader->num_steps *
sizeof(DWORD));
+ }
+ else
+ {
+ for(i=0; i < pHeader->num_steps; i++)
+ pCurData->aicur[i] = i;
+ }
+
+ return TRUE;
+
+error:
+ HeapFree(GetProcessHeap(), 0, pCurData->aspcur);
+ ZeroMemory(pCurData, sizeof(CURSORDATA));
+ return FALSE;
+}
+
+
static
HBITMAP
BITMAP_LoadImageW(
@@ -561,7 +923,7 @@
/* Caller wants an OEM bitmap */
if(!hinst)
hinst = User32Instance;
- hrsrc = FindResourceW(hinst, lpszName, (LPWSTR)RT_BITMAP);
+ hrsrc = FindResourceW(hinst, lpszName, RT_BITMAP);
if(!hrsrc)
return NULL;
hgRsrc = LoadResource(hinst, hrsrc);
@@ -774,28 +1136,6 @@
return hbmpRet;
}
-#include "pshpack1.h"
-
-typedef struct {
- BYTE bWidth;
- BYTE bHeight;
- BYTE bColorCount;
- BYTE bReserved;
- WORD xHotspot;
- WORD yHotspot;
- DWORD dwDIBSize;
- DWORD dwDIBOffset;
-} CURSORICONFILEDIRENTRY;
-
-typedef struct
-{
- WORD idReserved;
- WORD idType;
- WORD idCount;
- CURSORICONFILEDIRENTRY idEntries[1];
-} CURSORICONFILEDIR;
-
-#include "poppack.h"
static
HANDLE
@@ -807,14 +1147,11 @@
_In_ BOOL bIcon
)
{
- CURSORICONDIR* fakeDir;
- CURSORICONDIRENTRY* fakeEntry;
- CURSORICONFILEDIRENTRY *entry;
- CURSORICONFILEDIR *dir;
+ const CURSORICONFILEDIRENTRY *entry;
+ const CURSORICONFILEDIR *dir;
DWORD filesize = 0;
LPBYTE bits;
HANDLE hCurIcon = NULL;
- WORD i;
CURSORDATA cursorData;
TRACE("loading %s\n", debugstr_w( lpszName ));
@@ -831,63 +1168,10 @@
}
dir = (CURSORICONFILEDIR*) bits;
- if ( filesize < sizeof(*dir) )
+ entry = get_best_icon_file_entry(dir, filesize, cxDesired, cyDesired, bIcon,
fuLoad);
+ if(!entry)
goto end;
-
- if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1))
)
- goto end;
-
- /*
- * Cute little hack:
- * We allocate a buffer, fake it as if it was a pointer to a resource in a module,
- * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
- */
- fakeDir = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR,
idEntries[dir->idCount]));
- if(!fakeDir)
- goto end;
- fakeDir->idReserved = 0;
- fakeDir->idType = dir->idType;
- fakeDir->idCount = dir->idCount;
- for(i = 0; i<dir->idCount; i++)
- {
- fakeEntry = &fakeDir->idEntries[i];
- entry = &dir->idEntries[i];
- /* Take this as an occasion to perform a size check */
- if((entry->dwDIBOffset + entry->dwDIBSize) > filesize)
- goto end;
- /* File icon/cursors are not like resource ones */
- if(bIcon)
- {
- fakeEntry->ResInfo.icon.bWidth = entry->bWidth;
- fakeEntry->ResInfo.icon.bHeight = entry->bHeight;
- fakeEntry->ResInfo.icon.bColorCount = 0;
- fakeEntry->ResInfo.icon.bReserved = 0;
- }
- else
- {
- fakeEntry->ResInfo.cursor.wWidth = entry->bWidth;
- fakeEntry->ResInfo.cursor.wHeight = entry->bHeight;
- }
- /* Let's assume there's always one plane */
- fakeEntry->wPlanes = 1;
- /* We must get the bitcount from the BITMAPINFOHEADER itself */
- fakeEntry->wBitCount = ((BITMAPINFOHEADER *)((char *)dir +
entry->dwDIBOffset))->biBitCount;
- fakeEntry->dwBytesInRes = entry->dwDIBSize;
- fakeEntry->wResId = i + 1;
- }
-
- /* Now call LookupIconIdFromResourceEx */
- i = LookupIconIdFromDirectoryEx((PBYTE)fakeDir, bIcon, cxDesired, cyDesired, fuLoad
& LR_MONOCHROME);
- /* We don't need this anymore */
- HeapFree(GetProcessHeap(), 0, fakeDir);
- if(i == 0)
- {
- WARN("Unable to get a fit entry index.\n");
- goto end;
- }
-
- /* Get our entry */
- entry = &dir->idEntries[i-1];
+
/* Fix dimensions */
if(!cxDesired) cxDesired = entry->bWidth;
if(!cyDesired) cyDesired = entry->bHeight;
@@ -904,7 +1188,7 @@
if(!CURSORICON_GetCursorDataFromBMI(&cursorData,
(BITMAPINFO*)&bits[entry->dwDIBOffset]))
goto end;
- hCurIcon = NtUserxCreateEmptyCurObject(bIcon ? 0 : 1);
+ hCurIcon = NtUserxCreateEmptyCurObject(FALSE);
if(!hCurIcon)
goto end_error;
@@ -914,12 +1198,12 @@
NtUserDestroyCursor(hCurIcon, TRUE);
goto end_error;
}
-
+
end:
UnmapViewOfFile(bits);
return hCurIcon;
-
- /* Clean up */
+
+ /* Clean up */
end_error:
DeleteObject(cursorData.hbmMask);
if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
@@ -969,7 +1253,7 @@
{
DWORD size = MAX_PATH;
FINDEXISTINGCURICONPARAM param;
-
+
TRACE("Checking for an LR_SHARED cursor/icon.\n");
/* Prepare the resource name string */
if(IS_INTRESOURCE(lpszName))
@@ -1020,8 +1304,8 @@
hrsrc = FindResourceW(
hinst,
lpszName,
- (LPWSTR)(bIcon ? RT_GROUP_ICON : RT_GROUP_CURSOR));
-
+ bIcon ? RT_GROUP_ICON : RT_GROUP_CURSOR);
+
/* We let FindResource, LoadResource, etc. call SetLastError */
if(!hrsrc)
goto done;
@@ -1041,7 +1325,7 @@
hrsrc = FindResourceW(
hinst,
MAKEINTRESOURCEW(wResId),
- (LPWSTR)(bIcon ? RT_ICON : RT_CURSOR));
+ bIcon ? RT_ICON : RT_CURSOR);
if(!hrsrc)
goto done;
@@ -1055,9 +1339,12 @@
FreeResource(handle);
goto done;
}
-
+
ZeroMemory(&cursorData, sizeof(cursorData));
-
+
+ /* This is from resource */
+ cursorData.CURSORF_flags = CURSORF_FROMRESOURCE;
+
if(dir->idType == 2)
{
/* idType == 2 for cursor resources */
@@ -1080,11 +1367,8 @@
if(!bStatus)
goto done;
- /* This is from resource */
- cursorData.CURSORF_flags = CURSORF_FROMRESOURCE;
-
/* Create the handle */
- hCurIcon = NtUserxCreateEmptyCurObject(bIcon ? 0 : 1);
+ hCurIcon = NtUserxCreateEmptyCurObject(FALSE);
if(!hCurIcon)
{
goto end_error;
@@ -1352,21 +1636,21 @@
do
{
- if(!NtUserGetIconInfo(hicon, NULL, &ustrModule, &ustrRsrc, NULL,
FALSE))
+ if (!NtUserGetIconInfo(hicon, NULL, &ustrModule, &ustrRsrc, NULL,
FALSE))
{
HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
HeapFree(GetProcessHeap(), 0, pvBuf);
return NULL;
}
- if((ustrModule.Length < ustrModule.MaximumLength) &&
(ustrRsrc.Length < ustrRsrc.MaximumLength))
+ if (ustrModule.Length && (ustrRsrc.Length ||
IS_INTRESOURCE(ustrRsrc.Buffer)))
{
/* Buffers were big enough */
break;
}
/* Find which buffer were too small */
- if(ustrModule.Length == ustrModule.MaximumLength)
+ if (!ustrModule.Length)
{
PWSTR newBuffer;
ustrModule.MaximumLength *= 2;
@@ -1379,7 +1663,7 @@
ustrModule.Buffer = newBuffer;
}
- if(ustrRsrc.Length == ustrRsrc.MaximumLength)
+ if (!ustrRsrc.Length)
{
ustrRsrc.MaximumLength *= 2;
pvBuf = HeapReAlloc(GetProcessHeap(), 0, ustrRsrc.Buffer,
ustrRsrc.MaximumLength);
@@ -1400,7 +1684,7 @@
/* Get the module handle */
if(!GetModuleHandleExW(0, ustrModule.Buffer, &hModule))
{
- /* This hould never happen */
+ /* This should never happen */
ERR("Invalid handle?.\n");
SetLastError(ERROR_INVALID_PARAMETER);
goto leave;
@@ -1489,8 +1773,7 @@
_In_ HICON hIcon
)
{
- UNIMPLEMENTED;
- return NULL;
+ return CURSORICON_CopyImage(hIcon, FALSE, 0, 0, 0);
}
BOOL WINAPI DrawIcon(
@@ -1687,6 +1970,8 @@
_In_ UINT fuLoad
)
{
+ TRACE("hinst 0x%p, name %s, uType 0x%08x, cxDesired %d, cyDesired %d, fuLoad
0x%08x.\n",
+ hinst, debugstr_w(lpszName), uType, cxDesired, cyDesired, fuLoad);
/* Redirect to each implementation */
switch(uType)
{
@@ -1735,7 +2020,7 @@
WARN("Invalid resource.\n");
return 0;
}
-
+
if(Flags & LR_MONOCHROME)
bppDesired = 1;
else
@@ -1900,45 +2185,103 @@
{
CURSORDATA cursorData;
HICON hIcon;
+ BOOL isAnimated;
TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits, cbIconBits, fIcon,
dwVersion, cxDesired, cyDesired, uFlags);
-
- if(uFlags & ~LR_DEFAULTSIZE)
- FIXME("uFlags 0x%08x ignored.\n", uFlags & ~LR_DEFAULTSIZE);
if(uFlags & LR_DEFAULTSIZE)
{
if(!cxDesired) cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR);
if(!cyDesired) cyDesired = GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR);
}
-
- /* Check if this is an animated cursor */
- if(!memcmp(pbIconBits, "RIFF", 4))
- {
- UNIMPLEMENTED;
- return NULL;
- }
-
+
ZeroMemory(&cursorData, sizeof(cursorData));
cursorData.cx = cxDesired;
cursorData.cy = cyDesired;
cursorData.rt = (USHORT)((ULONG_PTR)(fIcon ? RT_ICON : RT_CURSOR));
- if(!fIcon)
- {
- WORD* pt = (WORD*)pbIconBits;
- cursorData.xHotspot = *pt++;
- cursorData.yHotspot = *pt++;
- pbIconBits = (PBYTE)pt;
- }
-
- if(!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)pbIconBits))
- {
- ERR("Couldn't fill the CURSORDATA structure.\n");
- return NULL;
- }
-
- hIcon = NtUserxCreateEmptyCurObject(fIcon ? 0 : 1);
- if(!hIcon)
+
+ /* Convert to win32k-ready data */
+ if(!memcmp(pbIconBits, "RIFF", 4))
+ {
+ if(!CURSORICON_GetCursorDataFromANI(&cursorData, pbIconBits, cbIconBits,
uFlags))
+ {
+ ERR("Could not get cursor data from .ani.\n");
+ return NULL;
+ }
+ isAnimated = !!(cursorData.CURSORF_flags & CURSORF_ACON);
+ }
+ else
+ {
+ /* It is possible to pass Icon Directories to this API */
+ int wResId = LookupIconIdFromDirectoryEx(pbIconBits, fIcon, cxDesired, cyDesired,
uFlags);
+ HANDLE ResHandle = NULL;
+ if(wResId)
+ {
+ HINSTANCE hinst;
+ HRSRC hrsrc;
+ CURSORICONDIR* pCurIconDir = (CURSORICONDIR*)pbIconBits;
+
+ TRACE("Pointer points to a directory structure.\n");
+
+ /* So this is a pointer to an icon directory structure. Find the module */
+ if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+ (LPCWSTR)pbIconBits,
+ &hinst))
+ {
+ return NULL;
+ }
+
+ /* Check we were given the right type of resource */
+ if((fIcon && pCurIconDir->idType == 2) || (!fIcon &&
pCurIconDir->idType == 1))
+ {
+ WARN("Got a %s directory pointer, but called for a %s", fIcon ?
"cursor" : "icon", fIcon ? "icon" : "cursor");
+ return NULL;
+ }
+
+ /* Get the relevant resource pointer */
+ hrsrc = FindResourceW(
+ hinst,
+ MAKEINTRESOURCEW(wResId),
+ fIcon ? RT_ICON : RT_CURSOR);
+ if (!hrsrc)
+ return NULL;
+
+ ResHandle = LoadResource(hinst, hrsrc);
+ if (!ResHandle)
+ return NULL;
+
+ pbIconBits = LockResource(ResHandle);
+ if (!pbIconBits)
+ {
+ FreeResource(ResHandle);
+ return NULL;
+ }
+ }
+ if(!fIcon)
+ {
+ WORD* pt = (WORD*)pbIconBits;
+ cursorData.xHotspot = *pt++;
+ cursorData.yHotspot = *pt++;
+ pbIconBits = (PBYTE)pt;
+ }
+
+ if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)pbIconBits))
+ {
+ ERR("Couldn't fill the CURSORDATA structure.\n");
+ if (ResHandle)
+ FreeResource(ResHandle);
+ return NULL;
+ }
+ if (ResHandle)
+ FreeResource(ResHandle);
+ isAnimated = FALSE;
+ }
+
+ if (uFlags & LR_SHARED)
+ cursorData.CURSORF_flags |= CURSORF_LRSHARED;
+
+ hIcon = NtUserxCreateEmptyCurObject(isAnimated);
+ if (!hIcon)
goto end_error;
if(!NtUserSetCursorIconData(hIcon, NULL, NULL, &cursorData))
@@ -1947,11 +2290,16 @@
NtUserDestroyCursor(hIcon, TRUE);
goto end_error;
}
+
+ if(isAnimated)
+ HeapFree(GetProcessHeap(), 0, cursorData.aspcur);
return hIcon;
-
+
/* Clean up */
end_error:
+ if(isAnimated)
+ HeapFree(GetProcessHeap(), 0, cursorData.aspcur);
DeleteObject(cursorData.hbmMask);
if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
@@ -1968,11 +2316,13 @@
CURSORDATA cursorData;
TRACE("%p.\n", piconinfo);
+
+ ZeroMemory(&cursorData, sizeof(cursorData));
if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData, piconinfo))
return NULL;
- hiconRet = NtUserxCreateEmptyCurObject(piconinfo->fIcon ? 0 : 1);
+ hiconRet = NtUserxCreateEmptyCurObject(FALSE);
if(!hiconRet)
goto end_error;
@@ -2064,3 +2414,10 @@
{
return NtUserDestroyCursor(hCursor, FALSE);
}
+
+HCURSOR
+WINAPI
+GetCursorFrameInfo(HCURSOR hCursor, DWORD reserved, DWORD istep, PINT rate_jiffies, DWORD
*num_steps)
+{
+ return NtUserGetCursorFrameInfo(hCursor, istep, rate_jiffies, num_steps);
+}