[WIN32SS]
[reactos.git] / reactos / win32ss / user / ntuser / cursoricon_new.c
index e5d25ba..40e2845 100644 (file)
@@ -2,7 +2,7 @@
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS Win32k subsystem
  * PURPOSE:          Cursor and icon functions
- * FILE:             subsystems/win32/win32k/ntuser/cursoricon.c
+ * FILE:             win32ss/user/ntuser/cursoricon.c
  * PROGRAMER:        ReactOS Team
  */
 /*
  *   Possibly shared by multiple processes
  *   Immune to NtDestroyCursorIcon()
  *   CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
- * There's a M:N relationship between processes and (shared) cursor/icons.
- * A process can have multiple cursor/icons and a cursor/icon can be used
- * by multiple processes. To keep track of this we keep a list of all
- * cursor/icons (CurIconList) and per cursor/icon we keep a list of
- * CURICON_PROCESS structs starting at CurIcon->ProcessList.
  */
 
 #include <win32k.h>
 DBG_DEFAULT_CHANNEL(UserIcon);
 
-static PPAGED_LOOKASIDE_LIST pgProcessLookasideList;
-static LIST_ENTRY gCurIconList;
-
 SYSTEM_CURSORINFO gSysCursorInfo;
 
 BOOL
-InitCursorImpl()
+InitCursorImpl(VOID)
 {
-    pgProcessLookasideList = ExAllocatePool(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST));
-    if(!pgProcessLookasideList)
-        return FALSE;
-
-    ExInitializePagedLookasideList(pgProcessLookasideList,
-                                   NULL,
-                                   NULL,
-                                   0,
-                                   sizeof(CURICON_PROCESS),
-                                   TAG_DIB,
-                                   128);
-    InitializeListHead(&gCurIconList);
-
-     gSysCursorInfo.Enabled = FALSE;
-     gSysCursorInfo.ButtonsDown = 0;
-     gSysCursorInfo.bClipped = FALSE;
-     gSysCursorInfo.LastBtnDown = 0;
-     gSysCursorInfo.CurrentCursorObject = NULL;
-     gSysCursorInfo.ShowingCursor = -1;
-     gSysCursorInfo.ClickLockActive = FALSE;
-     gSysCursorInfo.ClickLockTime = 0;
+    gSysCursorInfo.Enabled = FALSE;
+    gSysCursorInfo.ButtonsDown = 0;
+    gSysCursorInfo.bClipped = FALSE;
+    gSysCursorInfo.LastBtnDown = 0;
+    gSysCursorInfo.CurrentCursorObject = NULL;
+    gSysCursorInfo.ShowingCursor = -1;
+    gSysCursorInfo.ClickLockActive = FALSE;
+    gSysCursorInfo.ClickLockTime = 0;
 
     return TRUE;
 }
@@ -66,6 +45,13 @@ IntGetSysCursorInfo()
     return &gSysCursorInfo;
 }
 
+FORCEINLINE
+BOOL
+is_icon(PCURICON_OBJECT object)
+{
+    return MAKEINTRESOURCE(object->rt) == RT_ICON;
+}
+
 /* This function creates a reference for the object! */
 PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
 {
@@ -77,7 +63,14 @@ PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
         return NULL;
     }
 
-    CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, otCursorIcon);
+    if(UserObjectInDestroy(hCurIcon))
+    {
+        ERR("Requesting destroyed cursor.\n");
+        EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
+        return NULL;
+    }
+
+    CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR);
     if (!CurIcon)
     {
         /* We never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
@@ -131,99 +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)
+HANDLE
+IntCreateCurIconHandle(BOOLEAN Animated)
 {
     PCURICON_OBJECT CurIcon;
-
-    LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
-    {
-        /* See if we are looking for an icon or a cursor */
-        if(CurIcon->bIcon != param->bIcon)
-            continue;
-        /* See if module names match */
-        if(RtlCompareUnicodeString(pustrModule, &CurIcon->ustrModule, TRUE) == 0)
-        {
-            /* They do. Now see if this is the same resource */
-            if(IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer) && IS_INTRESOURCE(pustrRsrc->Buffer))
-            {
-                if(CurIcon->ustrRsrc.Buffer != pustrRsrc->Buffer)
-                    continue;
-            }
-            else if(IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer) || IS_INTRESOURCE(pustrRsrc->Buffer))
-                continue;
-            else if(RtlCompareUnicodeString(pustrRsrc, &CurIcon->ustrRsrc, TRUE) != 0)
-                continue;
-            
-            if ((param->cx == CurIcon->Size.cx) &&(param->cy == CurIcon->Size.cy))
-            {
-                if (! ReferenceCurIconByProcess(CurIcon))
-                {
-                    return NULL;
-                }
-
-                return CurIcon;
-            }
-        }
-    }
-
-    return NULL;
-}
-
-PCURICON_OBJECT
-IntCreateCurIconHandle(DWORD dwNumber)
-{
-    PCURICON_OBJECT CurIcon;
-    BOOLEAN bIcon = dwNumber == 0;
     HANDLE hCurIcon;
-    
-    if(dwNumber == 0)
-        dwNumber = 1;
 
-    CurIcon = UserCreateObject(gHandleTable, NULL, NULL, &hCurIcon, otCursorIcon, FIELD_OFFSET(CURICON_OBJECT, aFrame[dwNumber]));
+    CurIcon = UserCreateObject(
+        gHandleTable,
+        NULL,
+        NULL,
+        &hCurIcon,
+        TYPE_CURSOR,
+        Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT));
 
     if (!CurIcon)
     {
@@ -231,140 +144,168 @@ IntCreateCurIconHandle(DWORD dwNumber)
         return FALSE;
     }
 
