- Turn off debug print outs.
[reactos.git] / reactos / subsystems / win32 / win32k / objects / gdiobj.c
index 3aa4ff0..1c0dc8e 100644 (file)
@@ -8,21 +8,12 @@
 
 /** INCLUDES ******************************************************************/
 
-#include <w32k.h>
+//#define GDI_DEBUG
 
+#include <w32k.h>
 #define NDEBUG
 #include <debug.h>
 
-/* FIXME include right header for KeRosDumpStackFrames */
-VOID NTAPI KeRosDumpStackFrames(PULONG, ULONG);
-
-//#define GDI_DEBUG
-
-#ifdef GDI_DEBUG
-BOOLEAN STDCALL KiRosPrintAddress(PVOID Address);
-NTSYSAPI ULONG NTAPI RtlWalkFrameChain(OUT PVOID *Callers, IN ULONG Count, IN ULONG Flags);
-#endif
-
 #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)                                   \
@@ -31,11 +22,16 @@ NTSYSAPI ULONG NTAPI RtlWalkFrameChain(OUT PVOID *Callers, IN ULONG Count, IN UL
 /* apparently the first 10 entries are never used in windows as they are empty */
 #define RESERVE_ENTRIES_COUNT 10
 
+#define BASE_OBJTYPE_COUNT 32
+
 #define DelayExecution() \
   DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
   KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
 
-static BOOL INTERNAL_CALL GDI_CleanupDummy(PVOID ObjectBody);
+#include "gdidbg.c"
+
+/* static */ /* FIXME: -fno-unit-at-a-time breaks this */
+BOOL INTERNAL_CALL GDI_CleanupDummy(PVOID ObjectBody);
 
 /** GLOBALS *******************************************************************/
 
@@ -48,25 +44,25 @@ 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),            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(BITMAPOBJ),     TAG_SURFACE,      BITMAP_Cleanup},   /* 05 SURFACE */
-  {0, sizeof(DC),            TAG_CLIENTOBJ,    GDI_CleanupDummy}, /* 06 CLIENTOBJ: METADC,... FIXME: don't use DC struct */
-  {0, 0,                     TAG_PATH,         NULL},             /* 07 PATH, unused */
-  {1, sizeof(PALGDI),        TAG_PALETTE,      PALETTE_Cleanup},  /* 08 PAL */
-  {1, sizeof(COLORSPACE),    TAG_ICMLCS,       GDI_CleanupDummy}, /* 09 ICMLCS, unused */
+  {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, 0,                     TAG_ICMCXF,       NULL},             /* 0e ICMCXF, unused */
+  {0, sizeof(GDICLRXFORM),   TAG_ICMCXF,       GDI_CleanupDummy}, /* 0e ICMCXF, */
   {0, 0,                     TAG_SPRITE,       NULL},             /* 0f SPRITE, unused */
-  {1, sizeof(GDIBRUSHOBJ),   TAG_BRUSH,        BRUSH_Cleanup},    /* 10 BRUSH, PEN, EXTPEN */
+  {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 */
@@ -78,169 +74,74 @@ OBJ_TYPE_INFO ObjTypeInfo[] =
   {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, 0,                     TAG_DRVOBJ,       NULL},             /* 1c DRVOBJ, 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;
 
-/** DEBUGGING *****************************************************************/
-
-#ifdef GDI_DEBUG
+/** INTERNAL FUNCTIONS ********************************************************/
 
-static int leak_reported = 0;
-#define GDI_STACK_LEVELS 12
-static ULONG GDIHandleAllocator[GDI_HANDLE_COUNT][GDI_STACK_LEVELS+1];
-static ULONG GDIHandleLocker[GDI_HANDLE_COUNT][GDI_STACK_LEVELS+1];
-struct DbgOpenGDIHandle
-{
-    ULONG idx;
-    int count;
-};
-#define H 1024
-static struct DbgOpenGDIHandle h[H];
+// Audit Functions
+int tDC = 0;
+int tBRUSH = 0;
+int tBITMAP = 0;
+int tFONT = 0;
+int tRGN = 0;
 
-void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable)
+VOID
+AllocTypeDataDump(INT TypeInfo)
 {
-    int i, n = 0, j, k, J;
-
-    if (leak_reported)
+    switch( TypeInfo & GDI_HANDLE_TYPE_MASK )
     {
-        DPRINT1("gdi handle abusers already reported!\n");
-        return;
+       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;
     }
-
-    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");
 }
 
