[YAROTOWS] Reintegrate the branch. For a brighter future.
[reactos.git] / reactos / subsystems / win32 / win32k / objects / gdiobj.c
index 3b2bee3..f9bacf0 100644 (file)
@@ -1,61 +1,39 @@
 /*
- *  ReactOS W32 Subsystem
- *  Copyright (C) 1998 - 2004 ReactOS Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/*
- * GDIOBJ.C - GDI object manipulation routines
- *
- * $Id$
+ * PROJECT:         ReactOS win32 kernel mode subsystem
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            subsystems/win32/win32k/objects/gdiobj.c
+ * PURPOSE:         General GDI object manipulation routines
+ * PROGRAMMERS:     ...
  */
 
-#include <w32k.h>
+/** INCLUDES ******************************************************************/
 
+#define GDI_DEBUG
+
+#include <win32k.h>
 #define NDEBUG
 #include <debug.h>
 
-/* FIXME include right header for KeRosDumpStackFrames */
-VOID
-NTAPI
-KeRosDumpStackFrames(
-    PULONG Frame,
-    ULONG FrameCount
-);
-
 #define GDI_ENTRY_TO_INDEX(ht, e)                                              \
   (((ULONG_PTR)(e) - (ULONG_PTR)&((ht)->Entries[0])) / sizeof(GDI_TABLE_ENTRY))
 #define GDI_HANDLE_GET_ENTRY(HandleTable, h)                                   \
   (&(HandleTable)->Entries[GDI_HANDLE_GET_INDEX((h))])
 
-#define GDIBdyToHdr(body)                                                      \
-  ((PGDIOBJHDR)(body) - 1)
-#define GDIHdrToBdy(hdr)                                                       \
-  (PGDIOBJ)((PGDIOBJHDR)(hdr) + 1)
-
 /* apparently the first 10 entries are never used in windows as they are empty */
 #define RESERVE_ENTRIES_COUNT 10
 
-/*
- * Dummy GDI Cleanup Callback
- */
-static BOOL INTERNAL_CALL
-GDI_CleanupDummy(PVOID ObjectBody)
-{
-  return TRUE;
-}
+#define BASE_OBJTYPE_COUNT 32
+
+#define DelayExecution() \
+  DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
+  KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
+
+#include "gdidbg.c"
+
+static
+BOOL INTERNAL_CALL GDI_CleanupDummy(PVOID ObjectBody);
+
+/** GLOBALS *******************************************************************/
 
 typedef struct
 {
@@ -66,54 +44,108 @@ typedef struct
 } OBJ_TYPE_INFO, *POBJ_TYPE_INFO;
 
 static const
-OBJ_TYPE_INFO ObjTypeInfo[] =
+OBJ_TYPE_INFO ObjTypeInfo[BASE_OBJTYPE_COUNT] =
 {
-  {0, 0,                     0,                       NULL},             /* 00 reserved entry */
-  {1, sizeof(DC),            GDI_OBJECT_TAG_DC,       DC_Cleanup},       /* 01 DC */
-  {1, sizeof(DD_DIRECTDRAW), GDI_OBJECT_TAG_DDRAW,    DD_Cleanup},       /* 02 DD_DDRAW, should be moved away from gdi objects */
-  {1, sizeof(DD_SURFACE),    GDI_OBJECT_TAG_DDSURF,   DDSURF_Cleanup},   /* 03 DD_SURFACE, should be moved away from gdi objects */
-  {1, sizeof(ROSRGNDATA),    GDI_OBJECT_TAG_REGION,   RGNDATA_Cleanup},  /* 04 REGION */
-  {1, sizeof(BITMAPOBJ),     GDI_OBJECT_TAG_BITMAP,   BITMAP_Cleanup},   /* 05 BITMAP */
-  {0, sizeof(DC),            GDI_OBJECT_TAG_CLIOBJ,   GDI_CleanupDummy}, /* 06 CLIOBJ: METADC,... FIXME: don't use DC struct */
-  {0, 0,                     GDI_OBJECT_TAG_PATH,     NULL},             /* 07 PATH, unused */
-  {1, sizeof(PALGDI),        GDI_OBJECT_TAG_PALETTE,  PALETTE_Cleanup},  /* 08 PALETTE */
-  {0, 0,                     GDI_OBJECT_TAG_COLSPC,   NULL},             /* 09 COLORSPACE, unused */
-  {1, sizeof(TEXTOBJ),       GDI_OBJECT_TAG_FONT,     GDI_CleanupDummy}, /* 0a FONT */
-  {0, 0,                     0,                       NULL},             /* 0b RFONT, unused */
-  {0, 0,                     0,                       NULL},             /* 0c PFE, unused */
-  {0, 0,                     0,                       NULL},             /* 0d PFT, unused */
-  {0, 0,                     0,                       NULL},             /* 0e ICMCXF, unused */
-  {0, 0,                     0,                       NULL},             /* 0f ICMDLL, unused */
-  {1, sizeof(GDIBRUSHOBJ),   GDI_OBJECT_TAG_BRUSH,    BRUSH_Cleanup},    /* 10 BRUSH, PEN, EXTPEN */
-  {0, 0,                     0,                       NULL},             /* 11 D3D_HANDLE, unused */
-  {0, 0,                     0,                       NULL},             /* 12 DD_VPORT, unused */
-  {0, 0,                     0,                       NULL},             /* 13 SPACE, unused */
-  {0, 0,                     0,                       NULL},             /* 14 DD_MOTION, unused */
-  {0, 0,                     0,                       NULL},             /* 15 META, unused */
-  {0, 0,                     0,                       NULL},             /* 16 ENUMFONT, unused */
-  {0, 0,                     0,                       NULL},             /* 17 BMFD, unused */
-  {0, 0,                     0,                       NULL},             /* 18 VTFD, unused */
-  {0, 0,                     0,                       NULL},             /* 19 TTFD, unused */
-  {0, 0,                     0,                       NULL},             /* 1a RC, unused */
-  {0, 0,                     0,                       NULL},             /* 1b TEMP, unused */
-  {0, 0,                     0,                       NULL},             /* 1c DRVOBJ, unused */
-  {0, 0,                     0,                       NULL},             /* 1d DCIOBJ, unused */
-  {0, 0,                     0,                       NULL},             /* 1e SPOOL, unused */
+  {0, 0,                     0,                NULL},             /* 00 reserved entry */
+  {1, sizeof(DC),            TAG_DC,           DC_Cleanup},       /* 01 DC */
+  {1, 0,                     0,                NULL},             /* 02 UNUSED1 */
+  {1, 0,                     0,                NULL},             /* 03 UNUSED2 */
+  {1, sizeof(ROSRGNDATA),    TAG_REGION,       REGION_Cleanup},   /* 04 RGN */
+  {1, sizeof(SURFACE),       TAG_SURFACE,      SURFACE_Cleanup},  /* 05 SURFACE */
+  {1, sizeof(CLIENTOBJ),     TAG_CLIENTOBJ,    GDI_CleanupDummy}, /* 06 CLIENTOBJ: METADC,... */
+  {1, sizeof(PATH),          TAG_PATH,         GDI_CleanupDummy}, /* 07 PATH */
+  {1, sizeof(PALETTE),       TAG_PALETTE,      PALETTE_Cleanup},  /* 08 PAL */
+  {1, sizeof(COLORSPACE),    TAG_ICMLCS,       GDI_CleanupDummy}, /* 09 ICMLCS, */
+  {1, sizeof(TEXTOBJ),       TAG_LFONT,        GDI_CleanupDummy}, /* 0a LFONT */
+  {0, 0,                     TAG_RFONT,        NULL},             /* 0b RFONT, unused */
+  {0, 0,                     TAG_PFE,          NULL},             /* 0c PFE, unused */
+  {0, 0,                     TAG_PFT,          NULL},             /* 0d PFT, unused */
+  {0, sizeof(GDICLRXFORM),   TAG_ICMCXF,       GDI_CleanupDummy}, /* 0e ICMCXF, */
+  {0, 0,                     TAG_SPRITE,       NULL},             /* 0f SPRITE, unused */
+  {1, sizeof(BRUSH),         TAG_BRUSH,        BRUSH_Cleanup},    /* 10 BRUSH, PEN, EXTPEN */
+  {0, 0,                     TAG_UMPD,         NULL},             /* 11 UMPD, unused */
+  {0, 0,                     0,                NULL},             /* 12 UNUSED4 */
+  {0, 0,                     TAG_SPACE,        NULL},             /* 13 SPACE, unused */
+  {0, 0,                     0,                NULL},             /* 14 UNUSED5 */
+  {0, 0,                     TAG_META,         NULL},             /* 15 META, unused */
+  {0, 0,                     TAG_EFSTATE,      NULL},             /* 16 EFSTATE, unused */
+  {0, 0,                     TAG_BMFD,         NULL},             /* 17 BMFD, unused */
+  {0, 0,                     TAG_VTFD,         NULL},             /* 18 VTFD, unused */
+  {0, 0,                     TAG_TTFD,         NULL},             /* 19 TTFD, unused */
+  {0, 0,                     TAG_RC,           NULL},             /* 1a RC, unused */
+  {0, 0,                     TAG_TEMP,         NULL},             /* 1b TEMP, unused */
+  {0, sizeof(EDRIVEROBJ),    TAG_DRVOBJ,       DRIVEROBJ_Cleanup},/* 1c DRVOBJ */
+  {0, 0,                     TAG_DCIOBJ,       NULL},             /* 1d DCIOBJ, unused */
+  {0, 0,                     TAG_SPOOL,        NULL},             /* 1e SPOOL, unused */
+  {0, 0,                     0,                NULL},             /* 1f reserved entry */
 };
 
-#define BASE_OBJTYPE_COUNT (sizeof(ObjTypeInfo) / sizeof(ObjTypeInfo[0]))
-
 static LARGE_INTEGER ShortDelay;
 
-#define DelayExecution() \
-  DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
-  KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
+/** INTERNAL FUNCTIONS ********************************************************/
 
-#ifdef GDI_DEBUG
-BOOLEAN STDCALL KiRosPrintAddress(PVOID Address);
-VOID STDCALL KeRosDumpStackFrames(PULONG Frame, ULONG FrameCount);
-ULONG STDCALL KeRosGetStackFrames(PULONG Frames, ULONG FrameCount);
-#endif
+// Audit Functions
+int tDC = 0;
+int tBRUSH = 0;
+int tBITMAP = 0;
+int tFONT = 0;
+int tRGN = 0;
+
+VOID
+AllocTypeDataDump(INT TypeInfo)
+{
+    switch( TypeInfo & GDI_HANDLE_TYPE_MASK )
+    {
+       case GDILoObjType_LO_BRUSH_TYPE:
+          tBRUSH++;
+          break;
+       case GDILoObjType_LO_DC_TYPE:
+          tDC++;
+          break;
+       case GDILoObjType_LO_BITMAP_TYPE:
+          tBITMAP++;
+          break;
+       case GDILoObjType_LO_FONT_TYPE:
+          tFONT++;
+          break;
+       case GDILoObjType_LO_REGION_TYPE:
+          tRGN++;
+          break;
+    }
+}
+
+VOID
+DeAllocTypeDataDump(INT TypeInfo)
+{
+    switch( TypeInfo & GDI_HANDLE_TYPE_MASK )
+    {
+       case GDILoObjType_LO_BRUSH_TYPE:
+          tBRUSH--;
+          break;
+       case GDILoObjType_LO_DC_TYPE:
+          tDC--;
+          break;
+       case GDILoObjType_LO_BITMAP_TYPE:
+          tBITMAP--;
+          break;
+       case GDILoObjType_LO_FONT_TYPE:
+          tFONT--;
+          break;
+       case GDILoObjType_LO_REGION_TYPE:
+          tRGN--;
+          break;
+    }
+}
+
+/*
+ * Dummy GDI Cleanup Callback
+ */
+static
+BOOL INTERNAL_CALL
+GDI_CleanupDummy(PVOID ObjectBody)
+{
+    return TRUE;
+}
 
 /*!
  * Allocate GDI object table.
@@ -122,195 +154,80 @@ ULONG STDCALL KeRosGetStackFrames(PULONG Frames, ULONG FrameCount);
 PGDI_HANDLE_TABLE INTERNAL_CALL
 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject)
 {
-  PGDI_HANDLE_TABLE HandleTable = NULL;
-  LARGE_INTEGER htSize;
-  UINT ObjType;
-  UINT i;
-  ULONG ViewSize = 0;
-  PGDI_TABLE_ENTRY Entry;
-  NTSTATUS Status;
-
-  ASSERT(SectionObject != NULL);
-
-  htSize.QuadPart = sizeof(GDI_HANDLE_TABLE);
-
-  Status = MmCreateSection((PVOID*)SectionObject,
-                           SECTION_ALL_ACCESS,
-                           NULL,
-                           &htSize,
-                           PAGE_READWRITE,
-                           SEC_COMMIT,
-                           NULL,
-                           NULL);
-  if (!NT_SUCCESS(Status))
-      return NULL;
-
-  /* FIXME - use MmMapViewInSessionSpace once available! */
-  Status = MmMapViewInSystemSpace(*SectionObject,
-                                  (PVOID*)&HandleTable,
-                                  &ViewSize);
-  if (!NT_SUCCESS(Status))
-  {
-      ObDereferenceObject(*SectionObject);
-      *SectionObject = NULL;
-      return NULL;
-  }
+    PGDI_HANDLE_TABLE HandleTable = NULL;
+    LARGE_INTEGER htSize;
+    UINT ObjType;
+    ULONG ViewSize = 0;
+    NTSTATUS Status;
 