-    CurIcon->Self = hCurIcon;
-    CurIcon->bIcon = bIcon;
-    InitializeListHead(&CurIcon->ProcessList);
-
-    if (! ReferenceCurIconByProcess(CurIcon))
-    {
-        ERR("Failed to add process\n");
-        UserDeleteObject(hCurIcon, otCursorIcon);
-        UserDereferenceObject(CurIcon);
-        return NULL;
-    }
-
-    InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
+    UserDereferenceObject(CurIcon);
 
-    return CurIcon;
+    return hCurIcon;
 }
 
 BOOLEAN FASTCALL
-IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi, BOOLEAN bForce)
+IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, BOOLEAN bForce)
 {
-    PSYSTEM_CURSORINFO CurInfo;
-    HBITMAP bmpMask, bmpColor, bmpAlpha;
-    BOOLEAN Ret, bListEmpty, bFound = FALSE;
-    PCURICON_PROCESS Current = NULL;
-    
-    /* For handles created without any data (error handling) */
-    if(IsListEmpty(&CurIcon->ProcessList))
-        goto emptyList;
-
-    /* Now find this process in the list of processes referencing this object and
-       remove it from that list */
-    LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
+    if(CurIcon->CURSORF_flags & CURSORF_CURRENT)
     {
-        if (Current->Process == ppi)
-        {
-            bFound = TRUE;
-            bListEmpty = RemoveEntryList(&Current->ListEntry);
-            break;
-        }
+        /* Mark the object as destroyed, and fail, as per tests */
+        TRACE("Cursor is current, marking as destroyed.\n");
+        UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
+        return FALSE;
     }
-    
-    if(!bFound)
+
+    if(CurIcon->head.ppi != PsGetCurrentProcessWin32Process())
     {
-        /* This object doesn't belong to this process */
-        EngSetLastError(ERROR_INVALID_HANDLE);
-        /* Caller expects us to dereference! */
+        /* This object doesn't belong to the current process */
+        WARN("Trying to delete foreign cursor!\n");
         UserDereferenceObject(CurIcon);
+        EngSetLastError(ERROR_DESTROY_OBJECT_OF_OTHER_THREAD);
         return FALSE;
     }
     
-    /* We found our process, but we're told to not destroy it in case it is shared */
-    if((CurIcon->ustrModule.Buffer != NULL) && !bForce)
+    /* Do not destroy it if it is shared. (And we're not forced to) */
+    if((CurIcon->CURSORF_flags & CURSORF_LRSHARED) && !bForce)
     {
         /* Tests show this is a valid call */
+        WARN("Trying to destroy shared cursor!\n");
         UserDereferenceObject(CurIcon);
         return TRUE;
     }
 
-    ExFreeToPagedLookasideList(pgProcessLookasideList, Current);
-
-    /* If there are still processes referencing this object we can't destroy it yet */
-    if (!bListEmpty)
+    if(!(CurIcon->CURSORF_flags & CURSORF_ACON))
     {
-        if(CurIcon->head.ppi == ppi)
+        HBITMAP bmpMask = CurIcon->hbmMask;
+        HBITMAP bmpColor = CurIcon->hbmColor;
+        HBITMAP bmpAlpha = CurIcon->hbmAlpha;
+
+        /* Delete bitmaps */
+        if (bmpMask)
         {
-            /* Set the first process of the list as owner */
-            Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
-            UserSetObjectOwner(CurIcon, otCursorIcon, Current->Process);
+            GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
+            GreDeleteObject(bmpMask);
+            CurIcon->hbmMask = NULL;
+        }
+        if (bmpColor)
+        {
+            GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
+            GreDeleteObject(bmpColor);
+            CurIcon->hbmColor = NULL;
+        }
+        if (bmpAlpha)
+        {
+            GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED);
+            GreDeleteObject(bmpAlpha);
+            CurIcon->hbmAlpha = NULL;
         }
-        UserDereferenceObject(CurIcon);
-        return TRUE;
     }
+    else
+    {
+        PACON AniCurIcon = (PACON)CurIcon;
+        UINT i;
 
-emptyList:
-    /* Remove it from the list */
-    RemoveEntryList(&CurIcon->ListEntry);
-
-    CurInfo = IntGetSysCursorInfo();
+        for(i = 0; i < AniCurIcon->cpcur; i++)
+            IntDestroyCurIconObject(AniCurIcon->aspcur[i], TRUE);
+        ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
+    }
 
