[Win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / gdiobj.c
index ec9efde..6bbca8c 100644 (file)
@@ -8,29 +8,17 @@
 
 /** INCLUDES ******************************************************************/
 
-//#define GDI_DEBUG
-
-#include <w32k.h>
+#include <win32k.h>
 #define NDEBUG
 #include <debug.h>
 
-#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))])
-
-/* 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)
 
-#include "gdidbg.c"
-
-/* static */ /* FIXME: -fno-unit-at-a-time breaks this */
+static
 BOOL INTERNAL_CALL GDI_CleanupDummy(PVOID ObjectBody);
 
 /** GLOBALS *******************************************************************/
@@ -81,13 +69,68 @@ OBJ_TYPE_INFO ObjTypeInfo[BASE_OBJTYPE_COUNT] =
 };
 
 static LARGE_INTEGER ShortDelay;
+PGDI_HANDLE_TABLE GdiHandleTable = NULL;
+PSECTION_OBJECT GdiTableSection = NULL;
 
 /** 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 */ /* FIXME: -fno-unit-at-a-time breaks this */
+static
 BOOL INTERNAL_CALL
 GDI_CleanupDummy(PVOID ObjectBody)
 {
@@ -98,7 +141,9 @@ GDI_CleanupDummy(PVOID ObjectBody)
  * Allocate GDI object table.
  * \param      Size - number of entries in the object table.
 */
-PGDI_HANDLE_TABLE INTERNAL_CALL
+INIT_FUNCTION
+PGDI_HANDLE_TABLE
+INTERNAL_CALL
 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject)
 {
     PGDI_HANDLE_TABLE HandleTable = NULL;
@@ -168,6 +213,23 @@ GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject)
     return HandleTable;
 }
 