-ULONG
-CaptureStackBackTace(PVOID* pFrames, ULONG nFramesToCapture)
+VOID
+DeAllocTypeDataDump(INT TypeInfo)
 {
-    ULONG nFrameCount;
-
-    memset(pFrames, 0x00, (nFramesToCapture + 1) * sizeof(PVOID));
-
-    nFrameCount = RtlCaptureStackBackTrace(1, nFramesToCapture, pFrames, NULL);
-
-    if (nFrameCount < nFramesToCapture)
+    switch( TypeInfo & GDI_HANDLE_TYPE_MASK )
     {
-        nFrameCount += RtlWalkFrameChain(pFrames + nFrameCount, nFramesToCapture - nFrameCount, 1);
+       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;
     }
-
-    return nFrameCount;
 }
 
-#define GDIDBG_TRACECALLER() \
-  DPRINT1("-> called from:\n"); \
-  KeRosDumpStackFrames(NULL, 20);
-#define GDIDBG_TRACEALLOCATOR(index) \
-  DPRINT1("-> allocated from:\n"); \
-  KeRosDumpStackFrames(GDIHandleAllocator[index], GDI_STACK_LEVELS);
-#define GDIDBG_TRACELOCKER(index) \
-  DPRINT1("-> locked from:\n"); \
-  KeRosDumpStackFrames(GDIHandleLocker[index], GDI_STACK_LEVELS);
-#define GDIDBG_CAPTUREALLOCATOR(index) \
-  CaptureStackBackTace((PVOID*)GDIHandleAllocator[index], GDI_STACK_LEVELS);
-#define GDIDBG_CAPTURELOCKER(index) \
-  CaptureStackBackTace((PVOID*)GDIHandleLocker[index], GDI_STACK_LEVELS);
-#define GDIDBG_DUMPHANDLETABLE() \
-  IntDumpHandleTable(GdiHandleTable)
-#define GDIDBG_INITLOOPTRACE() \
-  ULONG Attempts = 0;
-#define GDIDBG_TRACELOOP(Handle, PrevThread, Thread) \
-  if ((++Attempts % 20) == 0) \
-  { \
-    DPRINT1("[%d] Handle 0x%p Locked by 0x%x (we're 0x%x)\n", Attempts, Handle, PrevThread, Thread); \
-  }
-
-#else
-
-#define GDIDBG_TRACECALLER()
-#define GDIDBG_TRACEALLOCATOR(index)
-#define GDIDBG_TRACELOCKER(index)
-#define GDIDBG_CAPTUREALLOCATOR(index)
-#define GDIDBG_CAPTURELOCKER(index)
-#define GDIDBG_DUMPHANDLETABLE()
-#define GDIDBG_INITLOOPTRACE()
-#define GDIDBG_TRACELOOP(Handle, PrevThread, Thread)
-
-#endif /* GDI_DEBUG */
-
-
-/** INTERNAL FUNCTIONS ********************************************************/
-
 /*
  * Dummy GDI Cleanup Callback
  */
