* Sync up to trunk head (r64921).
[reactos.git] / win32ss / user / ntuser / cursoricon_new.c
index 0c772a2..2fbfe99 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))
+    {
+        WARN("Requesting invalid/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,223 +124,154 @@ 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)
+HANDLE
+IntCreateCurIconHandle(BOOLEAN Animated)
 {
-    PPROCESSINFO Win32Process;
-    PCURICON_PROCESS Current;
-
-    Win32Process = PsGetCurrentProcessWin32Process();
+    PCURICON_OBJECT CurIcon;
+    HANDLE hCurIcon;
 
-    LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
-    {
-        if (Current->Process == Win32Process)
-        {
-            /* Already registered for this process */
-            return TRUE;
-        }
-    }
+    CurIcon = UserCreateObject(
+        gHandleTable,
+        NULL,
+        GetW32ThreadInfo(),
+        &hCurIcon,
+        TYPE_CURSOR,
+        Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT));
 
-    /* Not registered yet */
-    Current = ExAllocateFromPagedLookasideList(pgProcessLookasideList);
-    if (NULL == Current)
+    if (!CurIcon)
     {
+        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return FALSE;
     }
-    InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
-    Current->Process = Win32Process;
 
-    return TRUE;
+    UserDereferenceObject(CurIcon);
+
+    return hCurIcon;
 }
 
-PCURICON_OBJECT FASTCALL
-IntFindExistingCurIconObject(HMODULE hModule,
-                             HRSRC hRsrc, LONG cx, LONG cy)
+BOOLEAN
+IntDestroyCurIconObject(
+    _In_ PVOID Object)
 {
-    PCURICON_OBJECT CurIcon;
+    PCURICON_OBJECT CurIcon = Object;
 
-    LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
+    /* Try finding it in its process cache */
+    if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
     {
+        PPROCESSINFO ppi;
 
-        // if (NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) // <- huh????
-//      UserReferenceObject(  CurIcon);
-//      {
-        if ((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
+        ppi = CurIcon->head.ppi;
+        if (ppi->pCursorCache == CurIcon)
         {
-            if (cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
-            {
-//               UserDereferenceObject(CurIcon);
-                continue;
-            }
-            if (! ReferenceCurIconByProcess(CurIcon))
+            ppi->pCursorCache = CurIcon->pcurNext;
+            UserDereferenceObject(CurIcon);
+        }
+        else
+        {
+            PCURICON_OBJECT CacheCurIcon = ppi->pCursorCache;
+            while (CacheCurIcon)
             {
-                return NULL;
+                if (CacheCurIcon->pcurNext == CurIcon)
+                {
+                    CacheCurIcon->pcurNext = CurIcon->pcurNext;
+                    break;
+                }
+                CacheCurIcon = CacheCurIcon->pcurNext;
             }
 
-            return CurIcon;
+            /* We must have found it! */
+            ASSERT(CacheCurIcon != NULL);
+            UserDereferenceObject(CurIcon);
         }
-//      }
-//      UserDereferenceObject(CurIcon);
-
-    }
-
-    return NULL;
-}
-
-PCURICON_OBJECT
-IntCreateCurIconHandle()
-{
-    PCURICON_OBJECT CurIcon;
-    HANDLE hCurIcon;
-
-    CurIcon = UserCreateObject(gHandleTable, NULL, NULL, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
-
-    if (!CurIcon)
-    {
-        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return FALSE;
-    }
-
-    CurIcon->Self = hCurIcon;
-    InitializeListHead(&CurIcon->ProcessList);
-
-    if (! ReferenceCurIconByProcess(CurIcon))
-    {
-        ERR("Failed to add process\n");
-        UserDeleteObject(hCurIcon, otCursorIcon);
-        UserDereferenceObject(CurIcon);
-        return NULL;
     }
 
-    InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
-
-    return CurIcon;
+    /* We just mark the handle as being destroyed.
+     * Deleting all the stuff will be deferred to the actual struct free. */
+    return UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
 }
 
-BOOLEAN FASTCALL
-IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi)
+void
+FreeCurIconObject(
+    _In_ PVOID Object)
 {
-    PSYSTEM_CURSORINFO CurInfo;
-    HBITMAP bmpMask, bmpColor, bmpAlpha;
-    BOOLEAN Ret, bListEmpty, bFound = FALSE;
-    PCURICON_PROCESS Current = NULL;
+    PCURICON_OBJECT CurIcon = Object;
     
-    /* 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_ACON))
     {
-        if (Current->Process == ppi)
+        HBITMAP bmpMask = CurIcon->hbmMask;
+        HBITMAP bmpColor = CurIcon->hbmColor;
+        HBITMAP bmpAlpha = CurIcon->hbmAlpha;
+
+        /* Delete bitmaps */
+        if (bmpMask)
         {
-            bFound = TRUE;
-            bListEmpty = RemoveEntryList(&Current->ListEntry);
-            break;
+            GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
+            GreDeleteObject(bmpMask);
+            CurIcon->hbmMask = NULL;
         }
-    }
-    
-    if(!bFound)
-    {
-        /* This object doesn't belong to this process */
-        EngSetLastError(ERROR_INVALID_HANDLE);
-        return FALSE;
-    }
-
-    ExFreeToPagedLookasideList(pgProcessLookasideList, Current);
-
-    /* If there are still processes referencing this object we can't destroy it yet */
-    if (!bListEmpty)
-    {
-        if(CurIcon->head.ppi == ppi)
+        if (bmpColor)
         {
-            /* Set the first process of the list as owner */
-            Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
-            UserSetObjectOwner(CurIcon, otCursorIcon, Current->Process);
+            GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
+            GreDeleteObject(bmpColor);
+            CurIcon->hbmColor = NULL;
+        }
+        if (bmpAlpha)
+        {
+            GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED);
+            GreDeleteObject(bmpAlpha);
+            CurIcon->hbmAlpha = NULL;
         }
-        UserDereferenceObject(CurIcon);
-        return TRUE;
     }
-
-emptyList:
-    /* Remove it from the list */
-    RemoveEntryList(&CurIcon->ListEntry);
-
-    CurInfo = IntGetSysCursorInfo();
-
-    if (CurInfo->CurrentCursorObject == CurIcon)
+    else
     {
-        /* Hide the cursor if we're destroying the current cursor */
-        UserSetCursor(NULL, TRUE);
-    }
-
-    bmpMask = CurIcon->aFrame[0].hbmMask;
-    bmpColor = CurIcon->aFrame[0].hbmColor;
-    bmpAlpha = CurIcon->aFrame[0].hbmAlpha;
+        PACON AniCurIcon = (PACON)CurIcon;
+        UINT i;
 
-    /* Delete bitmaps */
-    if (bmpMask)
-    {
-        GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
-        GreDeleteObject(bmpMask);
-        CurIcon->aFrame[0].hbmMask = NULL;
-    }
-    if (bmpColor)
-    {
-        GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
-        GreDeleteObject(bmpColor);
-        CurIcon->aFrame[0].hbmColor = NULL;
+        for(i = 0; i < AniCurIcon->cpcur; i++)
+            IntDestroyCurIconObject(AniCurIcon->aspcur[i]);
+        ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
     }
-    if (bmpAlpha)
+
+    if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
     {
-        GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED);
-        GreDeleteObject(bmpAlpha);
-        CurIcon->aFrame[0].hbmAlpha = NULL;
+        if (!IS_INTRESOURCE(CurIcon->strName.Buffer))
+            ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
+        if (CurIcon->atomModName)
+            RtlDeleteAtomFromAtomTable(gAtomTable, CurIcon->atomModName);
+        CurIcon->strName.Buffer = NULL;
+        CurIcon->atomModName = 0;
     }
 
-    /* We were given a pointer, no need to keep the reference anylonger! */
-    UserDereferenceObject(CurIcon);
-    Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
-
-    return Ret;
+    /* Finally free the thing */
+    FreeProcMarkObject(CurIcon);
 }
 
 VOID FASTCALL
-IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
+IntCleanupCurIconCache(PPROCESSINFO Win32Process)
 {
-    PCURICON_OBJECT CurIcon, tmp;
+    PCURICON_OBJECT CurIcon;
 
     /* Run through the list of icon objects */
-    LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
+    while (Win32Process->pCursorCache)
     {
-        UserReferenceObject(CurIcon);
-        IntDestroyCurIconObject(CurIcon, Win32Process);
+        CurIcon = Win32Process->pCursorCache;
+        Win32Process->pCursorCache = CurIcon->pcurNext;
+        UserDereferenceObject(CurIcon);
     }
 }
 
-
 /*
  * @implemented
  */
 BOOL
 APIENTRY
 NtUserGetIconInfo(
-    HANDLE hCurIcon,
-    PICONINFO IconInfo,
-    PUNICODE_STRING lpInstName, // Optional
-    PUNICODE_STRING lpResName,  // Optional
-    LPDWORD pbpp,               // Optional
-    BOOL bInternal)
+  _In_       HANDLE hCurIcon,
+  _Out_opt_  PICONINFO IconInfo,
+  _Out_opt_  PUNICODE_STRING lpModule,   // Optional
+  _Out_opt_  PUNICODE_STRING lpResName,  // Optional
+  _Out_opt_  LPDWORD pbpp,               // Optional
+  _In_       BOOL bInternal)
 {
     ICONINFO ii;
     PCURICON_OBJECT CurIcon;
@@ -356,66 +280,150 @@ NtUserGetIconInfo(
     DWORD colorBpp = 0;
 
     TRACE("Enter NtUserGetIconInfo\n");
-    UserEnterExclusive();
 
-    if (!IconInfo)
+    /* Check if something was actually asked */
+    if (!IconInfo && !lpModule && !lpResName)
     {
+        WARN("Nothing to fill.\n");
         EngSetLastError(ERROR_INVALID_PARAMETER);
-        goto leave;
+        return FALSE;
     }
+    
+    UserEnterExclusive();
 
     if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
     {
-        goto leave;
+        WARN("UserGetIconObject(0x%08x) Failed.\n", hCurIcon);
+        UserLeave();
+        return FALSE;
     }
     
-    /* Fill data */
-    ii.fIcon = CurIcon->bIcon;
-    ii.xHotspot = CurIcon->ptlHotspot.x;
-    ii.yHotspot = CurIcon->ptlHotspot.y;
-
-    /* Copy bitmaps */
-    ii.hbmMask = BITMAP_CopyBitmap(CurIcon->aFrame[0].hbmMask);
-    ii.hbmColor = BITMAP_CopyBitmap(CurIcon->aFrame[0].hbmColor);
-
-    if (pbpp)
+    /* Give back the icon information */
+    if(IconInfo)
     {
-        PSURFACE psurfBmp;
+        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(FrameCurIcon);
+        ii.xHotspot = FrameCurIcon->xHotspot;
+        ii.yHotspot = FrameCurIcon->yHotspot;
+
+        /* Copy bitmaps */
+        ii.hbmMask = BITMAP_CopyBitmap(FrameCurIcon->hbmMask);
+        GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED);
+        ii.hbmColor = BITMAP_CopyBitmap(FrameCurIcon->hbmColor);
+        GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED);
+        colorBpp = FrameCurIcon->bpp;
+
+        /* Copy fields */
+        _SEH2_TRY
+        {
+            ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
+            RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
+
+            if (pbpp)
+            {
+                ProbeForWrite(pbpp, sizeof(DWORD), 1);
+                *pbpp = colorBpp;
+            }
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Status = _SEH2_GetExceptionCode();
+        }
+        _SEH2_END
 
-        psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmColor);
-        if (psurfBmp)
+        if (!NT_SUCCESS(Status))
         {
-            colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
-            SURFACE_ShareUnlockSurface(psurfBmp);
+            WARN("Status: 0x%08x.\n", Status);
+            SetLastNtError(Status);
+            goto leave;
         }
     }
 