-    if (CurInfo->CurrentCursorObject == CurIcon)
+    if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
     {
-        /* Hide the cursor if we're destroying the current cursor */
-        UserSetCursor(NULL, TRUE);
+        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;
     }
 
-    bmpMask = CurIcon->aFrame[0].hbmMask;
-    bmpColor = CurIcon->aFrame[0].hbmColor;
-    bmpAlpha = CurIcon->aFrame[0].hbmAlpha;
+    /* We were given a pointer, no need to keep the reference any longer! */
+    UserDereferenceObject(CurIcon);
+    return UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
+}
+
+VOID FASTCALL
+IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
+{
+    PCURICON_OBJECT CurIcon;
 
-    /* Delete bitmaps */
-    if (bmpMask)
+    /* Run through the list of icon objects */
+    while(Win32Process->pCursorCache)
     {
-        GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
-        GreDeleteObject(bmpMask);
-        CurIcon->aFrame[0].hbmMask = NULL;
+        CurIcon = Win32Process->pCursorCache;
+        Win32Process->pCursorCache = CurIcon->pcurNext;
+        /* One ref for the handle, one for the list,
+         * and potentially one from an other process via SetCursor */
+        ASSERT(CurIcon->head.cLockObj <= 3);
+        IntDestroyCurIconObject(CurIcon, TRUE);
     }
-    if (bmpColor)
+}
+
+HCURSOR FASTCALL
+IntSetCursor(
+    HCURSOR hCursor)
+{
+    PCURICON_OBJECT pcurOld, pcurNew;
+    HCURSOR hOldCursor = NULL;
+
+    if (hCursor)
     {
-        GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
-        GreDeleteObject(bmpColor);
-        CurIcon->aFrame[0].hbmColor = NULL;
+        pcurNew = UserGetCurIconObject(hCursor);
+        if (!pcurNew)
+        {
+            EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
+            goto leave;
+        }
+        pcurNew->CURSORF_flags |= CURSORF_CURRENT;
     }
-    if (bmpAlpha)
+    else
     {
-        GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED);
-        GreDeleteObject(bmpAlpha);
-        CurIcon->aFrame[0].hbmAlpha = NULL;
+        pcurNew = NULL;
     }
-    
-    if(!IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer))
-        ExFreePoolWithTag(CurIcon->ustrRsrc.Buffer, TAG_STRING);
-    if(CurIcon->ustrModule.Buffer)
-        ReleaseCapturedUnicodeString(&CurIcon->ustrModule, UserMode);
-
-    /* We were given a pointer, no need to keep the reference anylonger! */
-    UserDereferenceObject(CurIcon);
-    Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
 
-    return Ret;
+    pcurOld = UserSetCursor(pcurNew, FALSE);
+    if (pcurOld)
+    {
+        hOldCursor = pcurOld->head.h;
+        pcurOld->CURSORF_flags &= ~CURSORF_CURRENT;
+        if(UserObjectInDestroy(hOldCursor))
+        {
+            /* Destroy it once and for all */
+            IntDestroyCurIconObject(pcurOld, TRUE);
+            hOldCursor = NULL;
+        }
+        else
+        {
+            UserDereferenceObject(pcurOld);
+        }
+    }
+leave:
+    return hOldCursor;
 }
 
-VOID FASTCALL
-IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
+BOOL FASTCALL
+IntDestroyCursor(
+  HANDLE hCurIcon,
+  BOOL bForce)
 {
-    PCURICON_OBJECT CurIcon, tmp;
+    PCURICON_OBJECT CurIcon;
+    BOOL ret;
 
-    /* Run through the list of icon objects */
-    LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
+    if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
     {
-        UserReferenceObject(CurIcon);
-        IntDestroyCurIconObject(CurIcon, Win32Process, TRUE);
+        return(FALSE);
     }
-}
 
+    ret = IntDestroyCurIconObject(CurIcon, bForce);
+    /* Note: IntDestroyCurIconObject will remove our reference for us! */
+
+    return ret;
+}
 
 /*
  * @implemented
@@ -407,28 +348,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 = CurIcon->bIcon;
-        ii.xHotspot = CurIcon->ptlHotspot.x;
-        ii.yHotspot = CurIcon->ptlHotspot.y;
+        ii.fIcon = is_icon(FrameCurIcon);
+        ii.xHotspot = FrameCurIcon->xHotspot;
+        ii.yHotspot = FrameCurIcon->yHotspot;
 
         /* Copy bitmaps */
-        ii.hbmMask = BITMAP_CopyBitmap(CurIcon->aFrame[0].hbmMask);
+        ii.hbmMask = BITMAP_CopyBitmap(FrameCurIcon->hbmMask);
         GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED);
-        ii.hbmColor = BITMAP_CopyBitmap(CurIcon->aFrame[0].hbmColor);
+        ii.hbmColor = BITMAP_CopyBitmap(FrameCurIcon->hbmColor);
         GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED);