-static BOOL INTERNAL_CALL
+/* static */ /* FIXME: -fno-unit-at-a-time breaks this */
+BOOL INTERNAL_CALL
 GDI_CleanupDummy(PVOID ObjectBody)
 {
     return TRUE;
@@ -326,6 +227,7 @@ LockErrorDebugOutput(HGDIOBJ hObj, PGDI_TABLE_ENTRY Entry, LPSTR Function)
     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))
     {
@@ -347,38 +249,66 @@ LockErrorDebugOutput(HGDIOBJ hObj, PGDI_TABLE_ENTRY Entry, LPSTR Function)
 
 ULONG
 FASTCALL
-InterlockedPopFreeEntry()
+InterlockedPopFreeEntry(VOID)
 {
-    ULONG idxFirstFree, idxNextFree, idxPrev;
-    PGDI_TABLE_ENTRY pFreeEntry;
+    ULONG idxFirst, idxNext, idxPrev;
+    PGDI_TABLE_ENTRY pEntry;
+    DWORD PrevProcId;
 
     DPRINT("Enter InterLockedPopFreeEntry\n");
 
-    do
+    while (TRUE)
     {
-        idxFirstFree = GdiHandleTable->FirstFree;
-        if (idxFirstFree)
-        {
-            pFreeEntry = GdiHandleTable->Entries + idxFirstFree;
-            ASSERT(((ULONG)pFreeEntry->KernelData & ~GDI_HANDLE_INDEX_MASK) == 0);
-            idxNextFree = (ULONG)pFreeEntry->KernelData;
-            idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree, idxNextFree, idxFirstFree);
-        }
-        else
+        idxFirst = GdiHandleTable->FirstFree;
+
+        if (!idxFirst)
         {
-            idxFirstFree = GdiHandleTable->FirstUnused;
-            idxNextFree = idxFirstFree + 1;
-            if (idxNextFree >= GDI_HANDLE_COUNT)
+            /* 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;
             }
-            idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstUnused, idxNextFree, idxFirstFree);
+
+            /* 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;
         }
     }
-    while (idxPrev != idxFirstFree);
 
-    return idxFirstFree;
+    return idxFirst;
 }
 
 /* Pushes an entry of the handle table to the free list,
@@ -400,9 +330,11 @@ InterlockedPushFreeEntry(ULONG idxToFree)
     do
     {
         idxFirstFree = GdiHandleTable->FirstFree;
-        pFreeEntry->KernelData = (PVOID)idxFirstFree;
+        pFreeEntry->KernelData = (PVOID)(ULONG_PTR)idxFirstFree;
 
-        idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree, idxToFree, idxFirstFree);
+        idxPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree,
+                                             idxToFree,
+                                             idxFirstFree);
     }
     while (idxPrev != idxFirstFree);
 }
@@ -466,18 +398,26 @@ GDIOBJ_AllocObj(UCHAR BaseType)
 POBJ INTERNAL_CALL
 GDIOBJ_AllocObjWithHandle(ULONG ObjectType)
 {
-    PW32PROCESS W32Process;
+    PPROCESSINFO W32Process;
     POBJ  newObject = NULL;
     HANDLE CurrentProcessId, LockedProcessId;
     UCHAR TypeIndex;
+    UINT Index;
+    PGDI_TABLE_ENTRY Entry;
+    LONG TypeInfo;
 
     GDIDBG_INITLOOPTRACE();
 
     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)
+    if (W32Process && W32Process->GDIHandleCount >= 0x2710)
+    {
+        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;
+    }
 
     ASSERT(ObjectType != GDI_OBJECT_TYPE_DONTCARE);
 
@@ -490,10 +430,6 @@ GDIOBJ_AllocObjWithHandle(ULONG ObjectType)
         return NULL;
     }
 
-    UINT Index;
-    PGDI_TABLE_ENTRY Entry;
-    LONG TypeInfo;
-
     CurrentProcessId = PsGetCurrentProcessId();
     LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1);
 
@@ -512,10 +448,10 @@ GDIOBJ_AllocObjWithHandle(ULONG ObjectType)
         Entry = &GdiHandleTable->Entries[Index];
 
 LockHandle:
-        PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, 0);
+        PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, 0);
         if (PrevProcId == NULL)
         {
-            PW32THREAD Thread = PsGetCurrentThreadWin32Thread();
+            PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
             HGDIOBJ Handle;
 
             Entry->KernelData = newObject;
@@ -536,14 +472,16 @@ LockHandle:
             newObject->cExclusiveLock = 1;
             newObject->Tid = Thread;
 
+            AllocTypeDataDump(TypeInfo);
+
             /* unlock the entry */
-            (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId);
+            (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId);
 
             GDIDBG_CAPTUREALLOCATOR(Index);
 
             if (W32Process != NULL)
             {
-                _InterlockedIncrement(&W32Process->GDIObjects);
+                InterlockedIncrement(&W32Process->GDIHandleCount);
             }
 
             DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, newObject);
@@ -598,6 +536,8 @@ GDIOBJ_FreeObj(POBJ pObject, UCHAR BaseType)
  * \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
 GDIOBJ_FreeObjByHandle(HGDIOBJ hObj, DWORD ExpectedType)
@@ -643,7 +583,7 @@ GDIOBJ_FreeObjByHandle(HGDIOBJ hObj, DWORD ExpectedType)
 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((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
+    PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
     if (PrevProcId == ProcessId)
     {
         if ( (Entry->KernelData != NULL) &&
@@ -654,16 +594,18 @@ LockHandle:
 
             Object = Entry->KernelData;
 
-            if (Object->cExclusiveLock == 0)
+            if ((Object->cExclusiveLock == 0 ||
+                Object->Tid == (PTHREADINFO)PsGetCurrentThreadWin32Thread()) &&
+                 Object->ulShareCount == 0)
             {
                 BOOL Ret;
-                PW32PROCESS W32Process = PsGetCurrentProcessWin32Process();
+                PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process();
 
                 /* 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((PVOID*)&Entry->ProcessId, NULL);
+                (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL);
 
                 /* push this entry to the free list */
                 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable, Entry));
@@ -672,34 +614,50 @@ LockHandle:
 
                 if (W32Process != NULL)
                 {
-                    _InterlockedDecrement(&W32Process->GDIObjects);
+                    InterlockedDecrement(&W32Process->GDIHandleCount);
                 }
 
                 /* 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)
+            {
+                Object->BaseFlags |= BASEFLAG_READY_TO_DIE;
+                DPRINT("Object %p, ulShareCount = %d\n", Object->hHmgr, Object->ulShareCount);
+                //GDIDBG_TRACECALLER();
+                //GDIDBG_TRACESHARELOCKER(GDI_HANDLE_GET_INDEX(hObj));
+                (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+                /* Don't wait on shared locks */
+                return FALSE;
+            }
             else
             {
                 /*
-                 * The object is currently locked, so freeing is forbidden!
+                 * The object is currently locked by another thread, so freeing is forbidden!
                  */
                 DPRINT1("Object->cExclusiveLock = %d\n", Object->cExclusiveLock);
                 GDIDBG_TRACECALLER();
                 GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj));
+                (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
                 /* do not assert here for it will call again from dxg.sys it being call twice */
-                //ASSERT(FALSE);
+
+                DelayExecution();
+                goto LockHandle;
             }
         }
         else
         {
             LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj");
-            (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+            (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
         }
     }
     else if (PrevProcId == LockedProcessId)
@@ -716,15 +674,19 @@ LockHandle:
     {
         if (!Silent)
         {
-            if (((ULONG_PTR)PrevProcId & ~0x1) == 0)
+            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);
-                DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry->Type, Entry->KernelData, Entry->ProcessId);
             }
             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(GDI_HANDLE_GET_INDEX(hObj));
         }
@@ -740,7 +702,7 @@ 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_REUSE_MASK) != 0 && Entry->KernelData != NULL)
+    if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
         return FALSE;
     else
     {
@@ -750,6 +712,69 @@ IsObjectDead(HGDIOBJ hObject)
 }
 
 