-    /* Copy fields */
-    _SEH2_TRY
+    /* Give back the module name */
+    if(lpModule)
     {
-        ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
-        RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
+        ULONG BufLen = 0;
+        if (!CurIcon->atomModName)
+            goto leave;
+
+        RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, NULL, &BufLen);
+        /* Get the module name from the atom table */
+        _SEH2_TRY
+        {
+            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 (pbpp)
+        if (!NT_SUCCESS(Status))
         {
-            ProbeForWrite(pbpp, sizeof(DWORD), 1);
-            *pbpp = colorBpp;
+            SetLastNtError(Status);
+            goto leave;
         }
     }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    
+    if (lpResName)
     {
-        Status = _SEH2_GetExceptionCode();
+        if (!CurIcon->strName.Buffer)
+            goto leave;
+
+        /* Copy it */
+        _SEH2_TRY
+        {
+            ProbeForWrite(lpResName, sizeof(UNICODE_STRING), 1);
+            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
+            {
+                ProbeForWrite(lpResName->Buffer, lpResName->MaximumLength * sizeof(WCHAR), 1);
+                RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, lpResName->Length);
+            }
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Status = _SEH2_GetExceptionCode();
+        }
+        _SEH2_END
     }
-    _SEH2_END
 
-    if (NT_SUCCESS(Status))
-        Ret = TRUE;
-    else
+    if (!NT_SUCCESS(Status))
+    {
         SetLastNtError(Status);
+        goto leave;
+    }
+    
+    Ret = TRUE;
 
