[WIN32SS]
authorJérôme Gardou <jerome.gardou@reactos.org>
Wed, 13 Nov 2013 20:06:01 +0000 (20:06 +0000)
committerJérôme Gardou <jerome.gardou@reactos.org>
Wed, 13 Nov 2013 20:06:01 +0000 (20:06 +0000)
 - 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

svn path=/trunk/; revision=60978

12 files changed:
reactos/win32ss/include/ntuser.h
reactos/win32ss/include/ntusrtyp.h
reactos/win32ss/user/ntuser/class.c
reactos/win32ss/user/ntuser/cursoricon.c
reactos/win32ss/user/ntuser/cursoricon.h
reactos/win32ss/user/ntuser/cursoricon_new.c
reactos/win32ss/user/ntuser/ntstubs.c
reactos/win32ss/user/ntuser/simplecall.c
reactos/win32ss/user/ntuser/win32.h
reactos/win32ss/user/user32/misc/stubs.c
reactos/win32ss/user/user32/windows/cursoricon.c
reactos/win32ss/user/user32/windows/cursoricon_new.c

index 862fae5..79a8c28 100644 (file)
@@ -2000,8 +2000,8 @@ NTAPI
 NtUserGetCursorFrameInfo(
   HCURSOR hCursor,
   DWORD istep,
-  PDWORD rate_jiffies,
-  INT *num_steps);
+  INT* rate_jiffies,
+  DWORD* num_steps);
 
 BOOL
 NTAPI