+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;
+  }
+
+  Lock = InterlockedCompareExchangePointer( (PVOID*)&GdiHandleCache->ulLock,
+                                             NtCurrentTeb(),
+                                             NULL );
+  if (Lock) return FALSE;
+
+  _SEH2_TRY
+  {
+     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;
+
+  (void)InterlockedExchangePointer((PVOID*)&GdiHandleCache->ulLock, Lock);
+  return Ret;
+}
+
 /*!
  * Delete GDI object
  * \param      hObject object handle
@@ -757,13 +782,49 @@ IsObjectDead(HGDIOBJ hObject)
 */
 BOOL
 FASTCALL
-NtGdiDeleteObject(HGDIOBJ hObject)
+GreDeleteObject(HGDIOBJ hObject)
 {
+    INT Index;
+    PGDI_TABLE_ENTRY Entry;
+    DWORD dwObjectType;
+    PVOID pAttr = NULL;
+
     DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
     if (!IsObjectDead(hObject))
     {
-        return NULL != hObject
-               ? GDIOBJ_FreeObjByHandle(hObject, GDI_OBJECT_TYPE_DONTCARE) : FALSE;
+       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
     {
@@ -772,67 +833,102 @@ NtGdiDeleteObject(HGDIOBJ hObject)
     }
 }
 
-/*!
- * 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(struct _EPROCESS *Process)
+VOID
+FASTCALL
+IntDeleteHandlesForProcess(struct _EPROCESS *Process, ULONG ObjectType)
 {
     PGDI_TABLE_ENTRY Entry, End;
-    PEPROCESS CurrentProcess;
-    PW32PROCESS W32Process;
-    HANDLE ProcId;
     ULONG Index = RESERVE_ENTRIES_COUNT;
+    HANDLE ProcId;
+    PPROCESSINFO W32Process;
 
-    DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId);
-    CurrentProcess = PsGetCurrentProcess();
-    if (CurrentProcess != Process)
-    {
-        KeAttachProcess(&Process->Pcb);
-    }
-    W32Process = (PW32PROCESS)Process->Win32Process;
+    W32Process = (PPROCESSINFO)Process->Win32Process;
     ASSERT(W32Process);
 
-    if (W32Process->GDIObjects > 0)
+    if (W32Process->GDIHandleCount > 0)
     {
-        /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
-                   we should delete it directly here! */
-        ProcId = Process->UniqueProcessId;
+       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++)
+             Entry != End;
+             Entry++, Index++)
         {
             /* ignore the lock bit */
-            if ( (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId &&
-                 (Entry->Type & ~GDI_ENTRY_REUSE_MASK) != 0 )
+            if ( (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId)
             {
-                HGDIOBJ ObjectHandle;
+                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));
+                    /* 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) &&
-                        W32Process->GDIObjects == 0)
-                {
-                    /* there are no more gdi handles for this process, bail */
-                    break;
+                    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(struct _EPROCESS *Process)
+{
+    PEPROCESS CurrentProcess;
+    PPROCESSINFO W32Process;
+
+    DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId);
+    CurrentProcess = PsGetCurrentProcess();
+    if (CurrentProcess != Process)
+    {
+        KeAttachProcess(&Process->Pcb);
+    }
+
+    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);
 
     if (CurrentProcess != Process)
     {
         KeDetachProcess();
     }
 
+#ifdef GDI_DEBUG
+       GdiDbgHTIntegrityCheck();
+#endif
+
     DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);