-  RtlZeroMemory(HandleTable, sizeof(GDI_HANDLE_TABLE));
+    ASSERT(SectionObject != NULL);
 
-  /*
-   * initialize the free entry cache
-   */
-  InitializeSListHead(&HandleTable->FreeEntriesHead);
-  Entry = &HandleTable->Entries[RESERVE_ENTRIES_COUNT];
-  for(i = GDI_HANDLE_COUNT - 1; i >= RESERVE_ENTRIES_COUNT; i--)
-  {
-    InterlockedPushEntrySList(&HandleTable->FreeEntriesHead, &HandleTable->FreeEntries[i]);
-  }
+    htSize.QuadPart = sizeof(GDI_HANDLE_TABLE);
 
-  HandleTable->LookasideLists = ExAllocatePoolWithTag(NonPagedPool,
-                                                      BASE_OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST),
-                                                      TAG_GDIHNDTBLE);
-  if(HandleTable->LookasideLists == NULL)
-  {
-    MmUnmapViewInSystemSpace(HandleTable);
-    ObDereferenceObject(*SectionObject);
-    *SectionObject = NULL;
-    return NULL;
-  }
+    Status = MmCreateSection((PVOID*)SectionObject,
+                             SECTION_ALL_ACCESS,
+                             NULL,
+                             &htSize,
+                             PAGE_READWRITE,
+                             SEC_COMMIT,
+                             NULL,
+                             NULL);
+    if (!NT_SUCCESS(Status))
+        return NULL;
 
-  for(ObjType = 0; ObjType < BASE_OBJTYPE_COUNT; ObjType++)
-  {
-    if (ObjTypeInfo[ObjType].bUseLookaside)
+    /* FIXME - use MmMapViewInSessionSpace once available! */
+    Status = MmMapViewInSystemSpace(*SectionObject,
+                                    (PVOID*)&HandleTable,
+                                    &ViewSize);
+    if (!NT_SUCCESS(Status))
     {
-      ExInitializePagedLookasideList(HandleTable->LookasideLists + ObjType, NULL, NULL, 0,
-                                     ObjTypeInfo[ObjType].ulBodySize + sizeof(GDIOBJHDR), ObjTypeInfo[ObjType].Tag, 0);
+        ObDereferenceObject(*SectionObject);
+        *SectionObject = NULL;
+        return NULL;
     }
-  }
 
-  ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */
-
-  return HandleTable;
-}
-
-static __inline PPAGED_LOOKASIDE_LIST
-FindLookasideList(PGDI_HANDLE_TABLE HandleTable,
-                  ULONG TypeIndex)
-{
-  return HandleTable->LookasideLists + TypeIndex;
-}
+    RtlZeroMemory(HandleTable, sizeof(GDI_HANDLE_TABLE));
 
-static __inline BOOL
-RunCleanupCallback(PGDIOBJ pObj, ULONG TypeIndex)
-{
-  return ((GDICLEANUPPROC)ObjTypeInfo[TypeIndex].CleanupProc)(pObj);
-}
+    HandleTable->LookasideLists = ExAllocatePoolWithTag(NonPagedPool,
+                                  BASE_OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST),
+                                  TAG_GDIHNDTBLE);
+    if (HandleTable->LookasideLists == NULL)
+    {
+        MmUnmapViewInSystemSpace(HandleTable);
+        ObDereferenceObject(*SectionObject);
+        *SectionObject = NULL;
+        return NULL;
+    }
 
-static __inline ULONG
-GetObjectSize(ULONG TypeIndex)
-{
-  return ObjTypeInfo[TypeIndex].ulBodySize;
-}
+    for (ObjType = 0; ObjType < BASE_OBJTYPE_COUNT; ObjType++)
+    {
+        if (ObjTypeInfo[ObjType].bUseLookaside)
+        {
+            ExInitializePagedLookasideList(HandleTable->LookasideLists + ObjType,
+                                           NULL,
+                                           NULL,
+                                           0,
+                                           ObjTypeInfo[ObjType].ulBodySize,
+                                           ObjTypeInfo[ObjType].Tag,
+                                           0);
+        }
+    }
 
-#ifdef GDI_DEBUG
+    ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */
 
-static int leak_reported = 0;
-#define GDI_STACK_LEVELS 12
-static ULONG GDIHandleAllocator[GDI_HANDLE_COUNT][GDI_STACK_LEVELS];
-struct DbgOpenGDIHandle
-{
-       ULONG idx;
-       int count;
-};
-#define H 1024
-static struct DbgOpenGDIHandle h[H];
+    HandleTable->FirstFree = 0;
+    HandleTable->FirstUnused = RESERVE_ENTRIES_COUNT;
 
-void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable)
-{
-       int i, n = 0, j, k, J;
-
-       if ( leak_reported )
-       {
-               DPRINT1("gdi handle abusers already reported!\n");
-               return;
-       }
-
-       leak_reported = 1;
-       DPRINT1("reporting gdi handle abusers:\n");
-
-       /* step through GDI handle table and find out who our culprit is... */
-       for ( i = RESERVE_ENTRIES_COUNT; i < GDI_HANDLE_COUNT; i++ )
-       {
-               for ( j = 0; j < n; j++ )
-               {
-next:
-                       J = h[j].idx;
-                       for ( k = 0; k < GDI_STACK_LEVELS; k++ )
-                       {
-                               if ( GDIHandleAllocator[i][k]
-                                 != GDIHandleAllocator[J][k] )
-                               {
-                                       if ( ++j == n )
-                                               goto done;
-                                       else
-                                               goto next;
-                               }
-                       }
-                       goto done;
-               }
-done:
-               if ( j < H )
-               {
-                       if ( j == n )
-                       {
-                               h[j].idx = i;
-                               h[j].count = 1;
-                               n = n + 1;
-                       }
-                       else
-                               h[j].count++;
-               }
-       }
-       /* bubble sort time! weeeeee!! */
-       for ( i = 0; i < n-1; i++ )
-       {
-               if ( h[i].count < h[i+1].count )
-               {
-                       struct DbgOpenGDIHandle t;
-                       t = h[i+1];
-                       h[i+1] = h[i];
-                       j = i;
-                       while ( j > 0 && h[j-1].count < t.count )
-                               j--;
-                       h[j] = t;
-               }
-       }
-       /* print the worst offenders... */
-       DbgPrint ( "Worst GDI Handle leak offenders (out of %i unique locations):\n", n );
-       for ( i = 0; i < n && h[i].count > 1; i++ )
-       {
-               int j;
-               DbgPrint ( " %i allocs: ", h[i].count );
-               for ( j = 0; j < GDI_STACK_LEVELS; j++ )
-               {
-                       ULONG Addr = GDIHandleAllocator[h[i].idx][j];
-                       if ( !KiRosPrintAddress ( (PVOID)Addr ) )
-                               DbgPrint ( "<%X>", Addr );
-               }
-               DbgPrint ( "\n" );
-       }
-       if ( i < n && h[i].count == 1 )
-               DbgPrint ( "(list terminated - the remaining entries have 1 allocation only)\n" );
+    return HandleTable;
 }
-#endif /* GDI_DEBUG */
-
 
 static void FASTCALL
 LockErrorDebugOutput(HGDIOBJ hObj, PGDI_TABLE_ENTRY Entry, LPSTR Function)
 {
-    if (Entry->KernelData == NULL)
+    if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == 0)
     {
         DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function, hObj);
+        GDIDBG_TRACEDELETER(hObj);
     }
     else if (GDI_HANDLE_GET_REUSECNT(hObj) != GDI_ENTRY_GET_REUSECNT(Entry->Type))
     {
@@ -327,168 +244,287 @@ LockErrorDebugOutput(HGDIOBJ hObj, PGDI_TABLE_ENTRY Entry, LPSTR Function)
         DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
                 Function, hObj, Entry->Type);
     }
