Don't destroy cursors/icons prematurely.
Modified: trunk/reactos/include/napi/win32.h
Modified: trunk/reactos/lib/user32/windows/bitmap.c
Modified: trunk/reactos/subsys/win32k/include/cursoricon.h
Modified: trunk/reactos/subsys/win32k/main/dllmain.c
Modified: trunk/reactos/subsys/win32k/ntuser/cursoricon.c

Modified: trunk/reactos/include/napi/win32.h
--- trunk/reactos/include/napi/win32.h	2005-01-02 23:46:28 UTC (rev 12741)
+++ trunk/reactos/include/napi/win32.h	2005-01-03 00:46:42 UTC (rev 12742)
@@ -28,8 +28,6 @@
   LIST_ENTRY MenuListHead;
   FAST_MUTEX PrivateFontListLock;
   LIST_ENTRY PrivateFontListHead;
-  FAST_MUTEX CursorIconListLock;
-  LIST_ENTRY CursorIconListHead;
   struct _KBDTABLES* KeyboardLayout;
   ULONG Flags;
   LONG GDIObjects;

Modified: trunk/reactos/lib/user32/windows/bitmap.c
--- trunk/reactos/lib/user32/windows/bitmap.c	2005-01-02 23:46:28 UTC (rev 12741)
+++ trunk/reactos/lib/user32/windows/bitmap.c	2005-01-03 00:46:42 UTC (rev 12742)
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: bitmap.c,v 1.34 2004/12/19 05:00:22 royce Exp $
+/* $Id$
  *
  * PROJECT:         ReactOS user32.dll
  * FILE:            lib/user32/windows/input.c
@@ -149,7 +149,7 @@
       hIcon = (HANDLE)CreateIconFromResourceEx((PBYTE)ResIcon,
          SizeofResource(hinst, h2Resource), FALSE, 0x00030000,
          32, 32, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
-      if (hIcon)
+      if (hIcon && 0 != (fuLoad & LR_SHARED))
       {
          NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, (HRSRC)hfRes, 
                                  (HRSRC)NULL);
@@ -157,100 +157,98 @@
 
       return hIcon;
    }
-   else
+
+   if (fuLoad & LR_SHARED)
    {
-      if (fuLoad & LR_SHARED)
-      {
-         DbgPrint("FIXME: need LR_SHARED support loading cursor images from files\n");
-      }
+      DbgPrint("FIXME: need LR_SHARED support loading cursor images from files\n");
+   }
       
-      hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
-         OPEN_EXISTING, 0, NULL);
-      if (hFile == NULL)
-      {
-         return NULL;
-      }
+   hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
+      OPEN_EXISTING, 0, NULL);
+   if (hFile == NULL)
+   {
+      return NULL;
+   }
 
-      hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
-      CloseHandle(hFile);
-      if (hSection == NULL)
-      {
-         return NULL;
-      }
+   hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+   CloseHandle(hFile);
+   if (hSection == NULL)
+   {
+      return NULL;
+   }
 
-      IconDIR = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
-      CloseHandle(hSection);
-      if (IconDIR == NULL || 0 != IconDIR->idReserved
-          || (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
-      {
-         return NULL;
-      }
+   IconDIR = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
+   CloseHandle(hSection);
+   if (IconDIR == NULL || 0 != IconDIR->idReserved
+       || (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
+   {
+      return NULL;
+   }
 
-      /* 
-       * Get a handle to the screen dc, the icon we create is going to be
-       * compatable with it.
+   /* 
+    * Get a handle to the screen dc, the icon we create is going to be
+    * compatable with it.
+    */
+   hScreenDc = CreateCompatibleDC(0);
+   if (hScreenDc == NULL)
+   {
+      UnmapViewOfFile(IconDIR);
+      return NULL;
+   }
+
+   if (fuLoad & LR_MONOCHROME)
+   {
+      ColorBits = 1;
+   }
+   else
+   {
+      ColorBits = GetDeviceCaps(hScreenDc, BITSPIXEL);
+      /*
+       * FIXME:
+       * Remove this after proper support for alpha icons will be finished.
        */
-      hScreenDc = CreateCompatibleDC(0);
-      if (hScreenDc == NULL)
-      {
-         UnmapViewOfFile(IconDIR);
-         return NULL;
-      }
+      if (ColorBits > 8)
+         ColorBits = 8;
+   }
 