+    if (W32Process->GDIHandleCount > 0)
+    {
+        DPRINT1("Leaking %d handles!\n", W32Process->GDIHandleCount);
+    }
 
     return TRUE;
 }
@@ -871,10 +967,11 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
           HandleType != ExpectedType) ||
          HandleType == 0 )
     {
-        DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
+        DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
                 hObj, HandleType, ExpectedType);
         GDIDBG_TRACECALLER();
-        GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj));
+        GDIDBG_TRACEALLOCATOR(hObj);
+        GDIDBG_TRACEDELETER(hObj);
         return NULL;
     }
 
@@ -907,7 +1004,7 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
     {
         /* Lock the handle table entry. */
         LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
-        PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
+        PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
                                                         LockedProcessId,
                                                         HandleProcessId);
 
@@ -921,7 +1018,7 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
             if ( (Entry->KernelData != NULL) &&
                  ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
             {
-                PW32THREAD Thread = PsGetCurrentThreadWin32Thread();
+                PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
                 Object = Entry->KernelData;
 
                 if (Object->cExclusiveLock == 0)
@@ -935,12 +1032,12 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
                     if (Object->Tid != Thread)
                     {
                         /* Unlock the handle table entry. */
-                        (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+                        (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
 
                         DelayExecution();
                         continue;
                     }
-                    _InterlockedIncrement((PLONG)&Object->cExclusiveLock);
+                    InterlockedIncrement((PLONG)&Object->cExclusiveLock);
                 }
             }
             else
@@ -953,7 +1050,7 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
             }
 
             /* Unlock the handle table entry. */
-            (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+            (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
 
             break;
         }
@@ -1040,7 +1137,7 @@ GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
     {
         /* Lock the handle table entry. */
         LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
-        PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
+        PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
                                                         LockedProcessId,
                                                         HandleProcessId);
 
@@ -1056,14 +1153,15 @@ GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
             {
                 Object = (POBJ)Entry->KernelData;
 
-#ifdef GDI_DEBUG
-                if (_InterlockedIncrement((PLONG)&Object->ulShareCount) == 1)
+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*)GDIHandleLocker[HandleIndex], NULL);
+                    RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleShareLocker[HandleIndex], NULL);
                 }
 #else