+INIT_FUNCTION
+NTSTATUS
+NTAPI
+InitGdiHandleTable()
+{
+    /* Create the GDI handle table */
+    GdiHandleTable = GDIOBJ_iAllocHandleTable(&GdiTableSection);
+    if (GdiHandleTable == NULL)
+    {
+        DPRINT1("Failed to initialize the GDI handle table.\n");
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
 static void FASTCALL
 LockErrorDebugOutput(HGDIOBJ hObj, PGDI_TABLE_ENTRY Entry, LPSTR Function)
 {
@@ -198,64 +260,51 @@ ULONG
 FASTCALL
 InterlockedPopFreeEntry(VOID)
 {
-    ULONG idxFirst, idxNext, idxPrev;
+    ULONG iFirst, iNext, iPrev;
     PGDI_TABLE_ENTRY pEntry;
-    DWORD PrevProcId;
 
     DPRINT("Enter InterLockedPopFreeEntry\n");
 
-    while (TRUE)
+    do
     {
-        idxFirst = GdiHandleTable->FirstFree;
+        /* Get the index and sequence number of the first free entry */
+        iFirst = GdiHandleTable->FirstFree;
 
-        if (!idxFirst)
+        /* Check if we have a free entry */
+        if (!(iFirst & GDI_HANDLE_INDEX_MASK))
         {
             /* Increment FirstUnused and get the new index */
-            idxFirst = InterlockedIncrement((LONG*)&GdiHandleTable->FirstUnused) - 1;
+            iFirst = InterlockedIncrement((LONG*)&GdiHandleTable->FirstUnused) - 1;
 
-            /* Check if we have entries left */
-            if (idxFirst >= GDI_HANDLE_COUNT)
+            /* Check if we have unused entries left */
+            if (iFirst >= GDI_HANDLE_COUNT)
             {
                 DPRINT1("No more gdi handles left!\n");
                 return 0;
             }
 
             /* Return the old index */
-            return idxFirst;
+            return iFirst;
         }
 
         /* 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;
-        }
+        pEntry = GdiHandleTable->Entries + (iFirst & GDI_HANDLE_INDEX_MASK);
 
-        /* Sanity check: is entry really free? */
-        ASSERT(((ULONG_PTR)pEntry->KernelData & ~GDI_HANDLE_INDEX_MASK) == 0);
+        /* Create a new value with an increased sequence number */
+        iNext = (USHORT)(ULONG_PTR)pEntry->KernelData;
+        iNext |= (iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000;
 
         /* 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;
-        }
+        iPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree,
+                                           iNext,
+                                           iFirst);
     }
+    while (iPrev != iFirst);
+
+    /* Sanity check: is entry really free? */
+    ASSERT(((ULONG_PTR)pEntry->KernelData & ~GDI_HANDLE_INDEX_MASK) == 0);
 
-    return idxFirst;
+    return iFirst & GDI_HANDLE_INDEX_MASK;
 }
 
 /* Pushes an entry of the handle table to the free list,
@@ -264,7 +313,7 @@ VOID
 FASTCALL
 InterlockedPushFreeEntry(ULONG idxToFree)
 {
-    ULONG idxFirstFree, idxPrev;
+    ULONG iToFree, iFirst, iPrev;
     PGDI_TABLE_ENTRY pFreeEntry;
 
     DPRINT("Enter InterlockedPushFreeEntry\n");
@@ -272,18 +321,26 @@ InterlockedPushFreeEntry(ULONG idxToFree)
     pFreeEntry = GdiHandleTable->Entries + idxToFree;
     ASSERT((pFreeEntry->Type & GDI_ENTRY_BASETYPE_MASK) == 0);
     ASSERT(pFreeEntry->ProcessId == 0);
-    pFreeEntry->UserData = NULL;
+    pFreeEntry->UserData = NULL; // FIXME
+    ASSERT(pFreeEntry->UserData == NULL);
 
     do
     {
-        idxFirstFree = GdiHandleTable->FirstFree;
-        pFreeEntry->KernelData = (PVOID)(ULONG_PTR)idxFirstFree;
+        /* Get the current first free index and sequence number */
+        iFirst = GdiHandleTable->FirstFree;
+
+        /* Set the KernelData member to the index of the first free entry */
+        pFreeEntry->KernelData = UlongToPtr(iFirst & GDI_HANDLE_INDEX_MASK);
 
-        idxPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree,
-                                             idxToFree,
-                                             idxFirstFree);
+        /* Combine new index and increased sequence number in iToFree */
+        iToFree = idxToFree | ((iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000);
+
+        /* Try to atomically update the first free entry */
+        iPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree,
+                                           iToFree,
+                                           iFirst);
     }
-    while (idxPrev != idxFirstFree);
+    while (iPrev != iFirst);
 }
 
 
@@ -361,6 +418,7 @@ GDIOBJ_AllocObjWithHandle(ULONG ObjectType)
     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;
     }
@@ -417,6 +475,11 @@ LockHandle:
             newObject->ulShareCount = 0;
             newObject->cExclusiveLock = 1;
             newObject->Tid = Thread;
+#if DBG
+            if (Thread) Thread->cExclusiveLocks++;
+#endif
+
+            AllocTypeDataDump(TypeInfo);
 
             /* unlock the entry */
             (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId);
@@ -535,11 +598,11 @@ LockHandle:
              ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == (HandleUpper & GDI_ENTRY_BASETYPE_MASK)) )
         {
             POBJ Object;
+            PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
 
             Object = Entry->KernelData;
 
-            if ((Object->cExclusiveLock == 0 ||
-                Object->Tid == (PTHREADINFO)PsGetCurrentThreadWin32Thread()) &&
+            if ((Object->cExclusiveLock == 0 || Object->Tid == Thread) &&
                  Object->ulShareCount == 0)
             {
                 BOOL Ret;
@@ -555,6 +618,18 @@ LockHandle:
                 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable, Entry));
 
                 Object->hHmgr = NULL;
+#if DBG
+                if (Thread)
+                {
+                    if (Thread->cExclusiveLocks < Object->cExclusiveLock)
+                    {
+                        DPRINT1("cExclusiveLocks = %ld, object: %ld\n",
+                                Thread->cExclusiveLocks, Object->cExclusiveLock);
+                        ASSERT(FALSE);
+                    }
+                    Thread->cExclusiveLocks -= Object->cExclusiveLock;
+                }
+#endif
 
                 if (W32Process != NULL)
                 {
@@ -565,6 +640,8 @@ LockHandle:
                 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);
 
@@ -573,11 +650,22 @@ LockHandle:
             }
             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);