-
-        if (pbpp)
-        {
-            PSURFACE psurfBmp;
-
-            psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmColor);
-            if (psurfBmp)
-            {
-                colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
-                SURFACE_ShareUnlockSurface(psurfBmp);
-            }
-        }
+        colorBpp = FrameCurIcon->bpp;
 
         /* Copy fields */
         _SEH2_TRY
@@ -447,64 +384,73 @@ 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->ustrRsrc.Buffer)
-        {
-            EngSetLastError(ERROR_INVALID_HANDLE);
+        if (!CurIcon->strName.Buffer)
             goto leave;
-        }
+
         /* Copy it */
         _SEH2_TRY
         {
             ProbeForWrite(lpResName, sizeof(UNICODE_STRING), 1);
-            if(IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer))
+            if (IS_INTRESOURCE(CurIcon->strName.Buffer))
+            {
+                lpResName->Buffer = CurIcon->strName.Buffer;
+                lpResName->Length = 0;
+            }
+            else if (lpResName->MaximumLength < CurIcon->strName.Length)
             {
-                lpResName->Buffer = CurIcon->ustrRsrc.Buffer;
                 lpResName->Length = 0;
             }
             else
             {
-                lpResName->Length = min(lpResName->MaximumLength, CurIcon->ustrRsrc.Length);
-                RtlCopyMemory(lpResName->Buffer, CurIcon->ustrRsrc.Buffer, lpResName->Length);
+                ProbeForWrite(lpResName->Buffer, lpResName->MaximumLength * sizeof(WCHAR), 1);
+                RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, lpResName->Length);
             }
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@@ -555,12 +501,21 @@ 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);
-        RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
+        *plcx = CurIcon->cx;
         ProbeForWrite(plcy, sizeof(LONG), 1);
-        RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
+        *plcy = CurIcon->cy;
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
@@ -605,7 +560,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;
 
@@ -715,7 +670,7 @@ NtUserClipCursor(
         prcl = &rclLocal;
     }
 
-       UserEnterExclusive();
+    UserEnterExclusive();
 
     /* Call the internal function */
     bResult = UserClipCursor(prcl);
@@ -747,7 +702,7 @@ NtUserDestroyCursor(
         RETURN(FALSE);
     }
 
-    ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process(), bForce);
+    ret = IntDestroyCurIconObject(CurIcon, bForce);
     /* Note: IntDestroyCurIconObject will remove our reference for us! */
 
     RETURN(ret);
@@ -774,21 +729,16 @@ 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
     {
         ProbeForRead(param, sizeof(*param), 1);
-        paramSafe = *param;
+        RtlCopyMemory(&paramSafe, param, sizeof(paramSafe));
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
@@ -796,16 +746,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;
 }
@@ -882,6 +881,7 @@ NtUserSetCursor(
             EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
             goto leave;
         }