-                _InterlockedIncrement((PLONG)&Object->ulShareCount);
+                InterlockedIncrement((PLONG)&Object->ulShareCount);
 #endif
             }
             else
@@ -1076,7 +1174,7 @@ GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
             }
 
             /* Unlock the handle table entry. */
-            (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+            (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
 
             break;
         }
@@ -1096,31 +1194,6 @@ GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
     return Object;
 }
 
-
-/*!
- * 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.
-
- * \param Object       Object pointer (as returned by GDIOBJ_LockObj).
- */
-VOID INTERNAL_CALL
-GDIOBJ_UnlockObjByPtr(POBJ Object)
-{
-    if (_InterlockedDecrement((PLONG)&Object->cExclusiveLock) < 0)
-    {
-        DPRINT1("Trying to unlock non-existant object\n");
-    }
-}
-
-VOID INTERNAL_CALL
-GDIOBJ_ShareUnlockObjByPtr(POBJ Object)
-{
-    if (_InterlockedDecrement((PLONG)&Object->ulShareCount) < 0)
-    {
-        DPRINT1("Trying to unlock non-existant object\n");
-    }
-}
-
 BOOL INTERNAL_CALL
 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle)
 {
@@ -1136,7 +1209,7 @@ GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle)
 
         Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
         Ret = Entry->KernelData != NULL &&
-              (Entry->Type & ~GDI_ENTRY_REUSE_MASK) != 0 &&
+              (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
               (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcessId;
 
         return Ret;
@@ -1154,7 +1227,7 @@ GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
      */
     PGDI_TABLE_ENTRY Entry;
     HANDLE ProcessId, LockedProcessId, PrevProcId;
-    PW32THREAD Thread;
+    PTHREADINFO Thread;
     HGDIOBJ hObj;
 
     GDIDBG_INITLOOPTRACE();
@@ -1164,7 +1237,7 @@ GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
 
     DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj);
 
-    Thread = PsGetCurrentThreadWin32Thread();
+    Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
 
     if (!GDI_HANDLE_IS_STOCKOBJ(hObj))
     {
@@ -1175,7 +1248,7 @@ GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
 
 LockHandle:
         /* lock the object, we must not convert stock objects, so don't check!!! */
-        PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
+        PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
         if (PrevProcId == ProcessId)
         {
             LONG NewType, PrevType, OldType;
@@ -1195,10 +1268,10 @@ LockHandle:
             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);
+            PrevType = InterlockedCompareExchange(&Entry->Type, NewType, OldType);
             if (PrevType == OldType && Entry->KernelData != NULL)
             {
-                PW32THREAD PrevThread;
+                PTHREADINFO PrevThread;
                 POBJ Object;
 
                 /* We successfully set the stock object flag.
@@ -1214,27 +1287,28 @@ LockHandle:
                     if (PrevProcId != GDI_GLOBAL_PROCESS)
                     {
                         PEPROCESS OldProcess;
-                        PW32PROCESS W32Process;
+                        PPROCESSINFO W32Process;
                         NTSTATUS Status;
 
                         /* FIXME */
                         Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
                         if (NT_SUCCESS(Status))
                         {
-                            W32Process = (PW32PROCESS)OldProcess->Win32Process;
+                            W32Process = (PPROCESSINFO)OldProcess->Win32Process;
                             if (W32Process != NULL)
                             {
-                                _InterlockedDecrement(&W32Process->GDIObjects);
+                                InterlockedDecrement(&W32Process->GDIHandleCount);
                             }
                             ObDereferenceObject(OldProcess);
                         }
                     }
 
-                    /* remove the process id lock and make it global */
-                    (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, GDI_GLOBAL_PROCESS);
-
                     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;
@@ -1246,7 +1320,7 @@ LockHandle:
                     /* 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);
+                    (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
 
                     DelayExecution();
                     goto LockHandle;
@@ -1277,18 +1351,19 @@ LockHandle:
     return FALSE;
 }
 
-void INTERNAL_CALL
+BOOL INTERNAL_CALL
 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
 {
     PGDI_TABLE_ENTRY Entry;
     HANDLE ProcessId, LockedProcessId, PrevProcId;
-    PW32THREAD Thread;
+    PTHREADINFO Thread;
+    BOOL Ret = TRUE;
 
     GDIDBG_INITLOOPTRACE();
 
     DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0));
 
-    Thread = PsGetCurrentThreadWin32Thread();
+    Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
 
     if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
     {
@@ -1299,12 +1374,12 @@ GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
 
 LockHandle:
         /* lock the object, we must not convert stock objects, so don't check!!! */
-        PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, ProcessId, LockedProcessId);
+        PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, ProcessId, LockedProcessId);
         if (PrevProcId == ProcessId)
         {
-            PW32THREAD PrevThread;
+            PTHREADINFO PrevThread;
 
-            if ((Entry->Type & ~GDI_ENTRY_REUSE_MASK) != 0 && Entry->KernelData != NULL)
+            if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
             {
                 POBJ Object = Entry->KernelData;
 
@@ -1312,7 +1387,7 @@ LockHandle:
                 if (Object->cExclusiveLock == 0 || PrevThread == Thread)
                 {
                     PEPROCESS OldProcess;
-                    PW32PROCESS W32Process;
+                    PPROCESSINFO W32Process;
                     NTSTATUS Status;
 
                     /* dereference the process' object counter */
@@ -1322,10 +1397,10 @@ LockHandle:
                         Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
                         if (NT_SUCCESS(Status))
                         {
-                            W32Process = (PW32PROCESS)OldProcess->Win32Process;
+                            W32Process = (PPROCESSINFO)OldProcess->Win32Process;
                             if (W32Process != NULL)
                             {
-                                _InterlockedDecrement(&W32Process->GDIObjects);
+                                InterlockedDecrement(&W32Process->GDIHandleCount);
                             }
                             ObDereferenceObject(OldProcess);
                         }
@@ -1336,20 +1411,20 @@ LockHandle:
                         ProcessId = PsGetProcessId(NewOwner);
 
                         /* Increase the new process' object counter */
-                        W32Process = (PW32PROCESS)NewOwner->Win32Process;
+                        W32Process = (PPROCESSINFO)NewOwner->Win32Process;
                         if (W32Process != NULL)
                         {
-                            _InterlockedIncrement(&W32Process->GDIObjects);
+                            InterlockedIncrement(&W32Process->GDIHandleCount);
                         }
                     }
                     else
                         ProcessId = 0;
 
                     /* remove the process id lock and change it to the new process id */
-                    (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, ProcessId);
+                    (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, ProcessId);
 
                     /* we're done! */
-                    return;
+                    return Ret;
                 }
                 else
                 {
@@ -1361,7 +1436,7 @@ LockHandle:
                        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);
+                    (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
 
                     DelayExecution();
                     goto LockHandle;
@@ -1371,6 +1446,7 @@ LockHandle:
             {
                 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 if (PrevProcId == LockedProcessId)
@@ -1393,26 +1469,30 @@ 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
         {
             DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle);
+            Ret = FALSE;
         }
     }
+    return Ret;
 }
 