-    KeRosDumpStackFrames(NULL, 20);
+    GDIDBG_TRACECALLER();
+}
+
+ULONG
+FASTCALL
+InterlockedPopFreeEntry(VOID)
+{
+    ULONG idxFirst, idxNext, idxPrev;
+    PGDI_TABLE_ENTRY pEntry;
+    DWORD PrevProcId;
+
+    DPRINT("Enter InterLockedPopFreeEntry\n");
+
+    while (TRUE)
+    {
+        idxFirst = GdiHandleTable->FirstFree;
+
+        if (!idxFirst)
+        {
+            /* Increment FirstUnused and get the new index */
+            idxFirst = InterlockedIncrement((LONG*)&GdiHandleTable->FirstUnused) - 1;
+
+            /* Check if we have entries left */
+            if (idxFirst >= GDI_HANDLE_COUNT)
+            {
+                DPRINT1("No more gdi handles left!\n");
+                return 0;
+            }
+
+            /* Return the old index */
+            return idxFirst;
+        }
+
+        /* Get a pointer to the first free entry */
+        pEntry = GdiHandleTable->Entries + idxFirst;
+
+        /* Try to lock the entry */
+        PrevProcId = InterlockedCompareExchange((LONG*)&pEntry->ProcessId, 1, 0);
+        if (PrevProcId != 0)
+        {
+            /* The entry was locked or not free, wait and start over */
+            DelayExecution();
+            continue;
+        }
+
+        /* Sanity check: is entry really free? */
+        ASSERT(((ULONG_PTR)pEntry->KernelData & ~GDI_HANDLE_INDEX_MASK) == 0);
+
+        /* Try to exchange the FirstFree value */
+        idxNext = (ULONG_PTR)pEntry->KernelData;
+        idxPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree,
+                                             idxNext,
+                                             idxFirst);
+
+        /* Unlock the free entry */
+        (void)InterlockedExchange((LONG*)&pEntry->ProcessId, 0);
+
+        /* If we succeeded, break out of the loop */
+        if (idxPrev == idxFirst)
+        {
+            break;
+        }
+    }
+
+    return idxFirst;
+}
+
+/* Pushes an entry of the handle table to the free list,
+   The entry must be unlocked and the base type field must be 0 */
+VOID
+FASTCALL
+InterlockedPushFreeEntry(ULONG idxToFree)
+{
+    ULONG idxFirstFree, idxPrev;
+    PGDI_TABLE_ENTRY pFreeEntry;
+
+    DPRINT("Enter InterlockedPushFreeEntry\n");
+
+    pFreeEntry = GdiHandleTable->Entries + idxToFree;
+    ASSERT((pFreeEntry->Type & GDI_ENTRY_BASETYPE_MASK) == 0);
+    ASSERT(pFreeEntry->ProcessId == 0);
+    pFreeEntry->UserData = NULL;
+
+    do
+    {
+        idxFirstFree = GdiHandleTable->FirstFree;
+        pFreeEntry->KernelData = (PVOID)(ULONG_PTR)idxFirstFree;
+
+        idxPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree,
+                                             idxToFree,
+                                             idxFirstFree);
+    }
+    while (idxPrev != idxFirstFree);
+}
+
+
+BOOL
+INTERNAL_CALL
+GDIOBJ_ValidateHandle(HGDIOBJ hObj, ULONG ObjectType)
+{
+    PGDI_TABLE_ENTRY Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
+    if ((((ULONG_PTR)hObj & GDI_HANDLE_TYPE_MASK) == ObjectType) &&
+        (Entry->Type << GDI_ENTRY_UPPER_SHIFT) == GDI_HANDLE_GET_UPPER(hObj))
+    {
+        HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
+        if (pid == NULL || pid == PsGetCurrentProcessId())
+        {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+POBJ INTERNAL_CALL
+GDIOBJ_AllocObj(UCHAR BaseType)
+{
+    POBJ pObject;
+
+    ASSERT((BaseType & ~GDIObjTypeTotal) == 0);
+//    BaseType &= GDI_HANDLE_BASETYPE_MASK;
+
+    if (ObjTypeInfo[BaseType].bUseLookaside)
+    {
+        PPAGED_LOOKASIDE_LIST LookasideList;
+
+        LookasideList = GdiHandleTable->LookasideLists + BaseType;
+        pObject = ExAllocateFromPagedLookasideList(LookasideList);
+    }
+    else
+    {
+        pObject = ExAllocatePoolWithTag(PagedPool,
+                                        ObjTypeInfo[BaseType].ulBodySize,
+                                        ObjTypeInfo[BaseType].Tag);
+    }
+
+    if (pObject)
+    {
+        RtlZeroMemory(pObject, ObjTypeInfo[BaseType].ulBodySize);
+    }
 
+    return pObject;
 }
 
+
 /*!
  * Allocate memory for GDI object and return handle to it.
  *
  * \param ObjectType - type of object \ref GDI object types
  *
- * \return Handle of the allocated object.
- *
- * \note Use GDIOBJ_Lock() to obtain pointer to the new object.
- * \todo return the object pointer and lock it by default.
+ * \return Pointer to the allocated object, which is locked.
 */
-HGDIOBJ INTERNAL_CALL
-#ifdef GDI_DEBUG
-GDIOBJ_AllocObjDbg(PGDI_HANDLE_TABLE HandleTable, const char* file, int line, ULONG ObjectType)
-#else /* !GDI_DEBUG */
-GDIOBJ_AllocObj(PGDI_HANDLE_TABLE HandleTable, ULONG ObjectType)
-#endif /* GDI_DEBUG */
+POBJ INTERNAL_CALL
+GDIOBJ_AllocObjWithHandle(ULONG ObjectType)
 {
-  PW32PROCESS W32Process;
-  PGDIOBJHDR  newObject = NULL;
-  PPAGED_LOOKASIDE_LIST LookasideList = NULL;
-  HANDLE CurrentProcessId, LockedProcessId;
-  ULONG TypeIndex;
-#ifdef GDI_DEBUG
-  ULONG Attempts = 0;
-#endif
-
-  W32Process = PsGetCurrentProcessWin32Process();
-  /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
-     to take too many GDI objects, itself. */
-  if ( W32Process && W32Process->GDIObjects >= 0x2710 )
-    return NULL;
+    PPROCESSINFO W32Process;
+    POBJ  newObject = NULL;
+    HANDLE CurrentProcessId, LockedProcessId;
+    UCHAR TypeIndex;
+    UINT Index;
+    PGDI_TABLE_ENTRY Entry;
+    LONG TypeInfo;
 
-  ASSERT(ObjectType != GDI_OBJECT_TYPE_DONTCARE);
+    GDIDBG_INITLOOPTRACE();
 
-  TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(ObjectType);
-  if (ObjTypeInfo[TypeIndex].bUseLookaside)
-  {
-    LookasideList = FindLookasideList(HandleTable, TypeIndex);
-    if(LookasideList != NULL)
+    W32Process = PsGetCurrentProcessWin32Process();
+    /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
+       to take too many GDI objects, itself. */
+    if (W32Process && W32Process->GDIHandleCount >= 0x2710)
     {
-      newObject = ExAllocateFromPagedLookasideList(LookasideList);
+        DPRINT1("Too many objects for process!!!\n");
+        DPRINT1("DC %d BRUSH %d BITMAP %d FONT %d RGN %d\n",tDC,tBRUSH,tBITMAP,tFONT,tRGN);
+        GDIDBG_DUMPHANDLETABLE();
+        return NULL;
     }
-  }
-  else
-  {
-    newObject = ExAllocatePoolWithTag(PagedPool,
-                                      ObjTypeInfo[TypeIndex].ulBodySize + sizeof(GDIOBJHDR),
-                                      ObjTypeInfo[TypeIndex].Tag);
-  }
-  if(newObject != NULL)
-  {
-    PSLIST_ENTRY FreeEntry;
-    PGDI_TABLE_ENTRY Entry;
-    PGDIOBJ ObjectBody;
-    LONG TypeInfo;
 
-    CurrentProcessId = PsGetCurrentProcessId();
-    LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1);
+    ASSERT(ObjectType != GDI_OBJECT_TYPE_DONTCARE);
 
-    newObject->LockingThread = NULL;
-    newObject->Locks = 0;
+    TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(ObjectType);
 
-#ifdef GDI_DEBUG
-    newObject->createdfile = file;
-    newObject->createdline = line;
-    newObject->lockfile = NULL;
-    newObject->lockline = 0;
-#endif
+    newObject = GDIOBJ_AllocObj(TypeIndex);
+    if (!newObject)
+    {
+        DPRINT1("Not enough memory to allocate gdi object!\n");
+        return NULL;
+    }
 
-    ObjectBody = GDIHdrToBdy(newObject);
+    CurrentProcessId = PsGetCurrentProcessId();
+    LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1);
 
-    RtlZeroMemory(ObjectBody, GetObjectSize(TypeIndex));
+//    RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
 
     /* On Windows the higher 16 bit of the type field don't contain the
        full type from the handle, but the base type.
        (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
     TypeInfo = (ObjectType & GDI_HANDLE_BASETYPE_MASK) | (ObjectType >> GDI_ENTRY_UPPER_SHIFT);
 
-    FreeEntry = InterlockedPopEntrySList(&HandleTable->FreeEntriesHead);
-    if(FreeEntry != NULL)
+    Index = InterlockedPopFreeEntry();
+    if (Index != 0)
     {
-      HANDLE PrevProcId;
-      UINT Index;
+        HANDLE PrevProcId;
 
-      /* calculate the entry from the address of the entry in the free slot array */
-      Index = ((ULONG_PTR)FreeEntry - (ULONG_PTR)&HandleTable->FreeEntries[0]) /
-               sizeof(HandleTable->FreeEntries[0]);
-      Entry = &HandleTable->Entries[Index];
+        Entry = &GdiHandleTable->Entries[Index];
 
 LockHandle:
-      PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, 0);
-      if(PrevProcId == NULL)
-      {
-        HGDIOBJ Handle;
+        PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, 0);
+        if (PrevProcId == NULL)
+        {
+            PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
+            HGDIOBJ Handle;
 
-        ASSERT(Entry->KernelData == NULL);
+            Entry->KernelData = newObject;
 
-        Entry->KernelData = ObjectBody;
+            /* copy the reuse-counter */
+            TypeInfo |= Entry->Type & GDI_ENTRY_REUSE_MASK;
 
-        /* copy the reuse-counter */
-        TypeInfo |= Entry->Type & GDI_ENTRY_REUSE_MASK;
+            /* we found a free entry, no need to exchange this field atomically
+               since we're holding the lock */
+            Entry->Type = TypeInfo;
 
-        /* we found a free entry, no need to exchange this field atomically
-           since we're holding the lock */
-        Entry->Type = TypeInfo;
+            /* Create a handle */
+            Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT));
 
-        /* unlock the entry */
-        (void)InterlockedExchangePointer(&Entry->ProcessId, CurrentProcessId);
+            /* Initialize BaseObject fields */
+            newObject->hHmgr = Handle;
+            newObject->ulShareCount = 0;
+            newObject->cExclusiveLock = 1;
+            newObject->Tid = Thread;
 
-#ifdef GDI_DEBUG
-        memset ( GDIHandleAllocator[Index], 0xcd, GDI_STACK_LEVELS * sizeof(ULONG) );
-        KeRosGetStackFrames ( GDIHandleAllocator[Index], GDI_STACK_LEVELS );
-#endif /* GDI_DEBUG */
+            AllocTypeDataDump(TypeInfo);
 
-        if(W32Process != NULL)
-        {
-          InterlockedIncrement(&W32Process->GDIObjects);
-        }
-        Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT));
+            /* unlock the entry */
+            (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId);
 
-        DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, ObjectBody);
-        return Handle;
-      }
-      else
-      {
-#ifdef GDI_DEBUG
-        if(++Attempts > 20)
+            GDIDBG_CAPTUREALLOCATOR(Index);
+
+            if (W32Process != NULL)
+            {
+                InterlockedIncrement(&W32Process->GDIHandleCount);
+            }
+
+            DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, newObject);
+            return newObject;
+        }
+        else
         {
-          DPRINT1("[%d]Waiting on handle in index 0x%x\n", Attempts, Index);
+            GDIDBG_TRACELOOP(Index, PrevProcId, CurrentProcessId);
+            /* damn, someone is trying to lock the object even though it doesn't
+               even exist anymore, wait a little and try again!
+               FIXME - we shouldn't loop forever! Give up after some time! */
+            DelayExecution();
+            /* try again */
+            goto LockHandle;
         }
-#endif
-          /* damn, someone is trying to lock the object even though it doesn't
-             eve nexist anymore, wait a little and try again!
-             FIXME - we shouldn't loop forever! Give up after some time! */
-        DelayExecution();
-          /* try again */
-        goto LockHandle;
-      }
     }
 
-    if (ObjTypeInfo[TypeIndex].bUseLookaside)
+    GDIOBJ_FreeObj(newObject, TypeIndex);
+
+    DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
+    GDIDBG_DUMPHANDLETABLE();
+
+    return NULL;
+}
+
+
+VOID INTERNAL_CALL
+GDIOBJ_FreeObj(POBJ pObject, UCHAR BaseType)
+{
+    /* Object must not have a handle! */
+    ASSERT(pObject->hHmgr == NULL);
+
+    if (ObjTypeInfo[BaseType].bUseLookaside)
     {
-      ExFreeToPagedLookasideList(LookasideList, newObject);
+        PPAGED_LOOKASIDE_LIST LookasideList;
+
+        LookasideList = GdiHandleTable->LookasideLists + BaseType;
+        ExFreeToPagedLookasideList(LookasideList, pObject);
     }
     else
     {
-      ExFreePool(newObject);
+        ExFreePool(pObject);
     }
-    DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
-#ifdef GDI_DEBUG
-    IntDumpHandleTable(HandleTable);
-#endif /* GDI_DEBUG */
-  }
-  else
-  {
-    DPRINT1("Not enough memory to allocate gdi object!\n");
-  }
-  return NULL;
 }
 
 /*!
@@ -500,162 +536,254 @@ LockHandle:
  * \return Returns TRUE if succesful.
  * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
  * to the calling process.
+ *
+ * \bug This function should return VOID and kill the object no matter what...
 */
 BOOL INTERNAL_CALL
-#ifdef GDI_DEBUG
-GDIOBJ_FreeObjDbg(PGDI_HANDLE_TABLE HandleTable, const char* file, int line, HGDIOBJ hObj, DWORD ExpectedType)
-#else /* !GDI_DEBUG */
-GDIOBJ_FreeObj(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
-#endif /* GDI_DEBUG */
+GDIOBJ_FreeObjByHandle(HGDIOBJ hObj, DWORD ExpectedType)
 {
-  PGDI_TABLE_ENTRY Entry;
-  PPAGED_LOOKASIDE_LIST LookasideList;
-  HANDLE ProcessId, LockedProcessId, PrevProcId;
-  ULONG HandleType, HandleUpper, TypeIndex;
-  BOOL Silent;
-#ifdef GDI_DEBUG
-  ULONG Attempts = 0;
-#endif
+    PGDI_TABLE_ENTRY Entry;
+    HANDLE ProcessId, LockedProcessId, PrevProcId;
+    ULONG HandleType, HandleUpper, TypeIndex;
+    BOOL Silent;
 
-  DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj);
+    GDIDBG_INITLOOPTRACE();
 
-  if(GDI_HANDLE_IS_STOCKOBJ(hObj))
-  {
-    DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj);
-#ifdef GDI_DEBUG
-    DPRINT1("-> called from %s:%i\n", file, line);
-#endif
-    return FALSE;
-  }
+    DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj);
 
-  ProcessId = PsGetCurrentProcessId();
-  LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
+    if (GDI_HANDLE_IS_STOCKOBJ(hObj))
+    {
+        DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj);
+        GDIDBG_TRACECALLER();
+        return FALSE;
+    }
 
-  Silent = (ExpectedType & GDI_OBJECT_TYPE_SILENT);
-  ExpectedType &= ~GDI_OBJECT_TYPE_SILENT;
+    ProcessId = PsGetCurrentProcessId();
+    LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
 
-  HandleType = GDI_HANDLE_GET_TYPE(hObj);
-  HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
+    Silent = (ExpectedType & GDI_OBJECT_TYPE_SILENT);
+    ExpectedType &= ~GDI_OBJECT_TYPE_SILENT;
 
-  /* Check if we have the requested type */
-  if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
-        HandleType != ExpectedType) ||
-       HandleType == 0 )
-  {
-     DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
-             hObj, HandleType, ExpectedType);
-     return FALSE;
-  }
+    HandleType = GDI_HANDLE_GET_TYPE(hObj);
+    HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
 
-  Entry = GDI_HANDLE_GET_ENTRY(HandleTable, hObj);
+    /* Check if we have the requested type */
+    if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
+          HandleType != ExpectedType) ||
+         HandleType == 0 )
+    {
+        DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
+                hObj, HandleType, ExpectedType);
+        GDIDBG_TRACECALLER();
+        return FALSE;
+    }
+
+    Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
 
 LockHandle:
-  /* lock the object, we must not delete global objects, so don't exchange the locking
-     process ID to zero when attempting to lock a global object... */
-  PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, ProcessId);
-  if(PrevProcId == ProcessId)
-  {
-    if( (Entry->KernelData != NULL) &&
-        ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
+    /* lock the object, we must not delete global objects, so don't exchange the locking
+       process ID to zero when attempting to lock a global object... */
+    PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
+    if (PrevProcId == ProcessId)
     {
-      PGDIOBJHDR GdiHdr;
+        if ( (Entry->KernelData != NULL) &&
+             ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) &&
+             ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == (HandleUpper & GDI_ENTRY_BASETYPE_MASK)) )
+        {
+            POBJ Object;
 
-      GdiHdr = GDIBdyToHdr(Entry->KernelData);
+            Object = Entry->KernelData;
 
-      if(GdiHdr->Locks == 0)
-      {
-        BOOL Ret;
-        PW32PROCESS W32Process = PsGetCurrentProcessWin32Process();
+            if ((Object->cExclusiveLock == 0 ||
+                Object->Tid == (PTHREADINFO)PsGetCurrentThreadWin32Thread()) &&
+                 Object->ulShareCount == 0)
+            {
+                BOOL Ret;
+                PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process();
 
-        /* Clear the type field so when unlocking the handle it gets finally deleted and increment reuse counter */
-        Entry->Type = (Entry->Type + GDI_ENTRY_REUSE_INC) & GDI_ENTRY_REUSE_MASK;
-        Entry->KernelData = NULL;
+                /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
+                Entry->Type = (Entry->Type + GDI_ENTRY_REUSE_INC) & ~GDI_ENTRY_BASETYPE_MASK;
 
-        /* unlock the handle slot */
-        (void)InterlockedExchangePointer(&Entry->ProcessId, NULL);
+                /* unlock the handle slot */
+                (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL);
 
-        /* push this entry to the free list */
-        InterlockedPushEntrySList(&HandleTable->FreeEntriesHead,
-                                  &HandleTable->FreeEntries[GDI_ENTRY_TO_INDEX(HandleTable, Entry)]);
+                /* push this entry to the free list */
+                InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable, Entry));
 
-        if(W32Process != NULL)
-        {
-          InterlockedDecrement(&W32Process->GDIObjects);
-        }
+                Object->hHmgr = NULL;
 
-        /* call the cleanup routine. */
-        TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(HandleType);
-        Ret = RunCleanupCallback(GDIHdrToBdy(GdiHdr), TypeIndex);
+                if (W32Process != NULL)
+                {
+                    InterlockedDecrement(&W32Process->GDIHandleCount);
+                }
 
-        /* Now it's time to free the memory */
-        if (ObjTypeInfo[TypeIndex].bUseLookaside)
-        {
-          LookasideList = FindLookasideList(HandleTable, TypeIndex);
-          if(LookasideList != NULL)
-          {
-            ExFreeToPagedLookasideList(LookasideList, GdiHdr);
-          }
+                /* call the cleanup routine. */
+                TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(HandleType);
+                Ret = ObjTypeInfo[TypeIndex].CleanupProc(Object);
+
+                DeAllocTypeDataDump(HandleType);
+
+                /* Now it's time to free the memory */
+                GDIOBJ_FreeObj(Object, TypeIndex);
+
+                GDIDBG_CAPTUREDELETER(hObj);
+                return Ret;
+            }
+            else if (Object->ulShareCount != 0)
+            {
+                NTSTATUS Status;
+                PEPROCESS OldProcess;
+                Object->BaseFlags |= BASEFLAG_READY_TO_DIE;
+                DPRINT("Object %p, ulShareCount = %d\n", Object->hHmgr, Object->ulShareCount);
+                /* Set NULL owner. Do the work here to avoid race conditions */
+                Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
+                if (NT_SUCCESS(Status))
+                {
+                    PPROCESSINFO W32Process = (PPROCESSINFO)OldProcess->Win32Process;
+                    if (W32Process != NULL)
+                    {
+                        InterlockedDecrement(&W32Process->GDIHandleCount);
+                    }
+                    ObDereferenceObject(OldProcess);
+                }
+                (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL);
+                /* Don't wait on shared locks */
+                return FALSE;
+            }
+            else
+            {
+                /*
+                 * The object is currently locked by another thread, so freeing is forbidden!
+                 */
+                DPRINT1("Object->cExclusiveLock = %d\n", Object->cExclusiveLock);
+                GDIDBG_TRACECALLER();
+                GDIDBG_TRACELOCKER(hObj);
+                (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+                /* do not assert here for it will call again from dxg.sys it being call twice */
+
+                DelayExecution();
+                goto LockHandle;
+            }
         }
         else
         {
-          ExFreePool(GdiHdr);
+            LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj");
+            (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
         }
+    }
+    else if (PrevProcId == LockedProcessId)
+    {
+        GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
 
-        return Ret;
-      }
-      else
-      {
-        /*
-         * The object is currently locked, so freeing is forbidden!
-         */
-        DPRINT1("GdiHdr->Locks: %d\n", GdiHdr->Locks);
-#ifdef GDI_DEBUG
-        DPRINT1("Locked from: %s:%d\n", GdiHdr->lockfile, GdiHdr->lockline);
-#endif
-        ASSERT(FALSE);
-      }
+        /* the object is currently locked, wait some time and try again.
+           FIXME - we shouldn't loop forever! Give up after some time! */
+        DelayExecution();
+        /* try again */
+        goto LockHandle;
     }
     else
     {
-      LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj");
-      (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
+        if (!Silent)
+        {
+            if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == 0)
+            {
+                DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj);
+            }
+            else if (((ULONG_PTR)PrevProcId & ~0x1) == 0)
+            {
+                DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj);
+            }
+            else
+            {
+                DPRINT1("Attempted to free foreign handle: 0x%x Owner: 0x%x from Caller: 0x%x\n", hObj, (ULONG_PTR)PrevProcId & ~0x1, (ULONG_PTR)ProcessId & ~0x1);
+            }
+            DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry->Type, Entry->KernelData, Entry->ProcessId);
+            GDIDBG_TRACECALLER();
+            GDIDBG_TRACEALLOCATOR(hObj);
+        }
     }
-  }
-  else if(PrevProcId == LockedProcessId)
-  {
-#ifdef GDI_DEBUG
-    if(++Attempts > 20)
+
+    return FALSE;
+}
+
+BOOL
+FASTCALL
+IsObjectDead(HGDIOBJ hObject)
+{
+    INT Index = GDI_HANDLE_GET_INDEX(hObject);
+    PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
+    // We check to see if the objects are knocking on deaths door.
+    if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
+        return FALSE;
+    else
     {
-      DPRINT1("[%d]Waiting on 0x%x\n", Attempts, hObj);
+        DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject);
+        return TRUE; // return true and move on.
     }
-#endif
-    /* the object is currently locked, wait some time and try again.
-       FIXME - we shouldn't loop forever! Give up after some time! */
-    DelayExecution();
-    /* try again */
-    goto LockHandle;
+}
+
+
+BOOL
+FASTCALL
+bPEBCacheHandle(HGDIOBJ Handle, int oType, PVOID pAttr)
+{
+  PGDIHANDLECACHE GdiHandleCache;
+  HGDIOBJ *hPtr;
+  BOOL Ret = FALSE;
+  int Offset = 0, Number;
+  HANDLE Lock;
+
+  GdiHandleCache = (PGDIHANDLECACHE)NtCurrentTeb()->ProcessEnvironmentBlock->GdiHandleBuffer;
+
+  switch (oType)
+  {
+     case hctBrushHandle:
+        Offset = 0;
+        break;
+
+     case hctPenHandle:
+        Offset = CACHE_BRUSH_ENTRIES;
+        break;
+
+     case hctRegionHandle:
+        Offset = CACHE_BRUSH_ENTRIES+CACHE_PEN_ENTRIES;
+        break;
+
+     default:
+        return FALSE;
   }
-  else
+
+  Lock = InterlockedCompareExchangePointer( (PVOID*)&GdiHandleCache->ulLock,
+                                             NtCurrentTeb(),
+                                             NULL );
+  if (Lock) return FALSE;
+
+  _SEH2_TRY
   {
-    if(!Silent)
-    {
-      if(((ULONG_PTR)PrevProcId & ~0x1) == 0)
-      {
-        DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj);
-        KeRosDumpStackFrames(NULL, 20);
-      }
-      else
-      {
-        DPRINT1("Attempted to free foreign handle: 0x%x Owner: 0x%x from Caller: 0x%x\n", hObj, (ULONG_PTR)PrevProcId & ~0x1, (ULONG_PTR)ProcessId & ~0x1);
-        KeRosDumpStackFrames(NULL, 20);
-      }
-#ifdef GDI_DEBUG
-      DPRINT1("-> called from %s:%i\n", file, line);
-#endif
-    }
+     Number = GdiHandleCache->ulNumHandles[oType];
+
+     hPtr = GdiHandleCache->Handle + Offset;
+
+     if ( pAttr && oType == hctRegionHandle)
+     {
+        if ( Number < CACHE_REGION_ENTRIES )
+        {
+           ((PRGN_ATTR)pAttr)->AttrFlags |= ATTR_CACHED;
+           hPtr[Number] = Handle;
+           GdiHandleCache->ulNumHandles[oType]++;
+           DPRINT("Put Handle Count %d PEB 0x%x\n", GdiHandleCache->ulNumHandles[oType], NtCurrentTeb()->ProcessEnvironmentBlock);
+           Ret = TRUE;
+        }
+     }
   }
+  _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+  {
+     Ret = FALSE;
+  }
+  _SEH2_END;
 
-  return FALSE;
+  (void)InterlockedExchangePointer((PVOID*)&GdiHandleCache->ulLock, Lock);
+  return Ret;
 }
 
 /*!
@@ -663,77 +791,157 @@ LockHandle:
  * \param      hObject object handle
  * \return     if the function fails the returned value is FALSE.
 */
-BOOL STDCALL
-NtGdiDeleteObject(HGDIOBJ hObject)
+BOOL
+FASTCALL
+GreDeleteObject(HGDIOBJ hObject)
 {
-  DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
+    INT Index;
+    PGDI_TABLE_ENTRY Entry;
+    DWORD dwObjectType;
+    PVOID pAttr = NULL;
 
-  return NULL != hObject
-         ? GDIOBJ_FreeObj(GdiHandleTable, hObject, GDI_OBJECT_TYPE_DONTCARE) : FALSE;
+    DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
+    if (!IsObjectDead(hObject))
+    {
+       dwObjectType = GDIOBJ_GetObjectType(hObject);
+
+       Index = GDI_HANDLE_GET_INDEX(hObject);
+       Entry = &GdiHandleTable->Entries[Index];
+       pAttr = Entry->UserData;
+
+       switch (dwObjectType)
+       {
+          case GDI_OBJECT_TYPE_BRUSH:
+             break;
+
+          case GDI_OBJECT_TYPE_REGION:
+             /* If pAttr NULL, the probability is high for System Region. */
+             if ( pAttr &&
+                  bPEBCacheHandle(hObject, hctRegionHandle, pAttr))
+             {
+                /* User space handle only! */
+                return TRUE;
+             }
+             if (pAttr)
+             {
+                FreeObjectAttr(pAttr);
+                Entry->UserData = NULL;
+             }
+             break;
+
+          case GDI_OBJECT_TYPE_DC:
+//             DC_FreeDcAttr(hObject);
+             break;
+       }
+
+       return NULL != hObject
+               ? GDIOBJ_FreeObjByHandle(hObject, dwObjectType) : FALSE;
+    }
+    else
+    {
+        DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject);
+        return TRUE; // return true and move on.
+    }
 }
 