+        pcurNew->CURSORF_flags |= CURSORF_CURRENT;
     }
     else
     {
@@ -891,8 +891,18 @@ NtUserSetCursor(
     pcurOld = UserSetCursor(pcurNew, FALSE);
     if (pcurOld)
     {
-        hOldCursor = (HCURSOR)pcurOld->Self;
-        UserDereferenceObject(pcurOld);
+        hOldCursor = pcurOld->head.h;
+        pcurOld->CURSORF_flags &= ~CURSORF_CURRENT;
+        if(UserObjectInDestroy(hOldCursor))
+        {
+            /* Destroy it once and for all */
+            IntDestroyCurIconObject(pcurOld, TRUE);
+            hOldCursor = NULL;
+        }
+        else
+        {
+            UserDereferenceObject(pcurOld);
+        }
     }
 
 leave:
@@ -902,7 +912,7 @@ leave:
 
 
 /*
- * @implemented
+ * @unimplemented
  */
 BOOL
 APIENTRY
@@ -910,150 +920,8 @@ NtUserSetCursorContents(
     HANDLE hCurIcon,
     PICONINFO UnsafeIconInfo)
 {
-    PCURICON_OBJECT CurIcon;
-    ICONINFO IconInfo;
-    PSURFACE psurfBmp;
-    NTSTATUS Status;
-    BOOL Ret = FALSE;
-    DECLARE_RETURN(BOOL);
-
-    TRACE("Enter NtUserSetCursorContents\n");
-    UserEnterExclusive();
-
-    if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
-    {
-        RETURN(FALSE);
-    }
-
-    /* Copy fields */
-    Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
-    if (!NT_SUCCESS(Status))
-    {
-        SetLastNtError(Status);
-        goto done;
-    }
-
-#if 0
-    /* Check if we get valid information */
-    if(IconInfo.fIcon != CurInfo->bIcon)
-    {
-        EngSetLastError(ERROR_INVALID_PARAMETER);
-        goto done;
-    }
-#endif
-
-    /* Delete old bitmaps */
-    if (CurIcon->aFrame[0].hbmColor)
-        GreDeleteObject(CurIcon->aFrame[0].hbmColor);
-    if (CurIcon->aFrame[0].hbmMask)
-        GreDeleteObject(CurIcon->aFrame[0].hbmMask);
-    if(CurIcon->aFrame[0].hbmAlpha)
-        GreDeleteObject(CurIcon->aFrame[0].hbmAlpha);
-
-    /* Set fields */
-    CurIcon->bIcon = IconInfo.fIcon;
-    CurIcon->ptlHotspot.x = IconInfo.xHotspot;
-    CurIcon->ptlHotspot.y = IconInfo.yHotspot;
-    CurIcon->aFrame[0].hbmMask = IconInfo.hbmMask;
-    CurIcon->aFrame[0].hbmColor = IconInfo.hbmColor;
-    CurIcon->aFrame[0].hbmAlpha = NULL;
-
-    if (IconInfo.hbmColor)
-    {
-        BOOLEAN bAlpha = FALSE;
-        psurfBmp = SURFACE_ShareLockSurface(IconInfo.hbmColor);
-        if (!psurfBmp)
-            goto done;
-        CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
-        CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
-        
-        /* 32bpp bitmap is likely to have an alpha channel */
-        if(psurfBmp->SurfObj.iBitmapFormat == BMF_32BPP)
-        {
-            PFN_DIB_GetPixel fn_GetPixel = DibFunctionsForBitmapFormat[BMF_32BPP].DIB_GetPixel;
-            INT i, j;
-
-            fn_GetPixel = DibFunctionsForBitmapFormat[BMF_32BPP].DIB_GetPixel;
-            for (i = 0; i < psurfBmp->SurfObj.sizlBitmap.cx; i++)
-            {
-                for (j = 0; j < psurfBmp->SurfObj.sizlBitmap.cy; j++)
-                {
-                    bAlpha = ((BYTE)(fn_GetPixel(&psurfBmp->SurfObj, i, j) >> 24)) != 0;
-                    if (bAlpha)
-                        break;
-                }
-                if (bAlpha)
-                    break;
-            }
-        }
-        /* We're done with this one */
-        SURFACE_ShareUnlockSurface(psurfBmp);
-        GreSetObjectOwner(IconInfo.hbmColor, GDI_OBJ_HMGR_PUBLIC);
-        
-        if(bAlpha)
-        {
-            UCHAR Alpha;
-            PUCHAR ptr;
-            INT i, j;
-            /* Copy the bitmap */
-            CurIcon->aFrame[0].hbmAlpha = BITMAP_CopyBitmap(IconInfo.hbmColor);
-            if(!CurIcon->aFrame[0].hbmAlpha)
-            {
-                ERR("BITMAP_CopyBitmap failed!");
-                goto done;
-            }
-
-            psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmAlpha);
-            if(!psurfBmp)
-            {
-                ERR("SURFACE_LockSurface failed!\n");
-                goto done;
-            }
-
-            /* Premultiply with the alpha channel value */
-            for (i = 0; i < psurfBmp->SurfObj.sizlBitmap.cy; i++)
-            {
-                       ptr = (PBYTE)psurfBmp->SurfObj.pvScan0 + i*psurfBmp->SurfObj.lDelta;
-                for (j = 0; j < psurfBmp->SurfObj.sizlBitmap.cx; j++)
-                {
-                    Alpha = ptr[3];
-                    ptr[0] = (ptr[0] * Alpha) / 0xff;
-                    ptr[1] = (ptr[1] * Alpha) / 0xff;
-                    ptr[2] = (ptr[2] * Alpha) / 0xff;
-                               ptr += 4;
-                }
-            }
-            SURFACE_ShareUnlockSurface(psurfBmp);
-            GreSetObjectOwner(CurIcon->aFrame[0].hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
-        }
-    }
-    else
-    {
-        psurfBmp = SURFACE_ShareLockSurface(IconInfo.hbmMask);
-        if (!psurfBmp)
-            goto done;
-
-        CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
-        CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
-
-        SURFACE_ShareUnlockSurface(psurfBmp);
-    }
-    GreSetObjectOwner(IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
-
-    Ret = TRUE;
-
-done:
-
-    if (CurIcon)
-    {
-        UserDereferenceObject(CurIcon);
-    }
-    RETURN(Ret);
-
-CLEANUP:
-    TRACE("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
-    UserLeave();
-    END_CLEANUP;
+    FIXME(" is UNIMPLEMENTED.\n");
+    return FALSE;
 }
 
 
@@ -1066,20 +934,17 @@ NtUserSetCursorIconData(
   _In_     HCURSOR Handle,
   _In_opt_ PUNICODE_STRING pustrModule,
   _In_opt_ PUNICODE_STRING pustrRsrc,
-  _In_     PICONINFO pIconInfo)
+  _In_     const CURSORDATA* pCursorData)
 {
     PCURICON_OBJECT CurIcon;
-    PSURFACE psurfBmp;
     NTSTATUS Status = STATUS_SUCCESS;
-    BOOL Ret = FALSE;
-    ICONINFO ii;
+    BOOLEAN Ret = FALSE;
+    BOOLEAN IsShared = FALSE, IsAnim = FALSE;
+    DWORD numFrames;
+    UINT i = 0;
     
     TRACE("Enter NtUserSetCursorIconData\n");
     
-    /* If a module name is provided, we need a resource name, and vice versa */
-    if((pustrModule && !pustrRsrc) || (!pustrModule && pustrRsrc))
-        return FALSE;
-    
     UserEnterExclusive();
 
     if (!(CurIcon = UserGetCurIconObject(Handle)))
@@ -1091,8 +956,50 @@ NtUserSetCursorIconData(
 
     _SEH2_TRY
     {
-        ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
-        ii = *pIconInfo;
+        ProbeForRead(pCursorData, sizeof(*pCursorData), 1);
+        if(pCursorData->CURSORF_flags & CURSORF_ACON)
+        {
+            /* This is an animated cursor */
+            PACON AniCurIcon = (PACON)CurIcon;
+            DWORD numSteps;
+
+            numFrames = AniCurIcon->cpcur = pCursorData->cpcur;
+            numSteps = AniCurIcon->cicur = pCursorData->cicur;
+            AniCurIcon->iicur = pCursorData->iicur;
+            AniCurIcon->rt = pCursorData->rt;
+
+            /* Calculate size: one cursor object for each frame, and a frame index and jiffies for each "step" */
+            AniCurIcon->aspcur = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, /* Let SEH catch allocation failures */
+                numFrames * sizeof(CURICON_OBJECT*) + numSteps * (sizeof(DWORD) + sizeof(INT)),
+                USERTAG_CURSOR);
+            AniCurIcon->aicur = (DWORD*)(AniCurIcon->aspcur + numFrames);
+            AniCurIcon->ajifRate = (INT*)(AniCurIcon->aicur + numSteps);
+
+            RtlZeroMemory(AniCurIcon->aspcur, numFrames * sizeof(CURICON_OBJECT*));
+
+            ProbeForRead(pCursorData->aicur, numSteps * sizeof(DWORD), 1);
+            RtlCopyMemory(AniCurIcon->aicur, pCursorData->aicur, numSteps * sizeof(DWORD));
+            ProbeForRead(pCursorData->ajifRate, numSteps * sizeof(INT), 1);
+            RtlCopyMemory(AniCurIcon->ajifRate, pCursorData->ajifRate, numSteps * sizeof(INT));
+            
+            AniCurIcon->CURSORF_flags = pCursorData->CURSORF_flags;
+            pCursorData = pCursorData->aspcur;
+
+            IsAnim = TRUE;
+        }
+        else
+        {
+            CurIcon->xHotspot = pCursorData->xHotspot;
+            CurIcon->yHotspot = pCursorData->yHotspot;
+            CurIcon->cx = pCursorData->cx;
+            CurIcon->cy = pCursorData->cy;
+            CurIcon->rt = pCursorData->rt;
+            CurIcon->bpp = pCursorData->bpp;
+            CurIcon->hbmMask = pCursorData->hbmMask;
+            CurIcon->hbmColor = pCursorData->hbmColor;
+            CurIcon->hbmAlpha = pCursorData->hbmAlpha;
+            CurIcon->CURSORF_flags = pCursorData->CURSORF_flags;
+        }
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
@@ -1105,94 +1012,96 @@ NtUserSetCursorIconData(
         SetLastNtError(Status);
         goto done;
     }
-    
-    /* This is probably not what windows does, but consistency checks can't hurt */
-    if(CurIcon->bIcon != ii.fIcon)
+
+    if(IsAnim)
     {
-        EngSetLastError(ERROR_INVALID_PARAMETER);
-        goto done;
+        PACON AniCurIcon = (PACON)CurIcon;
+        /* This is an animated cursor. Create a cursor object for each frame and set up the data */
+        for(i = 0; i < numFrames; i++)
+        {
+            HANDLE hCurFrame = IntCreateCurIconHandle(FALSE);
+            if(!NtUserSetCursorIconData(hCurFrame, NULL, NULL, pCursorData))
+                goto done;
+            AniCurIcon->aspcur[i] = UserGetCurIconObject(hCurFrame);
+            if(!AniCurIcon->aspcur[i])
+                goto done;
+            pCursorData++;
+        }
     }
-    CurIcon->ptlHotspot.x = ii.xHotspot;
-    CurIcon->ptlHotspot.y = ii.yHotspot;
     
-    if(!ii.hbmMask)
+    if(CurIcon->CURSORF_flags & CURSORF_LRSHARED)
     {
-        EngSetLastError(ERROR_INVALID_PARAMETER);
-        goto done;
+        IsShared = TRUE;
+        if(pustrRsrc && pustrModule)
+        {
+            UNICODE_STRING ustrModuleSafe;
+            /* We use this convenient function, because INTRESOURCEs and ATOMs are the same */
+            Status = ProbeAndCaptureUnicodeStringOrAtom(&CurIcon->strName, pustrRsrc);
+            if(!NT_SUCCESS(Status))
+                goto done;
+            Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
+            if(!NT_SUCCESS(Status))
+                goto done;
+            Status = RtlAddAtomToAtomTable(gAtomTable, ustrModuleSafe.Buffer, &CurIcon->atomModName);
+            ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode);
+            if(!NT_SUCCESS(Status))
+                goto done;
+        }
     }
-        
-    CurIcon->aFrame[0].hbmMask = BITMAP_CopyBitmap(ii.hbmMask);
-    if(!CurIcon->aFrame[0].hbmMask)
-        goto done;
 
-    if(ii.hbmColor)
+    if(!CurIcon->hbmMask)
     {
-        CurIcon->aFrame[0].hbmColor = BITMAP_CopyBitmap(ii.hbmColor);
-        if(!CurIcon->aFrame[0].hbmColor)
-            goto done;
+        ERR("NtUserSetCursorIconData was got no hbmMask.\n");
+        EngSetLastError(ERROR_INVALID_PARAMETER);
+        goto done;
     }
 
-    if (CurIcon->aFrame[0].hbmColor)
-    {
-        psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmColor);
-        if(!psurfBmp)
-            goto done;
-
-        CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
-        CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
-        SURFACE_ShareUnlockSurface(psurfBmp);
-        GreSetObjectOwner(CurIcon->aFrame[0].hbmColor, GDI_OBJ_HMGR_PUBLIC);
-    }
-    else
-    {
-        psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmMask);
-        if(!psurfBmp)
-            goto done;
+    GreSetObjectOwner(CurIcon->hbmMask, GDI_OBJ_HMGR_PUBLIC);
 
-        CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
-        CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy/2;
-        SURFACE_ShareUnlockSurface(psurfBmp);
-    }
-    GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_PUBLIC);
+    if(CurIcon->hbmColor)
+        GreSetObjectOwner(CurIcon->hbmColor, GDI_OBJ_HMGR_PUBLIC);
     
-    if(pustrModule)
+    if(CurIcon->hbmAlpha)
+        GreSetObjectOwner(CurIcon->hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
+
+    if(IsShared)
     {
-        /* We use this convenient function, because INTRESOURCEs and ATOMs are the same */
-        Status = ProbeAndCaptureUnicodeStringOrAtom(&CurIcon->ustrRsrc, pustrRsrc);
-        if(!NT_SUCCESS(Status))
-            goto done;
-        Status = ProbeAndCaptureUnicodeString(&CurIcon->ustrModule, UserMode, pustrModule);
-        if(!NT_SUCCESS(Status))
-            goto done;
+        /* Update process cache in case of shared cursor */
+        PPROCESSINFO ppi = CurIcon->head.ppi;
+        UserReferenceObject(CurIcon);
+        CurIcon->pcurNext = ppi->pCursorCache;
+        ppi->pCursorCache = CurIcon;
     }
     
     Ret = TRUE;
 
 done:
-    UserDereferenceObject(CurIcon);
-    if(!Ret)
+    if(!Ret && IsShared)
     {
-        if (CurIcon->aFrame[0].hbmMask)
-        {
-            GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_POWNED);
-            GreDeleteObject(CurIcon->aFrame[0].hbmMask);
-            CurIcon->aFrame[0].hbmMask = NULL;
-        }
-        if (CurIcon->aFrame[0].hbmColor)
+        if(!IS_INTRESOURCE(CurIcon->strName.Buffer))
+            ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
+    }
+
+    if(!Ret && IsAnim)
+    {
+        PACON AniCurIcon = (PACON)CurIcon;
+        for(i = 0; i < numFrames; i++)
         {
-            GreSetObjectOwner(CurIcon->aFrame[0].hbmColor, GDI_OBJ_HMGR_POWNED);
-            GreDeleteObject(CurIcon->aFrame[0].hbmColor);
-            CurIcon->aFrame[0].hbmColor = NULL;
+            if(AniCurIcon->aspcur[i])
+                IntDestroyCurIconObject(AniCurIcon->aspcur[i], TRUE);
         }
-        if(!IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer))
-            ExFreePoolWithTag(CurIcon->ustrRsrc.Buffer, TAG_STRING);
-        if(CurIcon->ustrModule.Buffer)
-            ReleaseCapturedUnicodeString(&CurIcon->ustrModule, UserMode);
+        AniCurIcon->cicur = 0;
+        AniCurIcon->cpcur = 0;
+        ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
+        AniCurIcon->aspcur = NULL;
+        AniCurIcon->aicur = NULL;
+        AniCurIcon->ajifRate = NULL;
     }
 