-void INTERNAL_CALL
+BOOL INTERNAL_CALL
 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
 {
     PGDI_TABLE_ENTRY FromEntry;
-    PW32THREAD Thread;
+    PTHREADINFO Thread;
     HANDLE FromProcessId, FromLockedProcessId, FromPrevProcId;
+    BOOL Ret = TRUE;
 
     GDIDBG_INITLOOPTRACE();
 
     DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo);
 
-    Thread = PsGetCurrentThreadWin32Thread();
+    Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
 
     if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo))
     {
@@ -1423,13 +1503,13 @@ GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
 
 LockHandleFrom:
         /* lock the object, we must not convert stock objects, so don't check!!! */
-        FromPrevProcId = _InterlockedCompareExchangePointer((PVOID*)&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
+        FromPrevProcId = InterlockedCompareExchangePointer((PVOID*)&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
         if (FromPrevProcId == FromProcessId)
         {
-            PW32THREAD PrevThread;
+            PTHREADINFO PrevThread;
             POBJ Object;
 
-            if ((FromEntry->Type & ~GDI_ENTRY_REUSE_MASK) != 0 && FromEntry->KernelData != NULL)
+            if ((FromEntry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
             {
                 Object = FromEntry->KernelData;
 
@@ -1456,7 +1536,7 @@ LockHandleFrom:
                         GDIOBJ_SetOwnership(CopyTo, NULL);
                     }
 
-                    (void)_InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
+                    (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
                 }
                 else
                 {
@@ -1468,7 +1548,7 @@ LockHandleFrom:
                        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);
+                    (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
 
                     DelayExecution();
                     goto LockHandleFrom;
@@ -1477,6 +1557,7 @@ LockHandleFrom:
             else
             {
                 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom);
+                Ret = FALSE;
             }
         }
         else if (FromPrevProcId == FromLockedProcessId)
@@ -1500,8 +1581,10 @@ LockHandleFrom:
         else
         {
             DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom);
+            Ret = FALSE;
         }
     }
+    return Ret;
 }
 
 PVOID INTERNAL_CALL
@@ -1536,6 +1619,146 @@ GDI_MapHandleTable(PSECTION_OBJECT SectionObject, PEPROCESS Process)
 
 /** 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_UnlockDc( pDC );
+
+     DC_FreeDcAttr( hDC );         // Free the dcattr!
+
+     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
@@ -1543,11 +1766,6 @@ NtGdiCreateClientObj(
     IN ULONG ulType
 )
 {
-// ATM we use DC object for KernelData. This is wrong.
-// The real type consists of BASEOBJECT and a pointer.
-// The UserData is set in user mode, so it is always NULL.
-// HANDLE should be HGDIOBJ
-//
     POBJ pObject;
     HANDLE handle;
 
@@ -1611,15 +1829,15 @@ IntGdiGetObject(IN HANDLE Handle,
     {
       case GDI_OBJECT_TYPE_PEN:
       case GDI_OBJECT_TYPE_EXTPEN:
-        Result = PEN_GetObject((PGDIBRUSHOBJ) pGdiObject, cbCount, (PLOGPEN) lpBuffer); // IntGdiCreatePenIndirect
+        Result = PEN_GetObject((PBRUSH) pGdiObject, cbCount, (PLOGPEN) lpBuffer); // IntGdiCreatePenIndirect
         break;
 
       case GDI_OBJECT_TYPE_BRUSH:
-        Result = BRUSH_GetObject((PGDIBRUSHOBJ ) pGdiObject, cbCount, (LPLOGBRUSH)lpBuffer);
+        Result = BRUSH_GetObject((PBRUSH ) pGdiObject, cbCount, (LPLOGBRUSH)lpBuffer);
         break;
 
       case GDI_OBJECT_TYPE_BITMAP:
-        Result = BITMAP_GetObject((BITMAPOBJ *) pGdiObject, cbCount, lpBuffer);
+        Result = BITMAP_GetObject((SURFACE *) pGdiObject, cbCount, lpBuffer);
         break;
       case GDI_OBJECT_TYPE_FONT:
         Result = FontGetObject((PTEXTOBJ) pGdiObject, cbCount, lpBuffer);
@@ -1633,7 +1851,7 @@ IntGdiGetObject(IN HANDLE Handle,
         break;
 
       case GDI_OBJECT_TYPE_PALETTE:
-        Result = PALETTE_GetObject((PPALGDI) pGdiObject, cbCount, lpBuffer);
+        Result = PALETTE_GetObject((PPALETTE) pGdiObject, cbCount, lpBuffer);
         break;
 
       default:
@@ -1647,13 +1865,6 @@ IntGdiGetObject(IN HANDLE Handle,
 }
 
 
-BOOL
-FASTCALL
-IntGdiSetDCOwnerEx( HGDIOBJ hObject, DWORD OwnerMask, BOOL NoSetBrush)
-{
-   UNIMPLEMENTED;
-   return FALSE;
-}
 
 W32KAPI
 INT
@@ -1686,19 +1897,19 @@ NtGdiExtGetObjectW(IN HANDLE hGdiObj,
     if ((cbCopyCount) && (lpBuffer))
     {
         // Enter SEH for buffer transfer
-        _SEH_TRY
+        _SEH2_TRY
         {
             // Probe the buffer and copy it
             ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD));
             RtlCopyMemory(lpBuffer, &Object, cbCopyCount);
         }
-        _SEH_HANDLE
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
             // Clear the return value.
             // Do *NOT* set last error here!
             iRetCount = 0;
         }
-        _SEH_END;
+        _SEH2_END;
     }
     // Return the count
     return iRetCount;