-                //GDIDBG_TRACECALLER();
-                //GDIDBG_TRACESHARELOCKER(GDI_HANDLE_GET_INDEX(hObj));
-                (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+                /* Set NULL owner. Do the work here to avoid race conditions */
+                Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
+                if (NT_SUCCESS(Status))
+                {
+                    PPROCESSINFO W32Process = (PPROCESSINFO)OldProcess->Win32Process;
+                    if (W32Process != NULL)
+                    {
+                        InterlockedDecrement(&W32Process->GDIHandleCount);
+                    }
+                    ObDereferenceObject(OldProcess);
+                }
+                (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL);
                 /* Don't wait on shared locks */
                 return FALSE;
             }
@@ -588,7 +676,7 @@ LockHandle:
                  */
                 DPRINT1("Object->cExclusiveLock = %d\n", Object->cExclusiveLock);
                 GDIDBG_TRACECALLER();
-                GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj));
+                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 */
 
@@ -630,7 +718,7 @@ LockHandle:
             }
             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);
         }
     }
 
@@ -654,6 +742,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
@@ -663,11 +814,47 @@ BOOL
 FASTCALL
 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
     {
@@ -795,12 +982,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];
@@ -810,7 +1003,7 @@ 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(hObj);
@@ -819,16 +1012,6 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
     }
 
     ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
-    HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
-
-    /* Check for invalid owner. */
-    if (ProcessId != HandleProcessId && HandleProcessId != NULL)
-    {
-        DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj, ProcessId, HandleProcessId);
-        GDIDBG_TRACECALLER();
-        GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj));
-        return NULL;
-    }
 
     /*
      * Prevent the thread from being terminated during the locking process.
@@ -845,6 +1028,17 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
 
     for (;;)
     {
+        HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
+
+        /* Check for invalid owner. */
+        if (ProcessId != HandleProcessId && HandleProcessId != NULL)
+        {
+            DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj, ProcessId, HandleProcessId);
+            GDIDBG_TRACECALLER();
+            GDIDBG_TRACEALLOCATOR(hObj);
+            break;
+        }
+
         /* Lock the handle table entry. */
         LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
         PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
@@ -869,6 +1063,9 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
                     Object->Tid = Thread;
                     Object->cExclusiveLock = 1;
                     GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj))
+#if DBG
+                    if (Thread) Thread->cExclusiveLocks++;
+#endif
                 }
                 else
                 {
@@ -881,6 +1078,9 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
                         continue;
                     }
                     InterlockedIncrement((PLONG)&Object->cExclusiveLock);
+#if DBG
+                     if (Thread) Thread->cExclusiveLocks++;
+#endif
                 }
             }
             else
@@ -902,6 +1102,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;
@@ -934,6 +1135,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);
@@ -1233,6 +1438,19 @@ LockHandle:
                     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)
@@ -1251,8 +1469,6 @@ LockHandle:
 
                     if (NewOwner != NULL)
                     {
-                        ProcessId = PsGetProcessId(NewOwner);
-
                         /* Increase the new process' object counter */
                         W32Process = (PPROCESSINFO)NewOwner->Win32Process;
                         if (W32Process != NULL)
@@ -1260,9 +1476,8 @@ LockHandle:
                             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);
 
@@ -1460,60 +1675,68 @@ GDI_MapHandleTable(PSECTION_OBJECT SectionObject, PEPROCESS Process)
     return MappedView;
 }
 