+    UserDereferenceObject(CurIcon);
     TRACE("Leave NtUserSetCursorIconData, ret=%i\n",Ret);
     UserLeave();
-    
+
     return Ret;
 }
 
@@ -1232,12 +1141,20 @@ UserDrawIconEx(
         return FALSE;
     }
 
-    hbmMask = pIcon->aFrame[0].hbmMask;
-    hbmColor = pIcon->aFrame[0].hbmColor;
-    hbmAlpha = pIcon->aFrame[0].hbmAlpha;
-    
-    if (istepIfAniCur)
-        ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
+    if (pIcon->CURSORF_flags & CURSORF_ACON)
+    {
+        ACON* pAcon = (ACON*)pIcon;
+        if(istepIfAniCur >= pAcon->cicur)
+        {
+            ERR("NtUserDrawIconEx: istepIfAniCur too big!\n");
+            return FALSE;
+        }
+        pIcon = pAcon->aspcur[pAcon->aicur[istepIfAniCur]];
+    }
+
+    hbmMask = pIcon->hbmMask;
+    hbmColor = pIcon->hbmColor;
+    hbmAlpha = pIcon->hbmAlpha;
     
     /*
      * Get our objects. 
@@ -1254,7 +1171,7 @@ UserDrawIconEx(
     if(hbmColor == NULL)
     {
         /* But then the mask bitmap must have the information in it's bottom half */
