[YAROTOWS] Reintegrate the branch. For a brighter future.
[reactos.git] / reactos / subsystems / win32 / win32k / objects / gdiobj.c
index b54a954..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, ULONG);
-
-#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)                                   \
   (&(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,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,       RGNDATA_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 */
-  {0, 0,                     TAG_ICMLCS,       NULL},             /* 09 ICMLCS, unused */
+  {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, 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 */
@@ -92,22 +70,82 @@ OBJ_TYPE_INFO ObjTypeInfo[] =
   {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_TTFD,         NULL},             /* 18 VTFD, 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, 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;
 
-#define DelayExecution() \
-  DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
-  KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
+/** INTERNAL FUNCTIONS ********************************************************/
+
+// 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.
@@ -183,168 +221,13 @@ GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject)
     return HandleTable;
 }
 
-static __inline PPAGED_LOOKASIDE_LIST
-FindLookasideList(ULONG TypeIndex)
-{
-    return GdiHandleTable->LookasideLists + TypeIndex;
-}
-
-static __inline BOOL
-RunCleanupCallback(PGDIOBJ pObj, ULONG TypeIndex)
-{
-    return ((GDICLEANUPPROC)ObjTypeInfo[TypeIndex].CleanupProc)(pObj);
-}
-
-static __inline ULONG
-GetObjectSize(ULONG TypeIndex)
-{
-    return ObjTypeInfo[TypeIndex].ulBodySize;
-}
-
-#ifdef GDI_DEBUG
-
-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];
-
-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");
-}
-
-ULONG
-CaptureStackBackTace(PVOID* pFrames, ULONG nFramesToCapture)
-{
-    ULONG nFrameCount;
-
-    memset(pFrames, 0x00, (nFramesToCapture + 1) * sizeof(PVOID));
-
-    nFrameCount = RtlCaptureStackBackTrace(1, nFramesToCapture, pFrames, NULL);
-
-    if (nFrameCount < nFramesToCapture)
-    {
-        nFrameCount += RtlWalkFrameChain(pFrames + nFrameCount, nFramesToCapture - nFrameCount, 1);
-    }
-
-    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)
-
-#else
-
-#define GDIDBG_TRACECALLER()
-#define GDIDBG_TRACEALLOCATOR(index)
-#define GDIDBG_TRACELOCKER(index)
-#define GDIDBG_CAPTUREALLOCATOR(index)
-#define GDIDBG_CAPTURELOCKER(index)
-#define GDIDBG_DUMPHANDLETABLE()
-
-#endif /* GDI_DEBUG */
-
-
 static void FASTCALL
 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))
     {
@@ -366,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,
@@ -419,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);
 }
@@ -444,136 +357,174 @@ GDIOBJ_ValidateHandle(HGDIOBJ hObj, ULONG ObjectType)
     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
-GDIOBJ_AllocObj(ULONG ObjectType)
+POBJ INTERNAL_CALL
+GDIOBJ_AllocObjWithHandle(ULONG ObjectType)
 {
-    PW32PROCESS W32Process;
+    PPROCESSINFO W32Process;
     POBJ  newObject = NULL;
-    PPAGED_LOOKASIDE_LIST LookasideList = NULL;
     HANDLE CurrentProcessId, LockedProcessId;
-    ULONG TypeIndex;
-#ifdef GDI_DEBUG
-    ULONG Attempts = 0;
-#endif
+    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);
 
     TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(ObjectType);
-    if (ObjTypeInfo[TypeIndex].bUseLookaside)
-    {
-        LookasideList = FindLookasideList(TypeIndex);
-        if (LookasideList != NULL)
-        {
-            newObject = ExAllocateFromPagedLookasideList(LookasideList);
-        }
-    }
-    else
+
+    newObject = GDIOBJ_AllocObj(TypeIndex);
+    if (!newObject)
     {
-        newObject = ExAllocatePoolWithTag(PagedPool,
-                                          ObjTypeInfo[TypeIndex].ulBodySize,
-                                          ObjTypeInfo[TypeIndex].Tag);
+        DPRINT1("Not enough memory to allocate gdi object!\n");
+        return NULL;
     }