+leave:
     UserDereferenceObject(CurIcon);
 
-leave:
     TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret);
     UserLeave();
 
@@ -446,12 +454,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)
     {
@@ -496,7 +513,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;
 
@@ -606,7 +623,7 @@ NtUserClipCursor(
         prcl = &rclLocal;
     }
 
-       UserEnterExclusive();
+    UserEnterExclusive();
 
     /* Call the internal function */
     bResult = UserClipCursor(prcl);
@@ -623,30 +640,57 @@ NtUserClipCursor(
 BOOL
 APIENTRY
 NtUserDestroyCursor(
-    HANDLE hCurIcon,
-    DWORD Unknown)
+  _In_   HANDLE hCurIcon,
+  _In_   BOOL bForce)
 {
-    PCURICON_OBJECT CurIcon;
     BOOL ret;
-    DECLARE_RETURN(BOOL);
+    PCURICON_OBJECT CurIcon = NULL;
 
-    TRACE("Enter NtUserDestroyCursorIcon\n");
+    TRACE("Enter NtUserDestroyCursorIcon (%p, %u)\n", hCurIcon, bForce);
     UserEnterExclusive();
 
-    if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+    CurIcon = UserGetCurIconObject(hCurIcon);
+    if (!CurIcon)
     {
-        RETURN(FALSE);
+        ret = FALSE;
+        goto leave;
     }
 
-    ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process());
-    /* Note: IntDestroyCurIconObject will remove our reference for us! */
+    if (!bForce)
+    {
+        /* Maybe we have good reasons not to destroy this object */
+        if (CurIcon->head.ppi != PsGetCurrentProcessWin32Process())
+        {
+            /* No way, you're not touching my cursor */
+            ret = FALSE;
+            goto leave;
+        }
+
+        if (CurIcon->CURSORF_flags & CURSORF_CURRENT)
+        {
+            WARN("Trying to delete current cursor!\n");
+            ret = FALSE;
+            goto leave;
+        }
+
+        if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
+        {
+            WARN("Trying to delete shared cursor.\n");
+            /* This one is not an error */
+            ret = TRUE;
+            goto leave;
+        }
+    }
 
-    RETURN(ret);
+    /* Destroy the handle */
+    ret = IntDestroyCurIconObject(CurIcon);
 
-CLEANUP:
-    TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
+leave:
+    if (CurIcon)
+        UserDereferenceObject(CurIcon);
+    TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n", ret);
     UserLeave();
-    END_CLEANUP;
+    return ret;
 }
 
 