+VOID
+FASTCALL
+IntDeleteHandlesForProcess(struct _EPROCESS *Process, ULONG ObjectType)
+{
+    PGDI_TABLE_ENTRY Entry, End;
+    ULONG Index = RESERVE_ENTRIES_COUNT;
+    HANDLE ProcId;
+    PPROCESSINFO W32Process;
+
+    W32Process = (PPROCESSINFO)Process->Win32Process;
+    ASSERT(W32Process);
+
+    if (W32Process->GDIHandleCount > 0)
+    {
+       ProcId = Process->UniqueProcessId;
+
+    /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
+               we should delete it directly here! */
+
+        End = &GdiHandleTable->Entries[GDI_HANDLE_COUNT];
+        for (Entry = &GdiHandleTable->Entries[RESERVE_ENTRIES_COUNT];
+             Entry != End;
+             Entry++, Index++)
+        {
+            /* ignore the lock bit */
+            if ( (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId)
+            {
+                if ( (Entry->Type & GDI_ENTRY_BASETYPE_MASK) == ObjectType ||
+                     ObjectType == GDI_OBJECT_TYPE_DONTCARE)
+                {
+                    HGDIOBJ ObjectHandle;
+
+                    /* Create the object handle for the entry, the lower(!) 16 bit of the
+                       Type field includes the type of the object including the stock
+                       object flag - but since stock objects don't have a process id we can
+                       simply ignore this fact here. */
+                    ObjectHandle = (HGDIOBJ)(Index | (Entry->Type << GDI_ENTRY_UPPER_SHIFT));
+
+                    if (!GDIOBJ_FreeObjByHandle(ObjectHandle, GDI_OBJECT_TYPE_DONTCARE))
+                    {
+                        DPRINT1("Failed to delete object %p!\n", ObjectHandle);
+                    }
+
+                    if (W32Process->GDIHandleCount == 0)
+                    {
+                        /* there are no more gdi handles for this process, bail */
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
+
+
 /*!
  * Internal function. Called when the process is destroyed to free the remaining GDI handles.
  * \param      Process - PID of the process that will be destroyed.
 */
 BOOL INTERNAL_CALL
-GDI_CleanupForProcess (PGDI_HANDLE_TABLE HandleTable, struct _EPROCESS *Process)
+GDI_CleanupForProcess(struct _EPROCESS *Process)
 {
-  PGDI_TABLE_ENTRY Entry, End;
-  PEPROCESS CurrentProcess;
-  PW32PROCESS W32Process;
-  HANDLE ProcId;
-  ULONG Index = RESERVE_ENTRIES_COUNT;
-
-  DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId);
-  CurrentProcess = PsGetCurrentProcess();
-  if (CurrentProcess != Process)
+    PEPROCESS CurrentProcess;
+    PPROCESSINFO W32Process;
+
+    DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId);
+    CurrentProcess = PsGetCurrentProcess();
+    if (CurrentProcess != Process)
     {
-      KeAttachProcess(&Process->Pcb);
+        KeAttachProcess(&Process->Pcb);
     }
-  W32Process = (PW32PROCESS)Process->Win32Process;
-  ASSERT(W32Process);
 
-  if(W32Process->GDIObjects > 0)
-  {
-    /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
-               we should delete it directly here! */
-    ProcId = Process->UniqueProcessId;
+    W32Process = (PPROCESSINFO)CurrentProcess->Win32Process;
+
+    /* Delete objects. Begin with types that are not referenced by other types */
+    IntDeleteHandlesForProcess(Process, GDILoObjType_LO_DC_TYPE);
+    IntDeleteHandlesForProcess(Process, GDILoObjType_LO_BRUSH_TYPE);
+    IntDeleteHandlesForProcess(Process, GDILoObjType_LO_BITMAP_TYPE);
+
+    /* Finally finish with what's left */
+    IntDeleteHandlesForProcess(Process, GDI_OBJECT_TYPE_DONTCARE);
 
-    End = &HandleTable->Entries[GDI_HANDLE_COUNT];
-    for(Entry = &HandleTable->Entries[RESERVE_ENTRIES_COUNT];
-        Entry != End;
-        Entry++, Index++)
+    if (CurrentProcess != Process)
     {
-      /* ignore the lock bit */
-      if((HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId && (Entry->Type & ~GDI_ENTRY_REUSE_MASK) != 0)
-      {
-        HGDIOBJ ObjectHandle;
-
-        /* Create the object handle for the entry, the lower(!) 16 bit of the
-           Type field includes the type of the object including the stock
-           object flag - but since stock objects don't have a process id we can
-           simply ignore this fact here. */
-        ObjectHandle = (HGDIOBJ)(Index | (Entry->Type << GDI_ENTRY_UPPER_SHIFT));
-
-        if(GDIOBJ_FreeObj(HandleTable, ObjectHandle, GDI_OBJECT_TYPE_DONTCARE) &&
-           W32Process->GDIObjects == 0)
-        {
-          /* there are no more gdi handles for this process, bail */
-          break;
-        }
-      }
+        KeDetachProcess();
     }
-  }
 
-  if (CurrentProcess != Process)
+#ifdef GDI_DEBUG
+       GdiDbgHTIntegrityCheck();
+#endif
+
+    DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);
+    if (W32Process->GDIHandleCount > 0)
     {
-      KeDetachProcess();
+        DPRINT1("Leaking %d handles!\n", W32Process->GDIHandleCount);
     }
 
-  DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);
-
-  return TRUE;
+    return TRUE;
 }
 
 /*!
@@ -747,139 +955,137 @@ GDI_CleanupForProcess (PGDI_HANDLE_TABLE HandleTable, struct _EPROCESS *Process)
  * \todo Get rid of the ExpectedType parameter!
 */
 PGDIOBJ INTERNAL_CALL
-#ifdef GDI_DEBUG
-GDIOBJ_LockObjDbg (PGDI_HANDLE_TABLE HandleTable, const char* file, int line, HGDIOBJ hObj, DWORD ExpectedType)
-#else /* !GDI_DEBUG */
-GDIOBJ_LockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
-#endif /* GDI_DEBUG */
+GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
 {
-   USHORT HandleIndex;
-   PGDI_TABLE_ENTRY Entry;
-   HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
-   PGDIOBJ Object = NULL;
-   ULONG HandleType, HandleUpper;
-
-   HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
-   HandleType = GDI_HANDLE_GET_TYPE(hObj);
-   HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
-
-   /* Check that the handle index is valid. */
-   if (HandleIndex >= GDI_HANDLE_COUNT)
-      return NULL;
-
-   Entry = &HandleTable->Entries[HandleIndex];
-
-   /* Check if we have the requested type */
-   if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
-         HandleType != ExpectedType) ||
-        HandleType == 0 )
-   {
-      DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
-              hObj, HandleType, ExpectedType);
-      return NULL;
-   }
-
-   ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
-   HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
-    
-   /* Check for invalid owner. */
-   if (ProcessId != HandleProcessId && HandleProcessId != NULL)
-   {
-      return NULL;
-   }
-   
-   /*
-    * Prevent the thread from being terminated during the locking process.
-    * It would result in undesired effects and inconsistency of the global
-    * handle table.
-    */
-
-   KeEnterCriticalRegion();
-
-   /*
-    * Loop until we either successfully lock the handle entry & object or
-    * fail some of the check.
-    */
-   
-   for (;;)
-   {
-      /* Lock the handle table entry. */
-      LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
-      PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, 
-                                                     LockedProcessId,
-                                                     HandleProcessId);
-
-      if (PrevProcId == HandleProcessId)
-      {
-         /*
-          * We're locking an object that belongs to our process or it's a
-          * global object if HandleProcessId is 0 here.
-          */
-
-         if ( (Entry->KernelData != NULL) &&
-              ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
-         {
-            PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
-            PETHREAD Thread = PsGetCurrentThread();
-
-            if (GdiHdr->Locks == 0)
+    ULONG HandleIndex;
+    PGDI_TABLE_ENTRY Entry;
+    HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
+    POBJ Object = NULL;
+    ULONG HandleType, HandleUpper;
+
+    /* Check for dummy call */
+    if(hObj == NULL)
+        return NULL ;
+
+    GDIDBG_INITLOOPTRACE();
+
+    HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
+    HandleType = GDI_HANDLE_GET_TYPE(hObj);
+    HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
+
+    /* Check that the handle index is valid. */
+    if (HandleIndex >= GDI_HANDLE_COUNT )
+        return NULL;
+
+    Entry = &GdiHandleTable->Entries[HandleIndex];
+
+    /* Check if we have the requested type */
+    if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
+          HandleType != ExpectedType) ||
+         HandleType == 0 )
+    {
+        DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
+                hObj, HandleType, ExpectedType);
+        GDIDBG_TRACECALLER();
+        GDIDBG_TRACEALLOCATOR(hObj);
+        GDIDBG_TRACEDELETER(hObj);
+        return NULL;
+    }
+
+    ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
+    HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
+
+    /* Check for invalid owner. */
+    if (ProcessId != HandleProcessId && HandleProcessId != NULL)
+    {
+        DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj, ProcessId, HandleProcessId);
+        GDIDBG_TRACECALLER();
+        GDIDBG_TRACEALLOCATOR(hObj);
+        return NULL;
+    }
+
+    /*
+     * Prevent the thread from being terminated during the locking process.
+     * It would result in undesired effects and inconsistency of the global
+     * handle table.
+     */
+
+    KeEnterCriticalRegion();
+
+    /*
+     * Loop until we either successfully lock the handle entry & object or
+     * fail some of the check.
+     */
+
+    for (;;)
+    {
+        /* Lock the handle table entry. */
+        LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
+        PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
+                                                        LockedProcessId,
+                                                        HandleProcessId);
+
+        if (PrevProcId == HandleProcessId)
+        {
+            /*
+             * We're locking an object that belongs to our process or it's a
+             * global object if HandleProcessId is 0 here.
+             */
+
+            if ( (Entry->KernelData != NULL) &&
+                 ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
             {
-               GdiHdr->LockingThread = Thread;
-               GdiHdr->Locks = 1;
-#ifdef GDI_DEBUG
-               GdiHdr->lockfile = file;
-               GdiHdr->lockline = line;
-#endif
-               Object = Entry->KernelData;
+                PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
+                Object = Entry->KernelData;
+
+                if (Object->cExclusiveLock == 0)
+                {
+                    Object->Tid = Thread;
+                    Object->cExclusiveLock = 1;
+                    GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj))
+                }
+                else
+                {
+                    if (Object->Tid != Thread)
+                    {
+                        /* Unlock the handle table entry. */
+                        (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+
+                        DelayExecution();
+                        continue;
+                    }
+                    InterlockedIncrement((PLONG)&Object->cExclusiveLock);
+                }
             }
             else
             {
-               InterlockedIncrement((PLONG)&GdiHdr->Locks);
-               if (GdiHdr->LockingThread != Thread)
-               {
-                  InterlockedDecrement((PLONG)&GdiHdr->Locks);
-
-                  /* Unlock the handle table entry. */
-                  (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
-
-                  DelayExecution();
-                  continue;
-               }
-               Object = Entry->KernelData;
+                /*
+                 * Debugging code. Report attempts to lock deleted handles and
+                 * locking type mismatches.
+                 */
+                LockErrorDebugOutput(hObj, Entry, "GDIOBJ_LockObj");
             }
-         }
-         else
-         {
-            /*
-             * Debugging code. Report attempts to lock deleted handles and
-             * locking type mismatches.
-             */
-            LockErrorDebugOutput(hObj, Entry, "GDIOBJ_LockObj");
 
-#ifdef GDI_DEBUG
-            DPRINT1("-> called from %s:%i\n", file, line);
-#endif
-         }
-
-         /* Unlock the handle table entry. */
-         (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
+            /* Unlock the handle table entry. */
+            (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
 
-         break;
-      }
-      else
-      {
-         /*
-          * The handle is currently locked, wait some time and try again.
-          */
+            break;
+        }
+        else
+        {
+            /*
+             * The handle is currently locked, wait some time and try again.
+             */
+            GDIDBG_TRACELOOP(hObj, PrevProcId, NULL);
 
-         DelayExecution();
-         continue;
-      }
-   }
+            DelayExecution();
+            continue;
+        }
+    }
 
-   KeLeaveCriticalRegion();
+    KeLeaveCriticalRegion();
 
-   return Object;
+    return Object;
 }
 
 
@@ -895,558 +1101,522 @@ GDIOBJ_LockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
  * \todo Get rid of the ExpectedType parameter!
 */
 PGDIOBJ INTERNAL_CALL
-#ifdef GDI_DEBUG
-GDIOBJ_ShareLockObjDbg (PGDI_HANDLE_TABLE HandleTable, const char* file, int line, HGDIOBJ hObj, DWORD ExpectedType)
-#else /* !GDI_DEBUG */
-GDIOBJ_ShareLockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
-#endif /* GDI_DEBUG */
+GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
 {
-   USHORT HandleIndex;
-   PGDI_TABLE_ENTRY Entry;
-   HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
-   PGDIOBJ Object = NULL;
-   ULONG_PTR HandleType, HandleUpper;
-
-   HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
-   HandleType = GDI_HANDLE_GET_TYPE(hObj);
-   HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
-
-   /* Check that the handle index is valid. */
-   if (HandleIndex >= GDI_HANDLE_COUNT)
-      return NULL;
-
-   /* Check if we have the requested type */
-   if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
-         HandleType != ExpectedType) ||
-        HandleType == 0 )
-   {
-      DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
-              hObj, HandleType, ExpectedType);
-      return NULL;
-   }
-
-   Entry = &HandleTable->Entries[HandleIndex];
-
-   ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
-   HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
-    
-   /* Check for invalid owner. */
-   if (ProcessId != HandleProcessId && HandleProcessId != NULL)
-   {
-      return NULL;
-   }
-   
-   /*
-    * Prevent the thread from being terminated during the locking process.
-    * It would result in undesired effects and inconsistency of the global
-    * handle table.
-    */
-
-   KeEnterCriticalRegion();
-
-   /*
-    * Loop until we either successfully lock the handle entry & object or
-    * fail some of the check.
-    */
-   
-   for (;;)
-   {
-      /* Lock the handle table entry. */
-      LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
-      PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, 
-                                                     LockedProcessId,
-                                                     HandleProcessId);
-
-      if (PrevProcId == HandleProcessId)
-      {
-         /*
-          * We're locking an object that belongs to our process or it's a
-          * global object if HandleProcessId is 0 here.
-          */
-
-         if ( (Entry->KernelData != NULL) &&
-              (HandleUpper == (Entry->Type << GDI_ENTRY_UPPER_SHIFT)) )
-         {
-            PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
+    ULONG HandleIndex;
+    PGDI_TABLE_ENTRY Entry;
+    HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
+    POBJ Object = NULL;
+    ULONG_PTR HandleType, HandleUpper;
 
-#ifdef GDI_DEBUG
-            if (InterlockedIncrement((PLONG)&GdiHdr->Locks) == 1)
-            {
-               GdiHdr->lockfile = file;
-               GdiHdr->lockline = line;
-            }
-#else
-            InterlockedIncrement((PLONG)&GdiHdr->Locks);
-#endif
-            Object = Entry->KernelData;
-         }
-         else
-         {
-            /*
-             * Debugging code. Report attempts to lock deleted handles and
-             * locking type mismatches.
-             */
-            LockErrorDebugOutput(hObj, Entry, "GDIOBJ_ShareLockObj");
+    /* Check for dummy call */
+    if(hObj == NULL)
+        return NULL ;
 
-#ifdef GDI_DEBUG
-            DPRINT1("-> called from %s:%i\n", file, line);
-#endif
-         }
+    HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
+    HandleType = GDI_HANDLE_GET_TYPE(hObj);
+    HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
 
-         /* Unlock the handle table entry. */
-         (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
+    /* Check that the handle index is valid. */
+    if (HandleIndex >= GDI_HANDLE_COUNT)
+        return NULL;
 
-         break;
-      }
-      else
-      {
-         /*
-          * The handle is currently locked, wait some time and try again.
-          */
+    /* Check if we have the requested type */
+    if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
+          HandleType != ExpectedType) ||
+         HandleType == 0 )
+    {
+        DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
+                hObj, HandleType, ExpectedType);
+        return NULL;
+    }
 