-    if (newObject != NULL)
-    {
-        UINT Index;
-        PGDI_TABLE_ENTRY Entry;
-        LONG TypeInfo;
 
-        CurrentProcessId = PsGetCurrentProcessId();
-        LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1);
+    CurrentProcessId = PsGetCurrentProcessId();
+    LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1);
 
-        RtlZeroMemory(newObject, 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);
+    /* 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);
 
-        Index = InterlockedPopFreeEntry();
-        if (Index != 0)
-        {
-            HANDLE PrevProcId;
+    Index = InterlockedPopFreeEntry();
+    if (Index != 0)
+    {
+        HANDLE PrevProcId;
 
-            Entry = &GdiHandleTable->Entries[Index];
+        Entry = &GdiHandleTable->Entries[Index];
 
 LockHandle:
-            PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&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;
 
-                Entry->KernelData = newObject;
+            Entry->KernelData = newObject;
 
-                /* 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;
 
-                /* unlock the entry */
-                (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId);
+            /* Create a handle */
+            Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT));
 
-                GDIDBG_CAPTUREALLOCATOR(Index);
+            /* Initialize BaseObject fields */
+            newObject->hHmgr = Handle;
+            newObject->ulShareCount = 0;
+            newObject->cExclusiveLock = 1;
+            newObject->Tid = Thread;
 
-                if (W32Process != NULL)
-                {
-                    _InterlockedIncrement(&W32Process->GDIObjects);
-                }
-                Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT));
+            AllocTypeDataDump(TypeInfo);
 
-                DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, newObject);
-                return Handle;
-            }
-            else
+            /* unlock the entry */
+            (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId);
+
+            GDIDBG_CAPTUREALLOCATOR(Index);
+
+            if (W32Process != NULL)
             {
-#ifdef GDI_DEBUG
-                if (++Attempts > 20)
-                {
-                    DPRINT1("[%d]Waiting on handle in index 0x%x\n", Attempts, Index);
-                }
-#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;
+                InterlockedIncrement(&W32Process->GDIHandleCount);
             }
-        }
 
-        if (ObjTypeInfo[TypeIndex].bUseLookaside)
-        {
-            ExFreeToPagedLookasideList(LookasideList, newObject);
+            DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, newObject);
+            return newObject;
         }
         else
         {
-            ExFreePool(newObject);
+            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;
         }
-        DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
-        GDIDBG_DUMPHANDLETABLE();
+    }
+
+    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)
+    {
+        PPAGED_LOOKASIDE_LIST LookasideList;
+
+        LookasideList = GdiHandleTable->LookasideLists + BaseType;
+        ExFreeToPagedLookasideList(LookasideList, pObject);
     }
     else
     {
-        DPRINT1("Not enough memory to allocate gdi object!\n");
+        ExFreePool(pObject);
     }
-    return NULL;
 }
 
 /*!
@@ -585,18 +536,18 @@ 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
-GDIOBJ_FreeObj(HGDIOBJ hObj, DWORD ExpectedType)
+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
+
+    GDIDBG_INITLOOPTRACE();
 
     DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj);
 
@@ -632,7 +583,7 @@ GDIOBJ_FreeObj(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) &&
@@ -643,69 +594,87 @@ 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));
 
+                Object->hHmgr = NULL;
+
                 if (W32Process != NULL)
                 {
-                    _InterlockedDecrement(&W32Process->GDIObjects);
+                    InterlockedDecrement(&W32Process->GDIHandleCount);
                 }
 
                 /* call the cleanup routine. */
                 TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(HandleType);
-                Ret = RunCleanupCallback(Object, TypeIndex);
+                Ret = ObjTypeInfo[TypeIndex].CleanupProc(Object);
+
+                DeAllocTypeDataDump(HandleType);
 
                 /* Now it's time to free the memory */
-                if (ObjTypeInfo[TypeIndex].bUseLookaside)
+                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))
                 {
-                    LookasideList = FindLookasideList(TypeIndex);
-                    if (LookasideList != NULL)
+                    PPROCESSINFO W32Process = (PPROCESSINFO)OldProcess->Win32Process;
+                    if (W32Process != NULL)
                     {
-                        ExFreeToPagedLookasideList(LookasideList, Object);
+                        InterlockedDecrement(&W32Process->GDIHandleCount);
                     }
+                    ObDereferenceObject(OldProcess);
                 }