@@ -2791,7 +2791,7 @@ NtUserSetCursorIconData(
   _In_ HCURSOR hCursor,
   _In_ PUNICODE_STRING pustrModule,
   _In_ PUNICODE_STRING puSrcName,
-  _In_ PCURSORDATA pCursorData);
+  _In_ const CURSORDATA* pCursorData);
 
 typedef struct _tagFINDEXISTINGCURICONPARAM
 {
index 27a5aad..d686fe0 100644 (file)
@@ -90,7 +90,7 @@ typedef struct
 {   union
     { 
         ICONRESDIR icon;
-        CURSORDIR  cursor;
+        CURSORRESDIR  cursor;
     } ResInfo;
     WORD   wPlanes;
     WORD   wBitCount;
index 6b11866..5852104 100644 (file)
@@ -1728,7 +1728,11 @@ IntSetClassMenuName(IN PCLS Class,
 }
 
 //// 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 @@ IntClassDestroyIcon(HANDLE hCurIcon)
         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");
index a4dbce0..c3a95b2 100644 (file)
@@ -203,7 +203,7 @@ IntFindExistingCurIconObject(HMODULE hModule,
     return NULL;
 }
 
-PCURICON_OBJECT
+HANDLE
 IntCreateCurIconHandle(DWORD dwNumber)
 {
     PCURICON_OBJECT CurIcon;
@@ -220,7 +220,7 @@ IntCreateCurIconHandle(DWORD dwNumber)
     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 @@ IntCreateCurIconHandle(DWORD dwNumber)
 
     InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
 
-    return CurIcon;
+    UserDereferenceObject(CurIcon);
+
+    return hCurIcon;
 }
 
 BOOLEAN FASTCALL
@@ -1519,4 +1521,20 @@ NtUserDrawIconEx(
     return Ret;
 }
 
+/*
+ * @unimplemented
+ */
+HCURSOR
+NTAPI
+NtUserGetCursorFrameInfo(
+    HCURSOR hCursor,
+    DWORD istep,
+    INT* rate_jiffies,
+    DWORD* num_steps)
+{
+    STUB
+
+    return 0;
+}
+
 /* EOF */
index 2d00177..0e16e86 100644 (file)
@@ -2,40 +2,53 @@
 
 #define MAXCURICONHANDLES 4096
 
-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;
+    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;
+
 typedef struct _CURICON_OBJECT
 {
   PROCMARKHEAD head;
@@ -91,7 +104,7 @@ typedef struct _SYSTEM_CURSORINFO
 } 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,
index c481eb5..f4907a2 100644 (file)
  *   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 @@ PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
         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 @@ BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Ho
     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 @@ IntCreateCurIconHandle(DWORD dwNumber)
         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;
-    }
-
-    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)
 {
-    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);
+        /* Mark the object as destroyed, and fail, as per wine tests */
+        UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
         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(CurIcon->head.ppi != PsGetCurrentProcessWin32Process())
     {
-        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! */
+        /* 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, TYPE_CURSOR, 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);
-
-    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], TRUE);
+        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! */
+    /* 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)
+    while(Win32Process->pCursorCache)
     {
-        UserReferenceObject(CurIcon);
-        IntDestroyCurIconObject(CurIcon, Win32Process, TRUE);
+        CurIcon = Win32Process->pCursorCache;
+        Win32Process->pCursorCache = CurIcon->pcurNext;
+        ASSERT(CurIcon->head.cLockObj == 2);
+        IntDestroyCurIconObject(CurIcon, TRUE);
     }
 }
 
@@ -410,17 +285,24 @@ NtUserGetIconInfo(
     /* 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 @@ NtUserGetIconInfo(
             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);
             }
         }
@@ -547,6 +438,15 @@ NtUserGetIconSize(
         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 @@ NtUserGetCursorInfo(
 
     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 @@ NtUserDestroyCursor(
         RETURN(FALSE);
     }
 
-    ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process(), bForce);
+    ret = IntDestroyCurIconObject(CurIcon, bForce);
     /* Note: IntDestroyCurIconObject will remove our reference for us! */
 
     RETURN(ret);
@@ -766,16 +666,11 @@ NtUserFindExistingCursorIcon(
     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
     {
@@ -788,16 +683,65 @@ NtUserFindExistingCursorIcon(
     }
     _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, &paramSafe);
-    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 @@ NtUserSetCursor(
     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,18 +871,17 @@ NtUserSetCursorIconData(
   _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)))
@@ -942,15 +894,49 @@ NtUserSetCursorIconData(
     _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,19 +949,43 @@ NtUserSetCursorIconData(
         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");
@@ -990,17 +1000,41 @@ NtUserSetCursorIconData(
     
     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,13 +1078,21 @@ UserDrawIconEx(
         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
@@ -1445,4 +1487,74 @@ NtUserDrawIconEx(
     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 */
index ff1c07c..b87c550 100644 (file)
@@ -1247,22 +1247,6 @@ BOOL APIENTRY NtUserGetUpdatedClipboardFormats(
     return FALSE;
 }
 
-/*
- * @unimplemented
- */
-HCURSOR
-NTAPI
-NtUserGetCursorFrameInfo(
-    HCURSOR hCursor,
-    DWORD istep,
-    PDWORD rate_jiffies,
-    INT *num_steps)
-{
-    STUB
-
-    return 0;
-}
-
 /*
  * @unimplemented
  */
index 2ad6cb1..c1b9791 100644 (file)
@@ -237,17 +237,13 @@ NtUserCallOneParam(
 
       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);
          }
 
index bfba150..fbbfaca 100644 (file)
@@ -235,6 +235,7 @@ typedef struct _PROCESSINFO
   ACCESS_MASK amwinsta;
   DWORD dwHotkey;
   HMONITOR hMonitor;
+  struct _CURICON_OBJECT* pCursorCache;
   LUID luidSession;
   USERSTARTUPINFO usi;
   DWORD dwLayout;
index 5014042..d349de5 100644 (file)
@@ -540,15 +540,6 @@ DeviceEventWorker(DWORD dw1, DWORD dw2, DWORD dw3, DWORD dw4, DWORD dw5)
     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
 WINAPI
 GetReasonTitleFromReasonCode(DWORD dw1, DWORD dw2, DWORD dw3)
index 6a6be37..23a2671 100644 (file)
@@ -2207,3 +2207,10 @@ User32CallCopyImageFromKernel(PVOID Arguments, ULONG ArgumentLength)
   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);
+}
+
index d622d56..5f4aa30 100644 (file)
@@ -14,6 +14,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(cursor);
 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 @@ User32SetupDefaultCursors(PVOID Arguments,
     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);
     }
 
@@ -304,6 +308,113 @@ done:
     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 ****************/
 
 static BOOL CURSORICON_GetCursorDataFromBMI(
@@ -509,6 +620,257 @@ static BOOL CURSORICON_GetCursorDataFromIconInfo(
     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 @@ BITMAP_LoadImageW(
         /* 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 @@ end:
     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 @@ CURSORICON_LoadFromFileW(
   _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 @@ CURSORICON_LoadFromFileW(
     }
 
     dir = (CURSORICONFILEDIR*) bits;
-    if ( filesize < sizeof(*dir) )
-        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");
+    entry = get_best_icon_file_entry(dir, filesize, cxDesired, cyDesired, bIcon, fuLoad);
+    if(!entry)
         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 @@ CURSORICON_LoadFromFileW(
     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 @@ CURSORICON_LoadFromFileW(
         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 @@ CURSORICON_LoadImageW(
     {
         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 @@ CURSORICON_LoadImageW(
     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 @@ CURSORICON_LoadImageW(
     hrsrc = FindResourceW(
         hinst,
         MAKEINTRESOURCEW(wResId),
-        (LPWSTR)(bIcon ? RT_ICON : RT_CURSOR));
+        bIcon ? RT_ICON : RT_CURSOR);
     if(!hrsrc)
         goto done;
     
@@ -1055,9 +1339,12 @@ CURSORICON_LoadImageW(
         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 @@ CURSORICON_LoadImageW(
     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 @@ CURSORICON_CopyImage(
         
         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 @@ CURSORICON_CopyImage(
                 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 @@ CURSORICON_CopyImage(
         /* 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 @@ HICON WINAPI CopyIcon(
   _In_  HICON hIcon
 )
 {
-    UNIMPLEMENTED;
-    return NULL;
+    return CURSORICON_CopyImage(hIcon, FALSE, 0, 0, 0);
 }
 
 BOOL WINAPI DrawIcon(
@@ -1687,6 +1970,8 @@ HANDLE WINAPI LoadImageW(
   _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 @@ int WINAPI LookupIconIdFromDirectoryEx(
         WARN("Invalid resource.\n");
         return 0;
     }
-    
+
     if(Flags & LR_MONOCHROME)
         bppDesired = 1;
     else
@@ -1900,45 +2185,103 @@ HICON WINAPI CreateIconFromResourceEx(
 {
     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)
+
+    /* Convert to win32k-ready data */
+    if(!memcmp(pbIconBits, "RIFF", 4))
     {
-        WORD* pt = (WORD*)pbIconBits;
-        cursorData.xHotspot = *pt++;
-        cursorData.yHotspot = *pt++;
-        pbIconBits = (PBYTE)pt;
+        if(!CURSORICON_GetCursorDataFromANI(&cursorData, pbIconBits, cbIconBits, uFlags))
+        {
+            ERR("Could not get cursor data from .ani.\n");
+            return NULL;
+        }
+        isAnimated = !!(cursorData.CURSORF_flags & CURSORF_ACON);
     }
-    
-    if(!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)pbIconBits))
+    else
     {
-        ERR("Couldn't fill the CURSORDATA structure.\n");
-        return NULL;
+        /* 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(fIcon ? 0 : 1);
-    if(!hIcon)
+    hIcon = NtUserxCreateEmptyCurObject(isAnimated);
+    if (!hIcon)
         goto end_error;
     
     if(!NtUserSetCursorIconData(hIcon, NULL, NULL, &cursorData))
@@ -1947,11 +2290,16 @@ HICON WINAPI CreateIconFromResourceEx(
         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 @@ HICON WINAPI CreateIconIndirect(
     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 @@ BOOL WINAPI DestroyCursor(
 {
     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);
+}