-      if (fuLoad & LR_MONOCHROME)
-      {
-         ColorBits = 1;
-      }
-      else
-      {
-         ColorBits = GetDeviceCaps(hScreenDc, BITSPIXEL);
-         /*
-          * FIXME:
-          * Remove this after proper support for alpha icons will be finished.
-          */
-         if (ColorBits > 8)
-            ColorBits = 8;
-      }
-
-      /* Pick the best size. */
-      dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(IconDIR, 32, 32, ColorBits);
-      if (!dirEntry)
-      {
-         UnmapViewOfFile(IconDIR);
-         return(NULL);
-      }
-
-      SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwBytesInRes); 
-      memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
+   /* Pick the best size. */
+   dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(IconDIR, 32, 32, ColorBits);
+   if (!dirEntry)
+   {
+      UnmapViewOfFile(IconDIR);
+      return(NULL);
    }
 
-  //at this point we have a copy of the icon image to play with
+   SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwBytesInRes); 
+   memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
 
-  SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
+   /* at this point we have a copy of the icon image to play with */
 
-  if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
-    {
+   SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
+
+   if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
+   {
       BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
       ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
       HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
-    }
-  else
-    {
+   }
+   else
+   {
       ColorCount = SafeIconImage->icHeader.biClrUsed;
       if (ColorCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
 	{
 	  ColorCount = 1 << SafeIconImage->icHeader.biBitCount;
 	}
       HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
-    }
+   }
   
-  //make data point to the start of the XOR image data
-  Data = (PBYTE)SafeIconImage + HeaderSize;
+   /* make data point to the start of the XOR image data */
+   Data = (PBYTE)SafeIconImage + HeaderSize;
 
-  hIcon = ICON_CreateCursorFromData(hScreenDc, Data, SafeIconImage, 32, 32, dirEntry->Info.cursor.wXHotspot, dirEntry->Info.cursor.wYHotspot);
-  DeleteDC(hScreenDc);
-  RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
-  return hIcon;
+   hIcon = ICON_CreateCursorFromData(hScreenDc, Data, SafeIconImage, 32, 32, dirEntry->Info.cursor.wXHotspot, dirEntry->Info.cursor.wYHotspot);
+   DeleteDC(hScreenDc);
+   RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
+   return hIcon;
 }
 
 