-         DelayExecution();
-         continue;
-      }
-   }
+    Entry = &GdiHandleTable->Entries[HandleIndex];
 
-   KeLeaveCriticalRegion();
+    ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
+    HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
 
-   return Object;
-}
+    /* Check for invalid owner. */
+    if (ProcessId != HandleProcessId && HandleProcessId != NULL)
+    {
+        return NULL;
+    }
 
+    /*
+     * Prevent the thread from being terminated during the locking process.
+     * It would result in undesired effects and inconsistency of the global
+     * handle table.
+     */
 
-/*!
- * Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
- * as soon as you don't need to have access to it's data.
+    KeEnterCriticalRegion();
 
- * \param Object       Object pointer (as returned by GDIOBJ_LockObj).
- */
-VOID INTERNAL_CALL
-GDIOBJ_UnlockObjByPtr(PGDI_HANDLE_TABLE HandleTable, PGDIOBJ Object)
-{
-   PGDIOBJHDR GdiHdr = GDIBdyToHdr(Object);
-#ifdef GDI_DEBUG
-   if (InterlockedDecrement((PLONG)&GdiHdr->Locks) == 0)
-   {
-      GdiHdr->lockfile = NULL;
-      GdiHdr->lockline = 0;
-   }
+    /*
+     * Loop until we either successfully lock the handle entry & object or
+     * fail some of the check.
+     */
+
+    for (;;)
+    {
+        /* Lock the handle table entry. */
+        LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
+        PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
+                                                        LockedProcessId,
+                                                        HandleProcessId);
+
+        if (PrevProcId == HandleProcessId)
+        {
+            /*
+             * We're locking an object that belongs to our process or it's a
+             * global object if HandleProcessId is 0 here.
+             */
+
+            if ( (Entry->KernelData != NULL) &&
+                 (HandleUpper == (Entry->Type << GDI_ENTRY_UPPER_SHIFT)) )
+            {
+                Object = (POBJ)Entry->KernelData;
+
+GDIDBG_CAPTURESHARELOCKER(HandleIndex);
+#ifdef GDI_DEBUG3
+                if (InterlockedIncrement((PLONG)&Object->ulShareCount) == 1)
+                {
+                    memset(GDIHandleLocker[HandleIndex], 0x00, GDI_STACK_LEVELS * sizeof(ULONG));
+                    RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleShareLocker[HandleIndex], NULL);
+                }
 #else
-   if (InterlockedDecrement((PLONG)&GdiHdr->Locks) < 0)
-       DPRINT1("Trying to unlock non-existant object\n");
+                InterlockedIncrement((PLONG)&Object->ulShareCount);
 #endif
-}
-
-BOOL INTERNAL_CALL
-GDIOBJ_OwnedByCurrentProcess(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ ObjectHandle)
-{
-  PGDI_TABLE_ENTRY Entry;
-  HANDLE ProcessId;
-  BOOL Ret;
+            }
+            else
+            {
+                /*
+                 * Debugging code. Report attempts to lock deleted handles and
+                 * locking type mismatches.
+                 */
+                LockErrorDebugOutput(hObj, Entry, "GDIOBJ_ShareLockObj");
+            }
 
-  DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
+            /* Unlock the handle table entry. */
+            (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
 
-  if(!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
-  {
-    ProcessId = PsGetCurrentProcessId();
+            break;
+        }
+        else
+        {
+            /*
+             * The handle is currently locked, wait some time and try again.
+             */
 
-    Entry = GDI_HANDLE_GET_ENTRY(HandleTable, ObjectHandle);
-    Ret = Entry->KernelData != NULL &&
-          (Entry->Type & ~GDI_ENTRY_REUSE_MASK) != 0 &&
-          (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcessId;
+            DelayExecution();
+            continue;
+        }
+    }
 
-    return Ret;
-  }
+    KeLeaveCriticalRegion();
 
-  return FALSE;
+    return Object;
 }
 
 BOOL INTERNAL_CALL
-GDIOBJ_ConvertToStockObj(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ *phObj)
+GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle)
 {
-/*
- * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
- *             MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
- */
-  PGDI_TABLE_ENTRY Entry;
-  HANDLE ProcessId, LockedProcessId, PrevProcId;
-  PETHREAD Thread;
-  HGDIOBJ hObj;
-#ifdef GDI_DEBUG
-  ULONG Attempts = 0;
-#endif
+    PGDI_TABLE_ENTRY Entry;
+    HANDLE ProcessId;
+    BOOL Ret;
 
-  ASSERT(phObj);
-  hObj = *phObj;
+    DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
 
-  DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj);
+    if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
+    {
+        ProcessId = PsGetCurrentProcessId();
 
-  Thread = PsGetCurrentThread();
+        Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
+        Ret = Entry->KernelData != NULL &&
+              (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
+              (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcessId;
 
-  if(!GDI_HANDLE_IS_STOCKOBJ(hObj))
-  {
-    ProcessId = PsGetCurrentProcessId();
-    LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
+        return Ret;
+    }
 
-    Entry = GDI_HANDLE_GET_ENTRY(HandleTable, hObj);
+    return FALSE;
+}
 
-LockHandle:
-    /* lock the object, we must not convert stock objects, so don't check!!! */
-    PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, ProcessId);
-    if(PrevProcId == ProcessId)
-    {
-      LONG NewType, PrevType, OldType;
+BOOL INTERNAL_CALL
+GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
+{
+    /*
+     * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
+     *             MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
+     */
+    PGDI_TABLE_ENTRY Entry;
+    HANDLE ProcessId, LockedProcessId, PrevProcId;
+    PTHREADINFO Thread;
+    HGDIOBJ hObj;
 
-      /* we're locking an object that belongs to our process. First calculate
-         the new object type including the stock object flag and then try to
-         exchange it.*/
-      OldType = ((ULONG)hObj & GDI_HANDLE_BASETYPE_MASK);
-      OldType |= GDI_HANDLE_GET_UPPER(hObj) >> GDI_ENTRY_UPPER_SHIFT;
+    GDIDBG_INITLOOPTRACE();
 
-      /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
-      NewType = OldType | GDI_ENTRY_STOCK_MASK;
+    ASSERT(phObj);
+    hObj = *phObj;
 
-      /* Try to exchange the type field - but only if the old (previous type) matches! */
-      PrevType = InterlockedCompareExchange(&Entry->Type, NewType, OldType);
-      if(PrevType == OldType && Entry->KernelData != NULL)
-      {
-        PETHREAD PrevThread;
-        PGDIOBJHDR GdiHdr;
+    DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj);
 
-        /* We successfully set the stock object flag.
-           KernelData should never be NULL here!!! */
-        ASSERT(Entry->KernelData);
+    Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
 
-        GdiHdr = GDIBdyToHdr(Entry->KernelData);
+    if (!GDI_HANDLE_IS_STOCKOBJ(hObj))
+    {
+        ProcessId = PsGetCurrentProcessId();
+        LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
 
-        PrevThread = GdiHdr->LockingThread;
-        if(GdiHdr->Locks == 0 || PrevThread == Thread)
-        {
-          /* dereference the process' object counter */
-          if(PrevProcId != GDI_GLOBAL_PROCESS)
-          {
-            PEPROCESS OldProcess;
-            PW32PROCESS W32Process;
-            NTSTATUS Status;
+        Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
 
-            /* FIXME */
-            Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
-            if(NT_SUCCESS(Status))
+LockHandle:
+        /* lock the object, we must not convert stock objects, so don't check!!! */
+        PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
+        if (PrevProcId == ProcessId)
+        {
+            LONG NewType, PrevType, OldType;
+
+            /* we're locking an object that belongs to our process. First calculate
+               the new object type including the stock object flag and then try to
+               exchange it.*/
+            /* On Windows the higher 16 bit of the type field don't contain the
+               full type from the handle, but the base type.
+               (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
+            OldType = ((ULONG)hObj & GDI_HANDLE_BASETYPE_MASK) | ((ULONG)hObj >> GDI_ENTRY_UPPER_SHIFT);
+            /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
+               we copy them as we can't get them from the handle */
+            OldType |= Entry->Type & GDI_ENTRY_FLAGS_MASK;
+
+            /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
+            NewType = OldType | GDI_ENTRY_STOCK_MASK;
+
+            /* Try to exchange the type field - but only if the old (previous type) matches! */
+            PrevType = InterlockedCompareExchange(&Entry->Type, NewType, OldType);
+            if (PrevType == OldType && Entry->KernelData != NULL)
             {
-              W32Process = (PW32PROCESS)OldProcess->Win32Process;
-              if(W32Process != NULL)
-              {
-                InterlockedDecrement(&W32Process->GDIObjects);
-              }
-              ObDereferenceObject(OldProcess);
+                PTHREADINFO PrevThread;
+                POBJ Object;
+
+                /* We successfully set the stock object flag.
+                   KernelData should never be NULL here!!! */
+                ASSERT(Entry->KernelData);
+
+                Object = Entry->KernelData;
+
+                PrevThread = Object->Tid;
+                if (Object->cExclusiveLock == 0 || PrevThread == Thread)
+                {
+                    /* dereference the process' object counter */
+                    if (PrevProcId != GDI_GLOBAL_PROCESS)
+                    {
+                        PEPROCESS OldProcess;
+                        PPROCESSINFO W32Process;
+                        NTSTATUS Status;
+
+                        /* FIXME */
+                        Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
+                        if (NT_SUCCESS(Status))
+                        {
+                            W32Process = (PPROCESSINFO)OldProcess->Win32Process;
+                            if (W32Process != NULL)
+                            {
+                                InterlockedDecrement(&W32Process->GDIHandleCount);
+                            }
+                            ObDereferenceObject(OldProcess);
+                        }
+                    }
+
+                    hObj = (HGDIOBJ)((ULONG)(hObj) | GDI_HANDLE_STOCK_MASK);
+                    *phObj = hObj;
+                    Object->hHmgr = hObj;
+
+                    /* remove the process id lock and make it global */
+                    (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, GDI_GLOBAL_PROCESS);
+
+                    /* we're done, successfully converted the object */
+                    return TRUE;
+                }
+                else
+                {
+                    GDIDBG_TRACELOOP(hObj, PrevThread, Thread);
+
+                    /* WTF?! The object is already locked by a different thread!
+                       Release the lock, wait a bit and try again!
+                       FIXME - we should give up after some time unless we want to wait forever! */
+                    (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+
+                    DelayExecution();
+                    goto LockHandle;
+                }
             }
-          }
-
-          /* remove the process id lock and make it global */
-          (void)InterlockedExchangePointer(&Entry->ProcessId, GDI_GLOBAL_PROCESS);
-
-          hObj = (HGDIOBJ)((ULONG)(hObj) | GDI_HANDLE_STOCK_MASK);
-          *phObj = hObj;
+            else
+            {
+                DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj);
+                DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType, Entry->Type, NewType, Entry->KernelData);
+            }
+        }
+        else if (PrevProcId == LockedProcessId)
+        {
+            GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
 
-          /* we're done, successfully converted the object */
-          return TRUE;
+            /* the object is currently locked, wait some time and try again.
+               FIXME - we shouldn't loop forever! Give up after some time! */
+            DelayExecution();
+            /* try again */
+            goto LockHandle;
         }
         else
         {
-#ifdef GDI_DEBUG
-          if(++Attempts > 20)
-          {
-            if(GdiHdr->lockfile != NULL)
-            {
-              DPRINT1("[%d]Locked %s:%i by 0x%x (we're 0x%x)\n", Attempts, GdiHdr->lockfile, GdiHdr->lockline, PrevThread, Thread);
-            }
-          }
-#endif
-          /* WTF?! The object is already locked by a different thread!
-             Release the lock, wait a bit and try again!
-             FIXME - we should give up after some time unless we want to wait forever! */
-          (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
-
-          DelayExecution();
-          goto LockHandle;
+            DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj);
         }
-      }
-      else
-      {
-        DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj);
-      }
-    }
-    else if(PrevProcId == LockedProcessId)
-    {
-#ifdef GDI_DEBUG
-    if(++Attempts > 20)
-    {
-      DPRINT1("[%d]Waiting on 0x%x\n", Attempts, hObj);
-    }
-#endif
-      /* the object is currently locked, wait some time and try again.
-         FIXME - we shouldn't loop forever! Give up after some time! */
-      DelayExecution();
-      /* try again */
-      goto LockHandle;
     }
-    else
-    {
-      DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj);
-    }
-  }
 