@@ -654,36 +698,95 @@ CLEANUP:
  * @implemented
  */
 HICON
-APIENTRY
+NTAPI
 NtUserFindExistingCursorIcon(
-    HMODULE hModule,
-    HRSRC hRsrc,
-    LONG cx,
-    LONG cy)
+  _In_  PUNICODE_STRING pustrModule,
+  _In_  PUNICODE_STRING pustrRsrc,
+  _In_  FINDEXISTINGCURICONPARAM* param)
 {
     PCURICON_OBJECT CurIcon;
-    HANDLE Ret = (HANDLE)0;
-    DECLARE_RETURN(HICON);
+    HICON Ret = NULL;
+    UNICODE_STRING ustrModuleSafe, ustrRsrcSafe;
+    FINDEXISTINGCURICONPARAM paramSafe;
+    NTSTATUS Status;
+    PPROCESSINFO pProcInfo = PsGetCurrentProcessWin32Process();
+    RTL_ATOM atomModName;
 
     TRACE("Enter NtUserFindExistingCursorIcon\n");
-    UserEnterExclusive();
-
-    CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy);
-    if (CurIcon)
+    
+    
+    _SEH2_TRY
     {
-        Ret = CurIcon->Self;
-
-//      IntReleaseCurIconObject(CurIcon); // FIXME: Is this correct? Does IntFindExistingCurIconObject add a ref?
-        RETURN(Ret);
+        ProbeForRead(param, sizeof(*param), 1);
+        RtlCopyMemory(&paramSafe, param, sizeof(paramSafe));
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
     }
+    _SEH2_END
 