@@ -326,7 +324,7 @@
       hIcon = (HANDLE)CreateIconFromResourceEx((PBYTE) ResIcon,
                         SizeofResource(hinst, h2Resource), TRUE, 0x00030000,
                         width, height, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
-      if(hIcon)
+      if (hIcon && 0 != (fuLoad & LR_SHARED))
       {
         NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, (HRSRC)hfRes, 
                                 (HRSRC)NULL);

Modified: trunk/reactos/subsys/win32k/include/cursoricon.h
--- trunk/reactos/subsys/win32k/include/cursoricon.h	2005-01-02 23:46:28 UTC (rev 12741)
+++ trunk/reactos/subsys/win32k/include/cursoricon.h	2005-01-03 00:46:42 UTC (rev 12742)
@@ -3,11 +3,18 @@
 
 #define MAXCURICONHANDLES 4096
 
+typedef struct tagCURICON_PROCESS
+{
+  LIST_ENTRY ListEntry;
+  PW32PROCESS Process;
+} CURICON_PROCESS, *PCURICON_PROCESS;
+
 typedef struct _CURICON_OBJECT
 {
+  LIST_ENTRY ListEntry;
   HANDLE Self;
-  LIST_ENTRY ListEntry;
-  PW32PROCESS Process;
+  FAST_MUTEX Lock;
+  LIST_ENTRY ProcessList;
   HMODULE hModule;
   HRSRC hRsrc;
   HRSRC hGroupRsrc;

Modified: trunk/reactos/subsys/win32k/main/dllmain.c
--- trunk/reactos/subsys/win32k/main/dllmain.c	2005-01-02 23:46:28 UTC (rev 12741)
+++ trunk/reactos/subsys/win32k/main/dllmain.c	2005-01-03 00:46:42 UTC (rev 12742)
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: dllmain.c,v 1.86 2004/12/29 19:55:01 gvg Exp $
+/* $Id$
  *
  *  Entry Point for win32k.sys
  */
@@ -71,9 +71,6 @@
       InitializeListHead(&Win32Process->PrivateFontListHead);
       ExInitializeFastMutex(&Win32Process->PrivateFontListLock);
       
-      InitializeListHead(&Win32Process->CursorIconListHead);
-      ExInitializeFastMutex(&Win32Process->CursorIconListLock);
-
       Win32Process->KeyboardLayout = W32kGetDefaultKeyLayout();
       
       /* setup process flags */

Modified: trunk/reactos/subsys/win32k/ntuser/cursoricon.c
--- trunk/reactos/subsys/win32k/ntuser/cursoricon.c	2005-01-02 23:46:28 UTC (rev 12741)
+++ trunk/reactos/subsys/win32k/ntuser/cursoricon.c	2005-01-03 00:46:42 UTC (rev 12742)
@@ -16,9 +16,32 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: cursoricon.c,v 1.5 2004/12/30 02:32:18 navaraf Exp $ */
+
+/*
+ * We handle two types of cursors/icons:
+ * - Private
+ *   Loaded without LR_SHARED flag
+ *   Private to a process
+ *   Can be deleted by calling NtDestroyCursorIcon()
+ *   CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
+ * - Shared
+ *   Loaded with LR_SHARED flag
+ *   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 <w32k.h>
 
+static PAGED_LOOKASIDE_LIST ProcessLookasideList;
+static LIST_ENTRY CurIconList;
+static FAST_MUTEX CurIconListLock;
+
 PCURICON_OBJECT FASTCALL
 IntGetCurIconObject(PWINSTATION_OBJECT WinStaObject, HANDLE Handle)
 {
@@ -248,48 +271,97 @@
 BOOL FASTCALL
 IntSetupCurIconHandles(PWINSTATION_OBJECT WinStaObject)
 {
+  ExInitializePagedLookasideList(&ProcessLookasideList,
+				 NULL,
+				 NULL,
+				 0,
+				 sizeof(CURICON_PROCESS),
+				 0,
+				 128);
+  InitializeListHead(&CurIconList);
+  ExInitializeFastMutex(&CurIconListLock);
+
   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 Object)
+{
+  PW32PROCESS Win32Process;
+  PLIST_ENTRY Search;
+  PCURICON_PROCESS Current;
+
+  Win32Process = PsGetWin32Process();
+  
+  ExAcquireFastMutex(&Object->Lock);
+  Search = Object->ProcessList.Flink;
+  while (Search != &Object->ProcessList)
+    {
+      Current = CONTAINING_RECORD(Search, CURICON_PROCESS, ListEntry);
+      if (Current->Process == Win32Process)
+        {
+          /* Already registered for this process */
+          ExReleaseFastMutex(&Object->Lock);
+          return TRUE;
+        }
+      Search = Search->Flink;
+    }
+
+  /* Not registered yet */
+  Current = ExAllocateFromPagedLookasideList(&ProcessLookasideList);
+  if (NULL == Current)
+    {
+      return FALSE;
+    }
+  InsertHeadList(&Object->ProcessList, &Current->ListEntry);
+  Current->Process = Win32Process;
+
+  ExReleaseFastMutex(&Object->Lock);
+  return TRUE;
+}
+
 PCURICON_OBJECT FASTCALL
 IntFindExistingCurIconObject(PWINSTATION_OBJECT WinStaObject, HMODULE hModule, 
                              HRSRC hRsrc, LONG cx, LONG cy)
 {
-  PUSER_HANDLE_TABLE HandleTable;
   PLIST_ENTRY CurrentEntry;
-  PUSER_HANDLE_BLOCK Current;
   PCURICON_OBJECT Object;
-  ULONG i;
-  
-  HandleTable = (PUSER_HANDLE_TABLE)WinStaObject->HandleTable;
-  ObmpLockHandleTable(HandleTable);
-  
-  CurrentEntry = HandleTable->ListHead.Flink;
-  while(CurrentEntry != &HandleTable->ListHead)
+
+  ExAcquireFastMutex(&CurIconListLock);  
+
+  CurrentEntry = CurIconList.Flink;
+  while (CurrentEntry != &CurIconList)
   {
-    Current = CONTAINING_RECORD(CurrentEntry, USER_HANDLE_BLOCK, ListEntry);
-    for(i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
+    Object = CONTAINING_RECORD(CurrentEntry, CURICON_OBJECT, ListEntry);
+    CurrentEntry = CurrentEntry->Flink;
+    if((Object->hModule == hModule) && (Object->hRsrc == hRsrc))
     {
-      Object = (PCURICON_OBJECT)Current->Handles[i].ObjectBody;
-      if(Object && (ObmReferenceObjectByPointer(Object, otCursorIcon) == STATUS_SUCCESS))
+      if(cx && ((cx != Object->Size.cx) || (cy != Object->Size.cy)))
       {
-        if((Object->hModule == hModule) && (Object->hRsrc == hRsrc))
-        {
-          if(cx && ((cx != Object->Size.cx) || (cy != Object->Size.cy)))
-          {
-	    ObmDereferenceObject(Object);
-	    continue;
-          }
-          ObmpUnlockHandleTable(HandleTable);
-          return Object;
-        }
         ObmDereferenceObject(Object);
+	continue;
       }
+      if (! ReferenceCurIconByProcess(Object))
+      {
+        ExReleaseFastMutex(&CurIconListLock);
+        return NULL;
+      }
+      ExReleaseFastMutex(&CurIconListLock);
+      return Object;
     }
-    CurrentEntry = CurrentEntry->Flink;
   }
   
-  ObmpUnlockHandleTable(HandleTable);
+  ExReleaseFastMutex(&CurIconListLock);
+
   return NULL;
 }
 
@@ -298,7 +370,6 @@
 {
   PCURICON_OBJECT Object;
   HANDLE Handle;
-  PW32PROCESS Win32Process;
   
   Object = ObmCreateObject(WinStaObject->HandleTable, &Handle, otCursorIcon, sizeof(CURICON_OBJECT));
   
@@ -308,39 +379,90 @@
     return FALSE;
   }
   
-  Win32Process = PsGetWin32Process();
-  
-  IntLockProcessCursorIcons(Win32Process);
-  InsertTailList(&Win32Process->CursorIconListHead, &Object->ListEntry);
-  IntUnLockProcessCursorIcons(Win32Process);
-  
   Object->Self = Handle;
-  Object->Process = PsGetWin32Process();
-  
+  ExInitializeFastMutex(&Object->Lock);
+  InitializeListHead(&Object->ProcessList);
+
+  if (! ReferenceCurIconByProcess(Object))
+  {
+    DPRINT1("Failed to add process\n");
+    ObmCloseHandle(WinStaObject->HandleTable, Handle);
+    ObmDereferenceObject(Object);
+    return NULL;
+  }
+
+  ExAcquireFastMutex(&CurIconListLock);
+  InsertHeadList(&CurIconList, &Object->ListEntry);
+  ExReleaseFastMutex(&CurIconListLock);
+
+  ObmDereferenceObject(Object);
+
   return Object;
 }
 