-  return FALSE;
+    return FALSE;
 }
 
-void INTERNAL_CALL
-GDIOBJ_SetOwnership(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
+BOOL INTERNAL_CALL
+GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
 {
-  PGDI_TABLE_ENTRY Entry;
-  HANDLE ProcessId, LockedProcessId, PrevProcId;
-  PETHREAD Thread;
-#ifdef GDI_DEBUG
-  ULONG Attempts = 0;
-#endif
-
-  DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0));
+    PGDI_TABLE_ENTRY Entry;
+    HANDLE ProcessId, LockedProcessId, PrevProcId;
+    PTHREADINFO Thread;
+    BOOL Ret = TRUE;
 
-  Thread = PsGetCurrentThread();
+    GDIDBG_INITLOOPTRACE();
 
-  if(!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
-  {
-    ProcessId = PsGetCurrentProcessId();
-    LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
+    DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0));
 
-    Entry = GDI_HANDLE_GET_ENTRY(HandleTable, ObjectHandle);
+    Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
 
-LockHandle:
-    /* lock the object, we must not convert stock objects, so don't check!!! */
-    PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, ProcessId, LockedProcessId);
-    if(PrevProcId == ProcessId)
+    if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
     {
-      PETHREAD PrevThread;
+        ProcessId = PsGetCurrentProcessId();
+        LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
 
-      if((Entry->Type & ~GDI_ENTRY_REUSE_MASK) != 0 && Entry->KernelData != NULL)
-      {
-        PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
+        Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
 
-        PrevThread = GdiHdr->LockingThread;
-        if(GdiHdr->Locks == 0 || PrevThread == Thread)
+LockHandle:
+        /* lock the object, we must not convert stock objects, so don't check!!! */
+        PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, ProcessId, LockedProcessId);
+        if (PrevProcId == ProcessId)
         {
-          PEPROCESS OldProcess;
-          PW32PROCESS W32Process;
-          NTSTATUS Status;
+            PTHREADINFO PrevThread;
 
-          /* dereference the process' object counter */
-          /* FIXME */
-          if((ULONG_PTR)PrevProcId & ~0x1)
-          {
-            Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
-            if(NT_SUCCESS(Status))
+            if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
             {
-              W32Process = (PW32PROCESS)OldProcess->Win32Process;
-              if(W32Process != NULL)
-              {
-                InterlockedDecrement(&W32Process->GDIObjects);
-              }
-              ObDereferenceObject(OldProcess);
+                POBJ Object = Entry->KernelData;
+
+                PrevThread = Object->Tid;
+                if (Object->cExclusiveLock == 0 || PrevThread == Thread)
+                {
+                    PEPROCESS OldProcess;
+                    PPROCESSINFO W32Process;
+                    NTSTATUS Status;
+
+                    if (NewOwner != NULL)
+                    {
+                        ProcessId = PsGetProcessId(NewOwner);
+                    }
+                    else
+                        ProcessId = 0;
+
+                    if((ULONG_PTR)ProcessId == ((ULONG_PTR)PrevProcId & ~0x1))
+                    {
+                        DPRINT("Setting same process than previous one, nothing to do\n");
+                        goto done;
+                    }
+
+                    /* dereference the process' object counter */
+                    /* FIXME */
+                    if ((ULONG_PTR)PrevProcId & ~0x1)
+                    {
+                        Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
+                        if (NT_SUCCESS(Status))
+                        {
+                            W32Process = (PPROCESSINFO)OldProcess->Win32Process;
+                            if (W32Process != NULL)
+                            {
+                                InterlockedDecrement(&W32Process->GDIHandleCount);
+                            }
+                            ObDereferenceObject(OldProcess);
+                        }
+                    }
+
+                    if (NewOwner != NULL)
+                    {
+                        /* Increase the new process' object counter */
+                        W32Process = (PPROCESSINFO)NewOwner->Win32Process;
+                        if (W32Process != NULL)
+                        {
+                            InterlockedIncrement(&W32Process->GDIHandleCount);
+                        }
+                    }
+
+                done:
+                    /* remove the process id lock and change it to the new process id */
+                    (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, ProcessId);
+
+                    /* we're done! */
+                    return Ret;
+                }
+                else
+                {
+                    GDIDBG_TRACELOOP(ObjectHandle, PrevThread, Thread);
+
+                    /* WTF?! The object is already locked by a different thread!
+                       Release the lock, wait a bit and try again! DO reset the pid lock
+                       so we make sure we don't access invalid memory in case the object is
+                       being deleted in the meantime (because we don't have aquired a reference
+                       at this point).
+                       FIXME - we should give up after some time unless we want to wait forever! */
+                    (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+
+                    DelayExecution();
+                    goto LockHandle;
+                }
             }
-          }
-
-          if(NewOwner != NULL)
-          {
-            ProcessId = PsGetProcessId(NewOwner);
-
-            /* Increase the new process' object counter */
-            W32Process = (PW32PROCESS)NewOwner->Win32Process;
-            if(W32Process != NULL)
+            else
             {
-              InterlockedIncrement(&W32Process->GDIObjects);
+                DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle);
+                DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry->Type, Entry->KernelData);
+                Ret = FALSE;
             }
-          }
-          else
-            ProcessId = 0;
-
-          /* remove the process id lock and change it to the new process id */
-          (void)InterlockedExchangePointer(&Entry->ProcessId, ProcessId);
+        }
+        else if (PrevProcId == LockedProcessId)
+        {
+            GDIDBG_TRACELOOP(ObjectHandle, PrevProcId, ProcessId);
 
-          /* we're done! */
-          return;
+            /* the object is currently locked, wait some time and try again.
+               FIXME - we shouldn't loop forever! Give up after some time! */
+            DelayExecution();
+            /* try again */
+            goto LockHandle;
+        }
+        else if (((ULONG_PTR)PrevProcId & ~0x1) == 0)
+        {
+            /* allow changing ownership of global objects */
+            ProcessId = NULL;
+            LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
+            goto LockHandle;
+        }
+        else if ((HANDLE)((ULONG_PTR)PrevProcId & ~0x1) != PsGetCurrentProcessId())
+        {
+            DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle, (ULONG_PTR)PrevProcId & ~0x1, PsGetCurrentProcessId());
+            Ret = FALSE;
         }
         else
         {
-#ifdef GDI_DEBUG
-          if(++Attempts > 20)
-          {
-            if(GdiHdr->lockfile != NULL)
-            {
-              DPRINT1("[%d]Locked from %s:%i by 0x%x (we're 0x%x)\n", Attempts, GdiHdr->lockfile, GdiHdr->lockline, PrevThread, Thread);
-            }
-          }
-#endif
-          /* WTF?! The object is already locked by a different thread!
-             Release the lock, wait a bit and try again! DO reset the pid lock
-             so we make sure we don't access invalid memory in case the object is
-             being deleted in the meantime (because we don't have aquired a reference
-             at this point).
-             FIXME - we should give up after some time unless we want to wait forever! */
-          (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
-
-          DelayExecution();
-          goto LockHandle;
+            DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle);
+            Ret = FALSE;
         }
-      }
-      else
-      {
-        DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle);
-      }
-    }
-    else if(PrevProcId == LockedProcessId)
-    {
-#ifdef GDI_DEBUG
-    if(++Attempts > 20)
-    {
-      DPRINT1("[%d]Waiting on 0x%x\n", Attempts, ObjectHandle);
-    }
-#endif
-      /* the object is currently locked, wait some time and try again.
-         FIXME - we shouldn't loop forever! Give up after some time! */
-      DelayExecution();
-      /* try again */
-      goto LockHandle;
-    }
-    else if(((ULONG_PTR)PrevProcId & ~0x1) == 0)
-    {
-      /* allow changing ownership of global objects */
-      ProcessId = NULL;
-      LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
-      goto LockHandle;
     }
-    else if((HANDLE)((ULONG_PTR)PrevProcId & ~0x1) != PsGetCurrentProcessId())
-    {
-      DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle, (ULONG_PTR)PrevProcId & ~0x1, PsGetCurrentProcessId());
-    }
-    else
-    {
-      DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle);
-    }
-  }
+    return Ret;
 }
 
-void INTERNAL_CALL
-GDIOBJ_CopyOwnership(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
+BOOL INTERNAL_CALL
+GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
 {
-  PGDI_TABLE_ENTRY FromEntry;
-  PETHREAD Thread;
-  HANDLE FromProcessId, FromLockedProcessId, FromPrevProcId;
-#ifdef GDI_DEBUG
-  ULONG Attempts = 0;
-#endif
+    PGDI_TABLE_ENTRY FromEntry;
+    PTHREADINFO Thread;
+    HANDLE FromProcessId, FromLockedProcessId, FromPrevProcId;
+    BOOL Ret = TRUE;
 
-  DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo);
+    GDIDBG_INITLOOPTRACE();
 
-  Thread = PsGetCurrentThread();
+    DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo);
 
-  if(!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo))
-  {
-    FromEntry = GDI_HANDLE_GET_ENTRY(HandleTable, CopyFrom);
+    Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
 
-    FromProcessId = (HANDLE)((ULONG_PTR)FromEntry->ProcessId & ~0x1);
-    FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
-
-LockHandleFrom:
-    /* lock the object, we must not convert stock objects, so don't check!!! */
-    FromPrevProcId = InterlockedCompareExchangePointer(&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
-    if(FromPrevProcId == FromProcessId)
+    if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo))
     {
-      PETHREAD PrevThread;
-      PGDIOBJHDR GdiHdr;
+        FromEntry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, CopyFrom);
 
-      if((FromEntry->Type & ~GDI_ENTRY_REUSE_MASK) != 0 && FromEntry->KernelData != NULL)
-      {
-        GdiHdr = GDIBdyToHdr(FromEntry->KernelData);
+        FromProcessId = (HANDLE)((ULONG_PTR)FromEntry->ProcessId & ~0x1);
+        FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
 
-        /* save the pointer to the calling thread so we know it was this thread
-           that locked the object */
-        PrevThread = GdiHdr->LockingThread;
-        if(GdiHdr->Locks == 0 || PrevThread == Thread)
+LockHandleFrom:
+        /* lock the object, we must not convert stock objects, so don't check!!! */
+        FromPrevProcId = InterlockedCompareExchangePointer((PVOID*)&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
+        if (FromPrevProcId == FromProcessId)
         {
-          /* now let's change the ownership of the target object */
+            PTHREADINFO PrevThread;
+            POBJ Object;
 
-          if(((ULONG_PTR)FromPrevProcId & ~0x1) != 0)
-          {
-            PEPROCESS ProcessTo;
-            /* FIXME */
-            if(NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1), &ProcessTo)))
+            if ((FromEntry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
             {
-              GDIOBJ_SetOwnership(HandleTable, CopyTo, ProcessTo);
-              ObDereferenceObject(ProcessTo);
+                Object = FromEntry->KernelData;
+
+                /* save the pointer to the calling thread so we know it was this thread
+                   that locked the object */
+                PrevThread = Object->Tid;
+                if (Object->cExclusiveLock == 0 || PrevThread == Thread)
+                {
+                    /* now let's change the ownership of the target object */
+
+                    if (((ULONG_PTR)FromPrevProcId & ~0x1) != 0)
+                    {
+                        PEPROCESS ProcessTo;
+                        /* FIXME */
+                        if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1), &ProcessTo)))
+                        {
+                            GDIOBJ_SetOwnership(CopyTo, ProcessTo);
+                            ObDereferenceObject(ProcessTo);
+                        }
+                    }
+                    else
+                    {
+                        /* mark the object as global */
+                        GDIOBJ_SetOwnership(CopyTo, NULL);
+                    }
+
+                    (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
+                }
+                else
+                {
+                    GDIDBG_TRACELOOP(CopyFrom, PrevThread, Thread);
+
+                    /* WTF?! The object is already locked by a different thread!
+                       Release the lock, wait a bit and try again! DO reset the pid lock
+                       so we make sure we don't access invalid memory in case the object is
+                       being deleted in the meantime (because we don't have aquired a reference
+                       at this point).
+                       FIXME - we should give up after some time unless we want to wait forever! */
+                    (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
+
+                    DelayExecution();
+                    goto LockHandleFrom;
+                }
             }
-          }
-          else
-          {
-            /* mark the object as global */
-            GDIOBJ_SetOwnership(HandleTable, CopyTo, NULL);
-          }
+            else
+            {
+                DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom);
+                Ret = FALSE;
+            }
+        }
+        else if (FromPrevProcId == FromLockedProcessId)
+        {
+            GDIDBG_TRACELOOP(CopyFrom, FromPrevProcId, FromProcessId);
 
-          (void)InterlockedExchangePointer(&FromEntry->ProcessId, FromPrevProcId);
+            /* the object is currently locked, wait some time and try again.
+               FIXME - we shouldn't loop forever! Give up after some time! */
+            DelayExecution();
+            /* try again */
+            goto LockHandleFrom;
+        }
+        else if ((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1) != PsGetCurrentProcessId())
+        {
+            /* FIXME - should we really allow copying ownership from objects that we don't even own? */
+            DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom, (ULONG_PTR)FromPrevProcId & ~0x1, PsGetCurrentProcessId());
+            FromProcessId = (HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1);
+            FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
+            goto LockHandleFrom;
         }
         else
         {
-#ifdef GDI_DEBUG
-          if(++Attempts > 20)
-          {
-            if(GdiHdr->lockfile != NULL)
-            {
-              DPRINT1("[%d]Locked from %s:%i by 0x%x (we're 0x%x)\n", Attempts, GdiHdr->lockfile, GdiHdr->lockline, PrevThread, Thread);
-            }
-          }
-#endif
-          /* WTF?! The object is already locked by a different thread!
-             Release the lock, wait a bit and try again! DO reset the pid lock
-             so we make sure we don't access invalid memory in case the object is
-             being deleted in the meantime (because we don't have aquired a reference
-             at this point).
-             FIXME - we should give up after some time unless we want to wait forever! */
-          (void)InterlockedExchangePointer(&FromEntry->ProcessId, FromPrevProcId);
-
-          DelayExecution();
-          goto LockHandleFrom;
+            DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom);
+            Ret = FALSE;
         }