-                else
-                {
-                    ExFreePool(Object);
-                }
-
-                return Ret;
+                (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL);
+                /* 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_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj));
-                ASSERT(FALSE);
+                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
         {
             LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj");
-            (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+            (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
         }
     }
     else if (PrevProcId == LockedProcessId)
     {
-#ifdef GDI_DEBUG
-        if (++Attempts > 20)
-        {
-            DPRINT1("[%d]Waiting on 0x%x\n", Attempts, hObj);
-        }
-#endif
+        GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
+
         /* the object is currently locked, wait some time and try again.
            FIXME - we shouldn't loop forever! Give up after some time! */
         DelayExecution();
@@ -716,17 +685,21 @@ 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));
+            GDIDBG_TRACEALLOCATOR(hObj);
         }
     }
 
@@ -740,7 +713,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 +723,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 +793,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_FreeObj(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 +844,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_FreeObj(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;
 }
@@ -856,12 +963,18 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
     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)
+    if (HandleIndex >= GDI_HANDLE_COUNT )
         return NULL;
 
     Entry = &GdiHandleTable->Entries[HandleIndex];
@@ -871,10 +984,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;
     }
 
@@ -886,7 +1000,7 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
     {
         DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj, ProcessId, HandleProcessId);
         GDIDBG_TRACECALLER();
-        GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj));
+        GDIDBG_TRACEALLOCATOR(hObj);
         return NULL;
     }
 
@@ -907,7 +1021,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 +1035,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 +1049,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 +1067,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;
         }
@@ -962,6 +1076,7 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
             /*
              * The handle is currently locked, wait some time and try again.
              */
+            GDIDBG_TRACELOOP(hObj, PrevProcId, NULL);
 
             DelayExecution();
             continue;
@@ -994,6 +1109,10 @@ GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
     POBJ Object = NULL;
     ULONG_PTR HandleType, HandleUpper;
 
+    /* Check for dummy call */
+    if(hObj == NULL)
+        return NULL ;
+
     HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
     HandleType = GDI_HANDLE_GET_TYPE(hObj);
     HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
@@ -1040,7 +1159,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 +1175,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 +1196,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 +1216,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 +1231,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,18 +1249,17 @@ GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
      */
     PGDI_TABLE_ENTRY Entry;
     HANDLE ProcessId, LockedProcessId, PrevProcId;
-    PW32THREAD Thread;
+    PTHREADINFO Thread;
     HGDIOBJ hObj;
-#ifdef GDI_DEBUG
-    ULONG Attempts = 0;
-#endif
+
+    GDIDBG_INITLOOPTRACE();
 
     ASSERT(phObj);
     hObj = *phObj;
 
     DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj);
 
-    Thread = PsGetCurrentThreadWin32Thread();
+    Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
 
     if (!GDI_HANDLE_IS_STOCKOBJ(hObj))
     {
@@ -1176,7 +1270,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;
@@ -1196,10 +1290,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.
@@ -1215,43 +1309,40 @@ 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;
                 }
                 else
                 {
-#ifdef GDI_DEBUG
-                    if (++Attempts > 20)
-                    {
-                        DPRINT1("[%d]Locked by 0x%x (we're 0x%x)\n", Attempts, PrevThread, Thread);
-                    }
-#endif
+                    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);
+                    (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
 
                     DelayExecution();
                     goto LockHandle;
@@ -1265,12 +1356,8 @@ LockHandle:
         }
         else if (PrevProcId == LockedProcessId)
         {
-#ifdef GDI_DEBUG
-            if (++Attempts > 20)
-            {
-                DPRINT1("[%d]Waiting on 0x%x\n", Attempts, hObj);
-            }
-#endif
+            GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
+
             /* the object is currently locked, wait some time and try again.
                FIXME - we shouldn't loop forever! Give up after some time! */
             DelayExecution();
@@ -1286,19 +1373,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;
-#ifdef GDI_DEBUG
-    ULONG Attempts = 0;
-#endif
+    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))
     {
@@ -1309,12 +1396,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;
 
@@ -1322,9 +1409,22 @@ LockHandle:
                 if (Object->cExclusiveLock == 0 || PrevThread == Thread)
                 {
                     PEPROCESS OldProcess;
-                    PW32PROCESS W32Process;
+                    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)
@@ -1332,10 +1432,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);
                         }