-BOOL FASTCALL
-IntDestroyCurIconObject(PWINSTATION_OBJECT WinStaObject, HANDLE Handle, BOOL RemoveFromProcess)
+BOOLEAN FASTCALL
+IntDestroyCurIconObject(PWINSTATION_OBJECT WinStaObject, PCURICON_OBJECT Object, BOOL ProcessCleanup)
 {
   PSYSTEM_CURSORINFO CurInfo;
-  PCURICON_OBJECT Object;
   HBITMAP bmpMask, bmpColor;
-  NTSTATUS Status;
-  BOOL Ret;
-  
-  Status = ObmReferenceObjectByHandle(WinStaObject->HandleTable, Handle, otCursorIcon, (PVOID*)&Object);
-  if(!NT_SUCCESS(Status))
-  {
-    return FALSE;
-  }
-  
-  if (Object->Process != PsGetWin32Process())
-  {
-    ObmDereferenceObject(Object);
-    return FALSE;
-  }
+  BOOLEAN Ret;
+  PLIST_ENTRY Search;
+  PCURICON_PROCESS Current;
+  PW32PROCESS W32Process = PsGetWin32Process();
 
+  ExAcquireFastMutex(&Object->Lock);
+
+  /* Private objects can only be destroyed by their own process */
+  if (NULL == Object->hModule)
+    {
+    ASSERT(Object->ProcessList.Flink->Flink == &Object->ProcessList);
+    Current = CONTAINING_RECORD(Object->ProcessList.Flink, CURICON_PROCESS, ListEntry);
+    if (Current->Process != W32Process)
+      {
+        ExReleaseFastMutex(&Object->Lock);
+        DPRINT1("Trying to destroy private icon/cursor of another process\n");
+        return FALSE;
+      }
+    }
+  else if (! ProcessCleanup)
+    {
+      ExReleaseFastMutex(&Object->Lock);
+      DPRINT("Trying to destroy shared icon/cursor\n");
+      return FALSE;
+    }
+
+  /* Now find this process in the list of processes referencing this object and
+     remove it from that list */
+  Search = Object->ProcessList.Flink;
+  while (Search != &Object->ProcessList)
+    {
+    Current = CONTAINING_RECORD(Object->ProcessList.Flink, CURICON_PROCESS, ListEntry);
+    if (Current->Process == W32Process)
+      {
+      break;
+      }
+    Search = Search->Flink;
+    }
+  ASSERT(Search != &Object->ProcessList);
+  RemoveEntryList(Search);
+  ExFreeToPagedLookasideList(&ProcessLookasideList, Current);
+
+  /* If there are still processes referencing this object we can't destroy it yet */
+  if (! IsListEmpty(&Object->ProcessList))
+    {
+    ExReleaseFastMutex(&Object->Lock);
+    return TRUE;
+    }
+    
+  ExReleaseFastMutex(&Object->Lock);
+
+  if (! ProcessCleanup)
+    {
+    ExAcquireFastMutex(&CurIconListLock);
+    RemoveEntryList(&Object->ListEntry);
+    ExReleaseFastMutex(&CurIconListLock);
+    }
+
   CurInfo = IntGetSysCursorInfo(WinStaObject);
 
   if (CurInfo->CurrentCursorObject == Object)
@@ -351,15 +473,8 @@
   
   bmpMask = Object->IconInfo.hbmMask;
   bmpColor = Object->IconInfo.hbmColor;
-
-  if (Object->Process && RemoveFromProcess)
-  {
-    IntLockProcessCursorIcons(Object->Process);
-    RemoveEntryList(&Object->ListEntry);
-    IntUnLockProcessCursorIcons(Object->Process);
-  }
   
-  Ret = NT_SUCCESS(ObmCloseHandle(WinStaObject->HandleTable, Handle));
+  Ret = NT_SUCCESS(ObmCloseHandle(WinStaObject->HandleTable, Object->Self));
   
   /* delete bitmaps */
   if(bmpMask)
@@ -372,8 +487,6 @@
     GDIOBJ_SetOwnership(bmpColor, PsGetCurrentProcess());
     NtGdiDeleteObject(bmpColor);
   }