-      }
-      else
-      {
-        DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom);
-      }
-    }
-    else if(FromPrevProcId == FromLockedProcessId)
-    {
-#ifdef GDI_DEBUG
-    if(++Attempts > 20)
-    {
-      DPRINT1("[%d]Waiting on 0x%x\n", Attempts, CopyFrom);
-    }
-#endif
-      /* the object is currently locked, wait some time and try again.
-         FIXME - we shouldn't loop forever! Give up after some time! */
-      DelayExecution();
-      /* try again */
-      goto LockHandleFrom;
     }
-    else if((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1) != PsGetCurrentProcessId())
-    {
-      /* FIXME - should we really allow copying ownership from objects that we don't even own? */
-      DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom, (ULONG_PTR)FromPrevProcId & ~0x1, PsGetCurrentProcessId());
-      FromProcessId = (HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1);
-      FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
-      goto LockHandleFrom;
-    }
-    else
-    {
-      DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom);
-    }
-  }
+    return Ret;
 }
 
 PVOID INTERNAL_CALL
@@ -1479,15 +1649,206 @@ GDI_MapHandleTable(PSECTION_OBJECT SectionObject, PEPROCESS Process)
     return MappedView;
 }
 
+/* Locks 2 or 3 objects at a time */
+VOID
+INTERNAL_CALL
+GDIOBJ_LockMultipleObjs(ULONG ulCount,
+                        IN HGDIOBJ* ahObj,
+                        OUT PGDIOBJ* apObj)
+{
+    UINT auiIndices[3] = {0,1,2};
+    UINT i, tmp ;
+    BOOL bUnsorted = TRUE;
+
+    /* First is greatest */
+    while(bUnsorted)
+    {
+        bUnsorted = FALSE;
+        for(i=1; i<ulCount; i++)
+        {
+            if((ULONG_PTR)ahObj[auiIndices[i-1]] < (ULONG_PTR)ahObj[auiIndices[i]])
+            {
+                tmp = auiIndices[i-1];
+                auiIndices[i-1] = auiIndices[i];
+                auiIndices[i] = tmp;
+                bUnsorted = TRUE;
+            }
+        }
+    }
+
+    for(i=0;i<ulCount;i++)
+        apObj[auiIndices[i]] = GDIOBJ_LockObj(ahObj[auiIndices[i]], GDI_OBJECT_TYPE_DONTCARE);
+}
+
+
+/** PUBLIC FUNCTIONS **********************************************************/
+
+BOOL
+FASTCALL
+IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
+{
+  INT Index;
+  PGDI_TABLE_ENTRY Entry;
+/*
+  System Regions:
+     These regions do not use attribute sections and when allocated, use gdiobj
+     level functions.
+ */
+  // FIXME! HAX!!! Remove this once we get everything right!
+  Index = GDI_HANDLE_GET_INDEX(hRgn);
+  Entry = &GdiHandleTable->Entries[Index];
+  if (Entry->UserData) FreeObjectAttr(Entry->UserData);
+  Entry->UserData = NULL;
+  //
+  if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
+  {
+     return GDIOBJ_SetOwnership(hRgn, NULL);
+  }
+  if (OwnerMask == GDI_OBJ_HMGR_POWNED)
+  {
+     return GDIOBJ_SetOwnership((HGDIOBJ) hRgn, PsGetCurrentProcess() );
+  }
+  return FALSE;
+}
+
+BOOL
+FASTCALL
+IntGdiSetBrushOwner(PBRUSH pbr, DWORD OwnerMask)
+{
+  HBRUSH hBR;
+  PEPROCESS Owner = NULL;
+  PGDI_TABLE_ENTRY pEntry = NULL;
+
+  if (!pbr) return FALSE;
+
+  hBR = pbr->BaseObject.hHmgr;
+
+  if (!hBR || (GDI_HANDLE_GET_TYPE(hBR) != GDI_OBJECT_TYPE_BRUSH))
+     return FALSE;
+  else
+  {
+     INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hBR);
+     pEntry = &GdiHandleTable->Entries[Index];
+  }
+
+  if (pbr->flAttrs & GDIBRUSH_IS_GLOBAL)
+  {
+     GDIOBJ_ShareUnlockObjByPtr((POBJ)pbr);
+     return TRUE;
+  }
+
+  if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
+  {
+     // Set this Brush to inaccessible mode and to an Owner of NONE.
+//     if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
+
+     if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, Owner))
+        return FALSE;
+
+     // Deny user access to User Data.
+     pEntry->UserData = NULL; // This hBR is inaccessible!
+  }
+
+  if (OwnerMask == GDI_OBJ_HMGR_POWNED)
+  {
+     if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, PsGetCurrentProcess() ))
+        return FALSE;
+
+     // Allow user access to User Data.
+     pEntry->UserData = pbr->pBrushAttr;
+  }
+  return TRUE;
+}
+
+BOOL
+FASTCALL
+IntGdiSetDCOwnerEx( HDC hDC, DWORD OwnerMask, BOOL NoSetBrush)
+{
+  PDC pDC;
+  BOOL Ret = FALSE;
+
+  if (!hDC || (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_DC)) return FALSE;
+
+  if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
+  {
+     pDC = DC_LockDc ( hDC );
+     MmCopyFromCaller(&pDC->dcattr, pDC->pdcattr, sizeof(DC_ATTR));
+     DC_vFreeDcAttr(pDC);
+     DC_UnlockDc( pDC );
+
+     if (!DC_SetOwnership( hDC, NULL )) // This hDC is inaccessible!
+        return Ret;
+  }
+
+  if (OwnerMask == GDI_OBJ_HMGR_POWNED)
+  {
+     pDC = DC_LockDc ( hDC );
+     ASSERT(pDC->pdcattr == &pDC->dcattr);
+     DC_UnlockDc( pDC );
+
+     if (!DC_SetOwnership( hDC, PsGetCurrentProcess() )) return Ret;
+
+     DC_AllocateDcAttr( hDC );      // Allocate new dcattr
+
+     DCU_SynchDcAttrtoUser( hDC );  // Copy data from dc to dcattr
+  }
+
+  if ((OwnerMask != GDI_OBJ_HMGR_NONE) && !NoSetBrush)
+  {
+     pDC = DC_LockDc ( hDC );
+     if (IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrFill, OwnerMask))
+         IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrLine, OwnerMask);
+     DC_UnlockDc( pDC );
+  }
+  return TRUE;
+}
+
+INT
+FASTCALL
+GreGetObjectOwner(HGDIOBJ Handle, GDIOBJTYPE ObjType)
+{
+  INT Ret = GDI_OBJ_HMGR_RESTRICTED;
+
+  if ( GDI_HANDLE_GET_INDEX(Handle) < GDI_HANDLE_COUNT )
+  {
+     PGDI_TABLE_ENTRY pEntry = &GdiHandleTable->Entries[GDI_HANDLE_GET_INDEX(Handle)];
+
+     if (pEntry->ObjectType == ObjType)
+     {
+        if (pEntry->FullUnique == (GDI_HANDLE_GET_UPPER(Handle) >> GDI_ENTRY_UPPER_SHIFT))
+           Ret = pEntry->ProcessId & ~1;
+     }
+  }
+  return Ret;
+}
+
 W32KAPI
 HANDLE
 APIENTRY
 NtGdiCreateClientObj(
     IN ULONG ulType
-    )
+)
 {
-  UNIMPLEMENTED;
-  return 0;
+    POBJ pObject;
+    HANDLE handle;
+
+    /* Mask out everything that would change the type in a wrong manner */
+    ulType &= (GDI_HANDLE_TYPE_MASK & ~GDI_HANDLE_BASETYPE_MASK);
+
+    /* Allocate a new object */
+    pObject = GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ | ulType);
+    if (!pObject)
+    {
+        return NULL;
+    }
+
+    /* get the handle */
+    handle = pObject->hHmgr;
+
+    /* Unlock it */
+    GDIOBJ_UnlockObjByPtr(pObject);
+
+    return handle;
 }
 
 W32KAPI
@@ -1495,10 +1856,126 @@ BOOL
 APIENTRY
 NtGdiDeleteClientObj(
     IN HANDLE h
-    )
+)
+{
+    /* We first need to get the real type from the handle */
+    ULONG type = GDI_HANDLE_GET_TYPE(h);
+
+    /* Check if it's really a CLIENTOBJ */
+    if ((type & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE)
+    {
+        /* FIXME: SetLastError? */
+        return FALSE;
+    }
+    return GDIOBJ_FreeObjByHandle(h, type);
+}
+
+INT
+FASTCALL
+IntGdiGetObject(IN HANDLE Handle,
+                IN INT cbCount,
+                IN LPVOID lpBuffer)
 {
-  UNIMPLEMENTED;
-  return 0;
+  PVOID pGdiObject;
+  INT Result = 0;
+  DWORD dwObjectType;
+
+  pGdiObject = GDIOBJ_LockObj(Handle, GDI_OBJECT_TYPE_DONTCARE);
+  if (!pGdiObject)
+    {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      return 0;
+    }
+
+  dwObjectType = GDIOBJ_GetObjectType(Handle);
+  switch (dwObjectType)
+    {
+      case GDI_OBJECT_TYPE_PEN:
+      case GDI_OBJECT_TYPE_EXTPEN:
+        Result = PEN_GetObject((PBRUSH) pGdiObject, cbCount, (PLOGPEN) lpBuffer); // IntGdiCreatePenIndirect
+        break;
+
+      case GDI_OBJECT_TYPE_BRUSH:
+        Result = BRUSH_GetObject((PBRUSH ) pGdiObject, cbCount, (LPLOGBRUSH)lpBuffer);
+        break;
+
+      case GDI_OBJECT_TYPE_BITMAP:
+        Result = BITMAP_GetObject((SURFACE *) pGdiObject, cbCount, lpBuffer);
+        break;
+      case GDI_OBJECT_TYPE_FONT:
+        Result = FontGetObject((PTEXTOBJ) pGdiObject, cbCount, lpBuffer);
+#if 0
+        // Fix the LOGFONT structure for the stock fonts
+        if (FIRST_STOCK_HANDLE <= Handle && Handle <= LAST_STOCK_HANDLE)
+          {
+            FixStockFontSizeW(Handle, cbCount, lpBuffer);
+          }
+#endif
+        break;
+
+      case GDI_OBJECT_TYPE_PALETTE:
+        Result = PALETTE_GetObject((PPALETTE) pGdiObject, cbCount, lpBuffer);
+        break;
+
+      default:
+        DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType);
+        break;
+    }
+
+  GDIOBJ_UnlockObjByPtr(pGdiObject);
+
+  return Result;
+}
+
+
+
+W32KAPI
+INT
+APIENTRY
+NtGdiExtGetObjectW(IN HANDLE hGdiObj,
+                   IN INT cbCount,
+                   OUT LPVOID lpBuffer)
+{
+    INT iRetCount = 0;
+    INT cbCopyCount;
+    union
+    {
+        BITMAP bitmap;
+        DIBSECTION dibsection;
+        LOGPEN logpen;
+        LOGBRUSH logbrush;
+        LOGFONTW logfontw;
+        EXTLOGFONTW extlogfontw;
+        ENUMLOGFONTEXDVW enumlogfontexdvw;
+    } Object;
+
+    // Normalize to the largest supported object size
+    cbCount = min((UINT)cbCount, sizeof(Object));
+
+    // Now do the actual call
+    iRetCount = IntGdiGetObject(hGdiObj, cbCount, lpBuffer ? &Object : NULL);
+    cbCopyCount = min((UINT)cbCount, (UINT)iRetCount);
+
+    // Make sure we have a buffer and a copy size
+    if ((cbCopyCount) && (lpBuffer))
+    {
+        // Enter SEH for buffer transfer
+        _SEH2_TRY
+        {
+            // Probe the buffer and copy it
+            ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD));
+            RtlCopyMemory(lpBuffer, &Object, cbCopyCount);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            // Clear the return value.
+            // Do *NOT* set last error here!
+            iRetCount = 0;
+        }
+        _SEH2_END;
+    }
+    // Return the count
+    return iRetCount;
 }
 
 /* EOF */