-    EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
-    RETURN((HANDLE)0);
+    /* 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;
+    }
 
-CLEANUP:
-    TRACE("Leave NtUserFindExistingCursorIcon, ret=%p\n",_ret_);
+    UserEnterExclusive();
+    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();
-    END_CLEANUP;
+
+done:
+    if(!IS_INTRESOURCE(ustrRsrcSafe.Buffer))
+        ExFreePoolWithTag(ustrRsrcSafe.Buffer, TAG_STRING);
+    
+    return Ret;
 }
 
 
@@ -747,7 +850,7 @@ NtUserSetCursor(
     PCURICON_OBJECT pcurOld, pcurNew;
     HCURSOR hOldCursor = NULL;
 
-    TRACE("Enter NtUserSetCursor\n");
+    TRACE("Enter NtUserSetCursor: %p\n", hCursor);
     UserEnterExclusive();
 
     if (hCursor)
@@ -758,6 +861,7 @@ NtUserSetCursor(
             EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
             goto leave;
         }
+        pcurNew->CURSORF_flags |= CURSORF_CURRENT;
     }
     else
     {
@@ -767,7 +871,11 @@ NtUserSetCursor(
     pcurOld = UserSetCursor(pcurNew, FALSE);
     if (pcurOld)
     {
-        hOldCursor = (HCURSOR)pcurOld->Self;
+        hOldCursor = pcurOld->head.h;
+        /* See if it was destroyed in the meantime */
+        if (UserObjectInDestroy(hOldCursor))
+            hOldCursor = NULL;
+        pcurOld->CURSORF_flags &= ~CURSORF_CURRENT;
         UserDereferenceObject(pcurOld);
     }
 
@@ -778,7 +886,7 @@ leave:
 
 
 /*
- * @implemented
+ * @unimplemented
  */
 BOOL
 APIENTRY
@@ -786,193 +894,86 @@ 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(!Ret)
-    {
-        IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process());
-        CurIcon = NULL;
-    }
-
-    if (CurIcon)
-    {
-        UserDereferenceObject(CurIcon);
-    }
-    RETURN(Ret);
-
-CLEANUP:
-    TRACE("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
-    UserLeave();
-    END_CLEANUP;
-}
+    FIXME(" is UNIMPLEMENTED.\n");
+    return FALSE;
+}
 
 
 /*
  * @implemented
  */
-#ifdef NEW_CURSORICON
 BOOL
 APIENTRY
 NtUserSetCursorIconData(
-  _In_ HCURSOR Handle,
-  _In_ HINSTANCE hinst,
-  _In_ HRSRC hrsrc,
-  _In_ PICONINFO pIconInfo)
+  _In_     HCURSOR Handle,
+  _In_opt_ PUNICODE_STRING pustrModule,
+  _In_opt_ PUNICODE_STRING pustrRsrc,
+  _In_     const CURSORDATA* pCursorData)
 {
     PCURICON_OBJECT CurIcon;
-    PSURFACE psurfBmp;
     NTSTATUS Status = STATUS_SUCCESS;
-    BOOL Ret = FALSE;
-    DECLARE_RETURN(BOOL);
-    ICONINFO ii;
-
+    BOOLEAN Ret = FALSE;
+    BOOLEAN IsShared = FALSE, IsAnim = FALSE;
+    DWORD numFrames;
+    UINT i = 0;
+    
     TRACE("Enter NtUserSetCursorIconData\n");
+    
     UserEnterExclusive();
 
     if (!(CurIcon = UserGetCurIconObject(Handle)))
     {
-        RETURN(FALSE);
+        UserLeave();
+        EngSetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
     }
 
-    CurIcon->hModule = hinst;
-    CurIcon->hRsrc =hrsrc;
-
     _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)
     {
@@ -985,167 +986,98 @@ NtUserSetCursorIconData(
         SetLastNtError(Status);
         goto done;
     }
-    
-    /* This is probably not what windows does, but consistency checks can't hurt */
-    if(CurIcon->bIcon != ii.fIcon)
-    {
-        EngSetLastError(ERROR_INVALID_PARAMETER);
-        goto done;
-    }
-    CurIcon->ptlHotspot.x = ii.xHotspot;
-    CurIcon->ptlHotspot.y = ii.yHotspot;
-    
-    if(!ii.hbmMask)
-    {
-        EngSetLastError(ERROR_INVALID_PARAMETER);
-        goto done;
-    }
-        
-    CurIcon->aFrame[0].hbmMask = BITMAP_CopyBitmap(ii.hbmMask);
-    if(!CurIcon->aFrame[0].hbmMask)
-        goto done;
-
-    if(ii.hbmColor)
-    {
-        CurIcon->aFrame[0].hbmColor = BITMAP_CopyBitmap(ii.hbmColor);
-        if(!CurIcon->aFrame[0].hbmColor)
-            goto done;
-    }
 
-    if (CurIcon->aFrame[0].hbmColor)
+    if(IsAnim)
     {
-        if ((psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmColor)))
+        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++)
         {
-            CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
-            CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
-            SURFACE_ShareUnlockSurface(psurfBmp);
-            GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_PUBLIC);
+            HANDLE hCurFrame = IntCreateCurIconHandle(FALSE);
+            if(!NtUserSetCursorIconData(hCurFrame, NULL, NULL, pCursorData))
+                goto done;
+            AniCurIcon->aspcur[i] = UserGetCurIconObject(hCurFrame);
+            if(!AniCurIcon->aspcur[i])
+                goto done;
+            pCursorData++;
         }