@@ -1343,39 +1443,32 @@ LockHandle:
 
                     if (NewOwner != NULL)
                     {
-                        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;
 
+                done:
                     /* 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
                 {
-#ifdef GDI_DEBUG
-                    if (++Attempts > 20)
-                    {
-                        DPRINT1("[%d]Locked by 0x%x (we're 0x%x)\n", Attempts, PrevThread, Thread);
-                    }
-#endif
+                    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);
+                    (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
 
                     DelayExecution();
                     goto LockHandle;
@@ -1385,16 +1478,13 @@ 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)
         {
-#ifdef GDI_DEBUG
-            if (++Attempts > 20)
-            {
-                DPRINT1("[%d]Waiting on 0x%x\n", Attempts, ObjectHandle);
-            }
-#endif
+            GDIDBG_TRACELOOP(ObjectHandle, PrevProcId, ProcessId);
+
             /* the object is currently locked, wait some time and try again.
                FIXME - we shouldn't loop forever! Give up after some time! */
             DelayExecution();
@@ -1411,27 +1501,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;
-#ifdef GDI_DEBUG
-    ULONG Attempts = 0;
-#endif
+    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))
     {
@@ -1442,13 +1535,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;
 
@@ -1475,23 +1568,19 @@ LockHandleFrom:
                         GDIOBJ_SetOwnership(CopyTo, NULL);
                     }
 
-                    (void)_InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
+                    (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
                 }
                 else
                 {
-#ifdef GDI_DEBUG
-                    if (++Attempts > 20)
-                    {
-                        DPRINT1("[%d]Locked by 0x%x (we're 0x%x)\n", Attempts, PrevThread, Thread);
-                    }
-#endif
+                    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);
+                    (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
 
                     DelayExecution();
                     goto LockHandleFrom;
@@ -1500,16 +1589,13 @@ LockHandleFrom:
             else
             {
                 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom);
+                Ret = FALSE;
             }
         }
         else if (FromPrevProcId == FromLockedProcessId)
         {
-#ifdef GDI_DEBUG
-            if (++Attempts > 20)
-            {
-                DPRINT1("[%d]Waiting on 0x%x\n", Attempts, CopyFrom);
-            }
-#endif
+            GDIDBG_TRACELOOP(CopyFrom, FromPrevProcId, FromProcessId);
+
             /* the object is currently locked, wait some time and try again.
                FIXME - we shouldn't loop forever! Give up after some time! */
             DelayExecution();
@@ -1527,8 +1613,10 @@ LockHandleFrom:
         else
         {
             DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom);
+            Ret = FALSE;
         }
     }
+    return Ret;
 }
 
 PVOID INTERNAL_CALL
@@ -1561,6 +1649,179 @@ 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
@@ -1568,21 +1829,25 @@ NtGdiCreateClientObj(
     IN ULONG ulType
 )
 {
-// ATM we use DC object for KernelData. I think it should be at a minimum GDIOBJEMPTYHDR.
-// The UserData is set in user mode, so it is always NULL.
-//
-    INT Index;
-    PGDI_TABLE_ENTRY Entry;
-    HANDLE handle = GDIOBJ_AllocObj(GDI_OBJECT_TYPE_CLIOBJ);
-// Need to change handle type based on ulType.
-    Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)handle);
-    Entry = &GdiHandleTable->Entries[Index];
-// mask out lower half and set the type by ulType.
-    Entry->Type &= GDI_HANDLE_UPPER_MASK;
-    Entry->Type |= ulType >> GDI_ENTRY_UPPER_SHIFT;
-// mask out handle type than set it by ulType.
-    handle = (HANDLE)(((ULONG_PTR)(handle)) & (GDI_HANDLE_REUSE_MASK|GDI_HANDLE_STOCK_MASK|0x0ffff));
-    handle = (HANDLE)(((ULONG_PTR)(handle)) | ulType);
+    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;
 }
 
@@ -1593,7 +1858,124 @@ NtGdiDeleteClientObj(
     IN HANDLE h
 )
 {
-    return GDIOBJ_FreeObj(h, GDI_OBJECT_TYPE_CLIOBJ);
+    /* 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)
+{
+  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 */