-/** PUBLIC FUNCTIONS **********************************************************/
-
-/*
-  Since Brush/Pen and Region objects are sharable,,, we can just use
-  UserHeapAlloc to allocate the small attribute objects.
-
-   Example Allocating:
-
-    // Save Kernel Space Pointer
-    (PBRUSH)->pBrushAttr = IntGdiAllocObjAttr(GDIObjType_BRUSH_TYPE);
+/* 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;
 
-    // Kernel Space to User Space Pointer
-    (PGDI_TABLE_ENTRY)->UserData = pBrushAttr;
-    // Gdi will adjust for heap delta.
+    /* 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;
+            }
+        }
+    }
 
-   Example Freeing:
+    for(i=0;i<ulCount;i++)
+        apObj[auiIndices[i]] = GDIOBJ_LockObj(ahObj[auiIndices[i]], GDI_OBJECT_TYPE_DONTCARE);
+}
 
-    (PGDI_TABLE_ENTRY)->UserData = NULL;      // Zero the user ptr.
-    UserHeapFree((PBRUSH)->pBrushAttr); // Free from kernel ptr.
-    (PBRUSH)->pBrushAttr = NULL;
 
-   Notes:
-    Testing with DC_ATTR works but has drawing difficulties.
-    Base on observation, (Over looking the obvious) we need to supply heap delta
-    to user space gdi. Now, with testing, looks all normal.
+/** PUBLIC FUNCTIONS **********************************************************/
 
- */
-PVOID
+BOOL
 FASTCALL
-IntGdiAllocObjAttr(GDIOBJTYPE Type)
+IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
 {
-  PVOID pMemAttr = NULL;
-
-  switch( Type )
+  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)
   {
-     case GDIObjType_DC_TYPE:
-        pMemAttr = UserHeapAlloc(sizeof(DC_ATTR));
-        if (pMemAttr) RtlZeroMemory(pMemAttr, sizeof(DC_ATTR));
-        break;
-     case GDIObjType_RGN_TYPE:
-        pMemAttr = UserHeapAlloc(sizeof(RGN_ATTR));
-        if (pMemAttr) RtlZeroMemory(pMemAttr, sizeof(RGN_ATTR));
-        break;
-     case GDIObjType_BRUSH_TYPE:
-        pMemAttr = UserHeapAlloc(sizeof(BRUSH_ATTR));
-        if (pMemAttr) RtlZeroMemory(pMemAttr, sizeof(BRUSH_ATTR));
-        break;
-     default:
-        break;
+     return GDIOBJ_SetOwnership(hRgn, NULL);
+  }
+  if (OwnerMask == GDI_OBJ_HMGR_POWNED)
+  {
+     return GDIOBJ_SetOwnership((HGDIOBJ) hRgn, PsGetCurrentProcess() );
   }
-  return pMemAttr;
+  return FALSE;
 }
 
-
 BOOL
 FASTCALL
 IntGdiSetBrushOwner(PBRUSH pbr, DWORD OwnerMask)
@@ -1563,7 +1786,6 @@ IntGdiSetBrushOwner(PBRUSH pbr, DWORD OwnerMask)
   return TRUE;
 }
 
-
 BOOL
 FASTCALL
 IntGdiSetDCOwnerEx( HDC hDC, DWORD OwnerMask, BOOL NoSetBrush)
@@ -1577,10 +1799,9 @@ IntGdiSetDCOwnerEx( HDC hDC, DWORD OwnerMask, BOOL NoSetBrush)
   {
      pDC = DC_LockDc ( hDC );
      MmCopyFromCaller(&pDC->dcattr, pDC->pdcattr, sizeof(DC_ATTR));
+     DC_vFreeDcAttr(pDC);
      DC_UnlockDc( pDC );
 
-     DC_FreeDcAttr( hDC );         // Free the dcattr!
-
      if (!DC_SetOwnership( hDC, NULL )) // This hDC is inaccessible!
         return Ret;
   }
@@ -1627,7 +1848,6 @@ GreGetObjectOwner(HGDIOBJ Handle, GDIOBJTYPE ObjType)
   return Ret;
 }
 
-
 W32KAPI
 HANDLE
 APIENTRY
@@ -1689,7 +1909,7 @@ IntGdiGetObject(IN HANDLE Handle,
   pGdiObject = GDIOBJ_LockObj(Handle, GDI_OBJECT_TYPE_DONTCARE);
   if (!pGdiObject)
     {
-      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      EngSetLastError(ERROR_INVALID_HANDLE);
       return 0;
     }