-
-  ObmDereferenceObject(Object);
   
   return Ret;
 }
@@ -382,23 +495,50 @@
 IntCleanupCurIcons(struct _EPROCESS *Process, PW32PROCESS Win32Process)
 {
   PWINSTATION_OBJECT WinStaObject;
-  PCURICON_OBJECT Current;
-  PLIST_ENTRY CurrentEntry, NextEntry;
-  
+  PLIST_ENTRY CurrentEntry;
+  PCURICON_OBJECT Object;
+  PLIST_ENTRY ProcessEntry;
+  PCURICON_PROCESS ProcessData;
+
   WinStaObject = IntGetWinStaObj();
-  if(WinStaObject != NULL)
+  if(WinStaObject == NULL)
   {
-    CurrentEntry = Win32Process->CursorIconListHead.Flink;
-    while(CurrentEntry != &Win32Process->CursorIconListHead)
-    {
-      NextEntry = CurrentEntry->Flink;
-      Current = CONTAINING_RECORD(CurrentEntry, CURICON_OBJECT, ListEntry);
-      RemoveEntryList(&Current->ListEntry);
-      IntDestroyCurIconObject(WinStaObject, Current->Self, FALSE);
-      CurrentEntry = NextEntry;
+    return;
+  }
+
+  ExAcquireFastMutex(&CurIconListLock);  
+
+  CurrentEntry = CurIconList.Flink;
+  while (CurrentEntry != &CurIconList)
+  {
+    Object = CONTAINING_RECORD(CurrentEntry, CURICON_OBJECT, ListEntry);
+    CurrentEntry = CurrentEntry->Flink;
+    if(NT_SUCCESS(ObmReferenceObjectByPointer(Object, otCursorIcon)))
+      {
+      ExAcquireFastMutex(&Object->Lock);
+      ProcessEntry = Object->ProcessList.Flink;
+      while (ProcessEntry != &Object->ProcessList)
+      {
+        ProcessData = CONTAINING_RECORD(ProcessEntry, CURICON_PROCESS, ListEntry);
+        if (Win32Process == ProcessData->Process)
+        {
+          ExReleaseFastMutex(&Object->Lock);
+          RemoveEntryList(&Object->ListEntry);
+          IntDestroyCurIconObject(WinStaObject, Object, TRUE);
+          break;
+        }
+        ProcessEntry = ProcessEntry->Flink;
+      }
+      if (ProcessEntry == &Object->ProcessList)
+      {
+        ExReleaseFastMutex(&Object->Lock);
+      }
+      ObmDereferenceObject(Object);
     }
-    ObDereferenceObject(WinStaObject);
   }
+  
+  ExReleaseFastMutex(&CurIconListLock);
+  ObDereferenceObject(WinStaObject);
 }
 
 /*
@@ -729,6 +869,8 @@
   DWORD Unknown)
 {
   PWINSTATION_OBJECT WinStaObject;
+  PCURICON_OBJECT Object;
+  NTSTATUS Status;
   
   WinStaObject = IntGetWinStaObj();
   if(WinStaObject == NULL)
@@ -736,14 +878,24 @@
     return FALSE;
   }
   
-  if(IntDestroyCurIconObject(WinStaObject, Handle, TRUE))
+  Status = ObmReferenceObjectByHandle(WinStaObject->HandleTable, Handle, otCursorIcon, (PVOID*)&Object);
+  if(!NT_SUCCESS(Status))
   {
     ObDereferenceObject(WinStaObject);
+    SetLastNtError(Status);
+    return FALSE;
+  }
+
+  if(IntDestroyCurIconObject(WinStaObject, Object, FALSE))
+  {
+    ObmDereferenceObject(Object);
+    ObDereferenceObject(WinStaObject);
     return TRUE;
   }
 
+  ObmDereferenceObject(Object);
+  ObDereferenceObject(WinStaObject);
   SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
-  ObDereferenceObject(WinStaObject);
   return FALSE;
 }