-        else
-            goto done;
     }
-    else
+    
+    if(CurIcon->CURSORF_flags & CURSORF_LRSHARED)
     {
-       if ((psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmMask)))
+        IsShared = TRUE;
+        if(pustrRsrc && pustrModule)
         {
-            CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
-            CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy/2;
-            SURFACE_ShareUnlockSurface(psurfBmp);
+            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;
         }
-        else
-            goto done;
     }
-    GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_PUBLIC);
-    
-    Ret = TRUE;
 
-done:
-    UserDereferenceObject(CurIcon);
-    if(!Ret)
+    if(!CurIcon->hbmMask)
     {
-        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)
-        {
-            GreSetObjectOwner(CurIcon->aFrame[0].hbmColor, GDI_OBJ_HMGR_POWNED);
-            GreDeleteObject(CurIcon->aFrame[0].hbmColor);
-            CurIcon->aFrame[0].hbmColor = NULL;
-        }
+        ERR("NtUserSetCursorIconData was got no hbmMask.\n");
+        EngSetLastError(ERROR_INVALID_PARAMETER);
+        goto done;
     }
-    RETURN(Ret);
 
-CLEANUP:
-    TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
-    UserLeave();
-    END_CLEANUP;
-}
-#else
-BOOL
-APIENTRY
-NtUserSetCursorIconData(
-    HANDLE hCurIcon,
-    PBOOL fIcon,
-    POINT *Hotspot,
-    HMODULE hModule,
-    HRSRC hRsrc,
-    HRSRC hGroupRsrc)
-{
-    PCURICON_OBJECT CurIcon;
-    NTSTATUS Status;
-    BOOL Ret = FALSE;
-    DECLARE_RETURN(BOOL);
+    GreSetObjectOwner(CurIcon->hbmMask, GDI_OBJ_HMGR_PUBLIC);
 
-    TRACE("Enter NtUserSetCursorIconData\n");
-    UserEnterExclusive();
+    if(CurIcon->hbmColor)
+        GreSetObjectOwner(CurIcon->hbmColor, GDI_OBJ_HMGR_PUBLIC);
+    
+    if(CurIcon->hbmAlpha)
+        GreSetObjectOwner(CurIcon->hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
 
-    if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+    if(IsShared)
     {
-        RETURN(FALSE);
+        /* Update process cache in case of shared cursor */
+        PPROCESSINFO ppi = CurIcon->head.ppi;
+        UserReferenceObject(CurIcon);
+        CurIcon->pcurNext = ppi->pCursorCache;
+        ppi->pCursorCache = CurIcon;
     }
+    
+    Ret = TRUE;
 
-    CurIcon->hModule = hModule;
-    CurIcon->hRsrc = hRsrc;
-    CurIcon->hGroupRsrc = hGroupRsrc;
-
-    /* Copy fields */
-    if (fIcon)
+done:
+    if(!Ret && IsShared)
     {
-        Status = MmCopyFromCaller(&CurIcon->bIcon, fIcon, sizeof(BOOL));
-        if (!NT_SUCCESS(Status))
-        {
-            SetLastNtError(Status);
-            goto done;
-        }
-    }
-    else
-    {
-        if (!Hotspot)
-            Ret = TRUE;
+        if(!IS_INTRESOURCE(CurIcon->strName.Buffer))
+            ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
     }
 
-    if (Hotspot)
+    if(!Ret && IsAnim)
     {
-        Status = MmCopyFromCaller(&CurIcon->ptlHotspot, Hotspot, sizeof(POINT));
-        if (!NT_SUCCESS(Status))
+        PACON AniCurIcon = (PACON)CurIcon;
+        for(i = 0; i < numFrames; i++)
         {
-            SetLastNtError(Status);
-            goto done;
+            if(AniCurIcon->aspcur[i])
+                IntDestroyCurIconObject(AniCurIcon->aspcur[i]);
         }
+        AniCurIcon->cicur = 0;
+        AniCurIcon->cpcur = 0;
+        ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
+        AniCurIcon->aspcur = NULL;
+        AniCurIcon->aicur = NULL;
+        AniCurIcon->ajifRate = NULL;
     }
 
-    if (!fIcon && !Hotspot)
-    {
-        Ret = TRUE;
-    }
-
-done:
-       if(Ret)
-       {
-               /* This icon is shared now */
-               GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_PUBLIC);
-               if(CurIcon->aFrame[0].hbmColor)
-               {
-                       GreSetObjectOwner(CurIcon->aFrame[0].hbmColor, GDI_OBJ_HMGR_PUBLIC);
-               }
-               if(CurIcon->aFrame[0].hbmAlpha)
-               {
-                       GreSetObjectOwner(CurIcon->aFrame[0].hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
-               }
-       }
     UserDereferenceObject(CurIcon);
-    RETURN(Ret);
-
-
-CLEANUP:
-    TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
+    TRACE("Leave NtUserSetCursorIconData, ret=%i\n",Ret);
     UserLeave();
-    END_CLEANUP;
+
+    return Ret;
 }
-#endif
 
 /* Mostly inspired from wine code.
  * We use low level functions because:
@@ -1167,7 +1099,7 @@ UserDrawIconEx(
     HBRUSH hbrFlickerFreeDraw,
     UINT diFlags)
 {
-    PSURFACE psurfDest, psurfMask, psurfColor, psurfOffScreen;
+    PSURFACE psurfDest, psurfMask, psurfColor; //, psurfOffScreen = NULL;
     PDC pdc = NULL;
     BOOL Ret = FALSE;
     HBITMAP hbmMask, hbmColor, hbmAlpha;
@@ -1183,12 +1115,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. 
@@ -1205,7 +1145,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)
@@ -1215,31 +1155,61 @@ UserDrawIconEx(
         return FALSE;
     }
     
+    pdc = DC_LockDc(hDc);
+    if(!pdc)
+    {
+        ERR("Could not lock the destination DC.\n");
+        SURFACE_ShareUnlockSurface(psurfMask);
+        if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+        return FALSE;
+    }
+    /* Calculate destination rectangle */
+    RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
+    IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
+    RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
+    
+    /* Prepare the underlying surface */
+    DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
+
+    /* We now have our destination surface and rectangle */
+    psurfDest = pdc->dclevel.pSurface;
+    
+    if(psurfDest == NULL)
+    {
+        /* Empty DC */
+        DC_vFinishBlit(pdc, NULL);
+        DC_UnlockDc(pdc);
+        SURFACE_ShareUnlockSurface(psurfMask);
+        if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+        return FALSE;
+    }
+    
     /* 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? */
-    bOffScreen = hbrFlickerFreeDraw && (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH);
+    bOffScreen = hbrFlickerFreeDraw && 
+        (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH);
 
     if (bOffScreen)
     {
@@ -1252,21 +1222,18 @@ UserDrawIconEx(
         if(!pbrush)
         {
             ERR("Failed to get brush object.\n");
-            SURFACE_ShareUnlockSurface(psurfMask);
-            if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
-            return FALSE;
+            goto Cleanup;
         }
 
+#if 0 //We lock the hdc surface during the whole function it makes no sense to use an offscreen surface for "flicker free" drawing
         psurfOffScreen = SURFACE_AllocSurface(STYPE_BITMAP,
-            cxWidth, cyHeight, psurfColor->SurfObj.iBitmapFormat,
+            cxWidth, cyHeight, psurfDest->SurfObj.iBitmapFormat,
             0, 0, NULL);
         if(!psurfOffScreen)
         {
             ERR("Failed to allocate the off-screen surface.\n");
-            SURFACE_ShareUnlockSurface(psurfMask);
-            if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
             BRUSH_ShareUnlockBrush(pbrush);
-            return FALSE;
+            goto Cleanup;
         }
         
         /* Paint the brush */
@@ -1292,58 +1259,51 @@ UserDrawIconEx(
         if(!Ret)
         {
             ERR("Failed to paint the off-screen surface.\n");
-            SURFACE_ShareUnlockSurface(psurfMask);
-            if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
-            GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
-            return FALSE;
+            goto Cleanup;
         }
         
         /* We now have our destination surface */
         psurfDest = psurfOffScreen;
+#else
+        pdcClipObj = &pdc->co.ClipObj;
+        /* Paint the brush */
+        EBRUSHOBJ_vInit(&eboFill, pbrush, psurfDest, 0x00FFFFFF, 0, NULL);
+        
+        Ret = IntEngBitBlt(&psurfDest->SurfObj,
+            NULL,
+            NULL,
+            pdcClipObj,
+            NULL,
+            &rcDest,
+            NULL,
+            NULL,
+            &eboFill.BrushObject,
+            &pbrush->ptOrigin,
+            ROP4_PATCOPY);
+
+        /* Clean up everything */
+        EBRUSHOBJ_vCleanup(&eboFill);
+        BRUSH_ShareUnlockBrush(pbrush);
+            
+        if(!Ret)
+        {
+            ERR("Failed to paint the off-screen surface.\n");
+            goto Cleanup;
+        }
+#endif
     }
     else
     {
         /* We directly draw to the DC */
         TRACE("Performing on screen rendering.\n");
-        
-        psurfOffScreen = NULL;
-        pdc = DC_LockDc(hDc);
-        if(!pdc)
-        {
-            ERR("Could not lock the destination DC.\n");
-            SURFACE_ShareUnlockSurface(psurfMask);
-            if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
-            return FALSE;
-        }
-        /* Calculate destination rectangle */
-        RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
-        IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
-        RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
-        
-        /* Prepare the underlying surface */
-        DC_vPrepareDCsForBlit(pdc, rcDest, NULL, rcDest);
-        
-        /* Get the clip object */
-        pdcClipObj = pdc->rosdc.CombinedClip;
-        
-        /* We now have our destination surface and rectangle */
-        psurfDest = pdc->dclevel.pSurface;
-        
-        if(psurfDest == NULL)
-        {
-            /* Empty DC */
-            DC_vFinishBlit(pdc, NULL);
-            DC_UnlockDc(pdc);
-            SURFACE_ShareUnlockSurface(psurfMask);
-            if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
-            return FALSE;
-        }
+        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);
@@ -1368,7 +1328,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)
@@ -1401,7 +1361,7 @@ NoAlpha:
 
     if(diFlags & DI_IMAGE)
     {
-               if (psurfColor)
+        if (psurfColor)
         {
             DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ;
             
@@ -1432,7 +1392,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);
         
@@ -1460,36 +1420,23 @@ NoAlpha:
     }
 
 done:
+#if 0
     /* We're done. Was it a double buffered draw ? */
     if(bOffScreen)
     {
         /* Yes. Draw it back to our DC */
         POINTL ptSrc = {0, 0};
-        pdc = DC_LockDc(hDc);
-        if(!pdc)
-        {
-            ERR("Could not lock the destination DC.\n");
-            return FALSE;
-        }
+
         /* Calculate destination rectangle */
         RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
         IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
         RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
         
-        /* Prepare the underlying surface */
-        DC_vPrepareDCsForBlit(pdc, rcDest, NULL, rcDest);
-        
         /* Get the clip object */
         pdcClipObj = pdc->rosdc.CombinedClip;
         
         /* We now have our destination surface and rectangle */
         psurfDest = pdc->dclevel.pSurface;
-        if(!psurfDest)
-        {
-            /* So, you did all of this for an empty DC. */
-            DC_UnlockDc(pdc);
-            goto Cleanup2;
-        }
         
         /* Color translation */
         EXLATEOBJ_vInitialize(&exlo, psurfOffScreen->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0);
@@ -1509,18 +1456,20 @@ done:
                            
         EXLATEOBJ_vCleanup(&exlo);
     }
+#endif
 Cleanup:
     if(pdc)
     {
         DC_vFinishBlit(pdc, NULL);
         DC_UnlockDc(pdc);
     }
-    
-Cleanup2:
+
+#if 0
     /* Delete off screen rendering surface */
     if(psurfOffScreen)
         GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
-    
+#endif
+
     /* Unlock other surfaces */
     SURFACE_ShareUnlockSurface(psurfMask);
     if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
@@ -1554,7 +1503,7 @@ NtUserDrawIconEx(
 
     if (!(pIcon = UserGetCurIconObject(hIcon)))
     {
-        ERR("UserGetCurIconObject() failed!\n");
+        ERR("UserGetCurIconObject(0x%08x) failed!\n", hIcon);
         UserLeave();
         return FALSE;
     }
@@ -1575,4 +1524,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 */