-        ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->Size.cy);
+        ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->cy);
         psurfColor = NULL;
     }
     else if ((psurfColor = SURFACE_ShareLockSurface(hbmColor)) == NULL)
@@ -1278,7 +1195,7 @@ UserDrawIconEx(
     RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
     
     /* Prepare the underlying surface */
-    DC_vPrepareDCsForBlit(pdc, rcDest, NULL, rcDest);
+    DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
 
     /* We now have our destination surface and rectangle */
     psurfDest = pdc->dclevel.pSurface;
@@ -1294,26 +1211,26 @@ UserDrawIconEx(
     }
     
     /* Set source rect */
-    RECTL_vSetRect(&rcSrc, 0, 0, pIcon->Size.cx, pIcon->Size.cy);
+    RECTL_vSetRect(&rcSrc, 0, 0, pIcon->cx, pIcon->cy);
 
     /* Fix width parameter, if needed */
     if (!cxWidth)
     {
         if(diFlags & DI_DEFAULTSIZE)
-            cxWidth = pIcon->bIcon ? 
+            cxWidth = is_icon(pIcon) ? 
                 UserGetSystemMetrics(SM_CXICON) : UserGetSystemMetrics(SM_CXCURSOR);
         else
-            cxWidth = pIcon->Size.cx;
+            cxWidth = pIcon->cx;
     }
     
     /* Fix height parameter, if needed */
     if (!cyHeight)
     {
         if(diFlags & DI_DEFAULTSIZE)
-            cyHeight = pIcon->bIcon ? 
+            cyHeight = is_icon(pIcon) ? 
                 UserGetSystemMetrics(SM_CYICON) : UserGetSystemMetrics(SM_CYCURSOR);
         else
-            cyHeight = pIcon->Size.cy;
+            cyHeight = pIcon->cy;
     }
 
     /* Should we render off-screen? */
@@ -1374,7 +1291,7 @@ UserDrawIconEx(
         /* We now have our destination surface */
         psurfDest = psurfOffScreen;
 #else
-        pdcClipObj = pdc->rosdc.CombinedClip;
+        pdcClipObj = &pdc->co.ClipObj;
         /* Paint the brush */
         EBRUSHOBJ_vInit(&eboFill, pbrush, psurfDest, 0x00FFFFFF, 0, NULL);
         
@@ -1405,14 +1322,14 @@ UserDrawIconEx(
     {
         /* We directly draw to the DC */
         TRACE("Performing on screen rendering.\n");
-        pdcClipObj = pdc->rosdc.CombinedClip;
+        pdcClipObj = &pdc->co.ClipObj;
         // psurfOffScreen = NULL;
     }
 
     /* Now do the rendering */
-       if(hbmAlpha && (diFlags & DI_IMAGE))
-       {
-           BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
+    if(hbmAlpha && ((diFlags & DI_NORMAL) == DI_NORMAL))
+    {
+        BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
         PSURFACE psurf = NULL;
 
         psurf = SURFACE_ShareLockSurface(hbmAlpha);
@@ -1437,7 +1354,7 @@ UserDrawIconEx(
         EXLATEOBJ_vCleanup(&exlo);
         SURFACE_ShareUnlockSurface(psurf);
         if(Ret) goto done;
-               ERR("NtGdiAlphaBlend failed!\n");
+        ERR("NtGdiAlphaBlend failed!\n");
     }
 NoAlpha:
     if (diFlags & DI_MASK)
@@ -1470,7 +1387,7 @@ NoAlpha:
 
     if(diFlags & DI_IMAGE)
     {
-               if (psurfColor)
+        if (psurfColor)
         {
             DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ;
             
@@ -1501,7 +1418,7 @@ NoAlpha:
         {
             /* Mask bitmap holds the information in its bottom half */
             DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY;
-            RECTL_vOffsetRect(&rcSrc, 0, pIcon->Size.cy);
+            RECTL_vOffsetRect(&rcSrc, 0, pIcon->cy);
             
             EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
         
@@ -1633,4 +1550,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 */