Allocate memory for the handle table from paged pool!
[reactos.git] / reactos / subsys / win32k / objects / gdiobj.c
index a464fed..149680d 100644 (file)
 /*
  * GDIOBJ.C - GDI object manipulation routines
  *
- * $Id: gdiobj.c,v 1.45 2003/10/04 21:09:29 gvg Exp $
+ * $Id: gdiobj.c,v 1.73 2004/10/02 16:48:12 navaraf Exp $
  *
  */
+#include <w32k.h>
 
-#undef WIN32_LEAN_AND_MEAN
-#define WIN32_NO_STATUS
-#include <windows.h>
-#include <ddk/ntddk.h>
-#include <include/dce.h>
-#include <include/object.h>
-#include <win32k/gdiobj.h>
-#include <win32k/brush.h>
-#include <win32k/pen.h>
-#include <win32k/text.h>
-#include <win32k/dc.h>
-#include <win32k/bitmaps.h>
-#include <win32k/region.h>
-#include <win32k/cursoricon.h>
-#include <include/palette.h>
-#define NDEBUG
-#include <win32k/debug1.h>
+/* count all gdi objects */
+#define GDI_COUNT_OBJECTS 1
 
 /*! Size of the GDI handle table
  * http://www.windevnet.com/documents/s=7290/wdj9902b/9902b.htm
@@ -63,6 +49,8 @@
 #define GDI_TYPE_TO_MAGIC(t) ((WORD) ((t) >> 16))
 #define GDI_MAGIC_TO_TYPE(m) ((DWORD)(m) << 16)
 
+/* FIXME Ownership of GDI objects by processes not properly implemented yet */
+#if 0
 #define GDI_VALID_OBJECT(h, obj, t, f) \
   (NULL != (obj) \
    && (GDI_MAGIC_TO_TYPE((obj)->Magic) == (t) || GDI_OBJECT_TYPE_DONTCARE == (t)) \
    && (((obj)->hProcessId == PsGetCurrentProcessId()) \
        || (GDI_GLOBAL_PROCESS == (obj)->hProcessId) \
        || ((f) & GDIOBJFLAG_IGNOREPID)))
+#else
+#define GDI_VALID_OBJECT(h, obj, t, f) \
+  (NULL != (obj) \
+   && (GDI_MAGIC_TO_TYPE((obj)->Magic) == (t) || GDI_OBJECT_TYPE_DONTCARE == (t)) \
+   && (GDI_HANDLE_GET_TYPE((h)) == GDI_MAGIC_TO_TYPE((obj)->Magic)))
+#endif
 
 typedef struct _GDI_HANDLE_TABLE
 {
-  WORD  wTableSize;
+  WORD wTableSize;
+  WORD AllocationHint;
+  #if GDI_COUNT_OBJECTS
+  ULONG HandlesCount;
+  #endif
+  PPAGED_LOOKASIDE_LIST LookasideLists;
   PGDIOBJHDR Handles[1];
 } GDI_HANDLE_TABLE, *PGDI_HANDLE_TABLE;
 
+typedef struct
+{
+  ULONG Type;
+  ULONG Size;
+} GDI_OBJ_SIZE;
+
+const
+GDI_OBJ_SIZE ObjSizes[] =
+{
+  /* Testing shows that regions are the most used GDIObj type,
+     so put that one first for performance */
+  {GDI_OBJECT_TYPE_REGION,      sizeof(ROSRGNDATA)},
+  {GDI_OBJECT_TYPE_BITMAP,      sizeof(BITMAPOBJ)},
+  {GDI_OBJECT_TYPE_DC,          sizeof(DC)},
+  {GDI_OBJECT_TYPE_PALETTE,     sizeof(PALGDI)},
+  {GDI_OBJECT_TYPE_BRUSH,       sizeof(GDIBRUSHOBJ)},
+  {GDI_OBJECT_TYPE_PEN,         sizeof(GDIBRUSHOBJ)},
+  {GDI_OBJECT_TYPE_FONT,        sizeof(TEXTOBJ)},
+  {GDI_OBJECT_TYPE_DCE,         sizeof(DCE)},
+/*
+  {GDI_OBJECT_TYPE_DIRECTDRAW,  sizeof(DD_DIRECTDRAW)},
+  {GDI_OBJECT_TYPE_DD_SURFACE,  sizeof(DD_SURFACE)},
+*/
+  {GDI_OBJECT_TYPE_EXTPEN,      0},
+  {GDI_OBJECT_TYPE_METADC,      0},
+  {GDI_OBJECT_TYPE_METAFILE,    0},
+  {GDI_OBJECT_TYPE_ENHMETAFILE, 0},
+  {GDI_OBJECT_TYPE_ENHMETADC,   0},
+  {GDI_OBJECT_TYPE_MEMDC,       0},
+  {GDI_OBJECT_TYPE_EMF,         0}
+};
+
+#define OBJTYPE_COUNT (sizeof(ObjSizes) / sizeof(ObjSizes[0]))
+
 /*  GDI stock objects */
 
 static LOGBRUSH WhiteBrush =
@@ -111,60 +144,80 @@ static LOGPEN NullPen =
 { PS_NULL, { 0, 0 }, 0 };
 
 static LOGFONTW OEMFixedFont =
-{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
-  0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
+{ 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
+  0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"Bitstream Vera Sans Mono" };
 
 static LOGFONTW AnsiFixedFont =
-{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
-  0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
+{ 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+  0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"Bitstream Vera Sans Mono" };
 
 /*static LOGFONTW AnsiVarFont =
- *{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+ *{ 10, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
  *  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif" }; */
 
 static LOGFONTW SystemFont =
-{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
-  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"System" };
+{ 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"Bitstream Vera Sans" };
 
 static LOGFONTW DeviceDefaultFont =
-{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
-  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"" };
+{ 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"Bitstream Vera Sans" };
 
 static LOGFONTW SystemFixedFont =
-{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
-  0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
+{ 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+  0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"Bitstream Vera Sans Mono" };
 
 /* FIXME: Is this correct? */
 static LOGFONTW DefaultGuiFont =
-{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
-  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif" };
+{ 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"Bitstream Vera Sans" };
 
 #define NB_STOCK_OBJECTS (DEFAULT_GUI_FONT + 1)
 
-static HGDIOBJ *StockObjects[NB_STOCK_OBJECTS];
+static HGDIOBJ StockObjects[NB_STOCK_OBJECTS];
 static PGDI_HANDLE_TABLE  HandleTable = 0;
 static FAST_MUTEX  HandleTableMutex;
 static FAST_MUTEX  RefCountHandling;
+static LARGE_INTEGER  ShortDelay;
 
 /*!
  * Allocate GDI object table.
  * \param      Size - number of entries in the object table.
+ * Notes:: Must be called at IRQL < DISPATCH_LEVEL.
 */
 static PGDI_HANDLE_TABLE FASTCALL
 GDIOBJ_iAllocHandleTable (WORD Size)
 {
   PGDI_HANDLE_TABLE  handleTable;
+  ULONG MemSize;
+  UINT ObjType;
+  
+  MemSize = sizeof(GDI_HANDLE_TABLE) + sizeof(PGDIOBJ) * Size;
 
-  ExAcquireFastMutexUnsafe (&HandleTableMutex);
-  handleTable = ExAllocatePool(PagedPool,
-                               sizeof(GDI_HANDLE_TABLE) +
-                               sizeof(PGDIOBJ) * Size);
+  ExAcquireFastMutex(&HandleTableMutex);
+  handleTable = ExAllocatePoolWithTag(PagedPool, MemSize, TAG_GDIHNDTBLE);
   ASSERT( handleTable );
-  memset (handleTable,
-          0,
-          sizeof(GDI_HANDLE_TABLE) + sizeof(PGDIOBJ) * Size);
+  memset (handleTable, 0, MemSize);
+#if GDI_COUNT_OBJECTS
+  handleTable->HandlesCount = 0;
+#endif
   handleTable->wTableSize = Size;
-  ExReleaseFastMutexUnsafe (&HandleTableMutex);
+  handleTable->AllocationHint = 1;
+  handleTable->LookasideLists = ExAllocatePoolWithTag(PagedPool,
+                                                      OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST),
+                                                      TAG_GDIHNDTBLE);
+  if (NULL == handleTable->LookasideLists)
+    {
+      ExFreePool(handleTable);
+      ExReleaseFastMutex(&HandleTableMutex);
+      return NULL;
+    }
+  for (ObjType = 0; ObjType < OBJTYPE_COUNT; ObjType++)
+    {
+      ExInitializePagedLookasideList(handleTable->LookasideLists + ObjType, NULL, NULL, 0,
+                                     ObjSizes[ObjType].Size + sizeof(GDIOBJHDR), TAG_GDIOBJ, 0);
+    }
+  ExReleaseFastMutex(&HandleTableMutex);
 
   return handleTable;
 }
@@ -191,20 +244,49 @@ GDIOBJ_iGetObjectForIndex(WORD TableIndex)
 static WORD FASTCALL
 GDIOBJ_iGetNextOpenHandleIndex (void)
 {
-  WORD tableIndex;
+   WORD tableIndex;
+
+   for (tableIndex = HandleTable->AllocationHint;
+        tableIndex < HandleTable->wTableSize;
+        tableIndex++)
+   {
+      if (HandleTable->Handles[tableIndex] == NULL)
+      {
+         HandleTable->AllocationHint = tableIndex + 1;
+         return tableIndex;
+      }
+   }
+
+   for (tableIndex = 1;
+        tableIndex < HandleTable->AllocationHint;
+        tableIndex++)
+   {
+      if (HandleTable->Handles[tableIndex] == NULL)
+      {
+         HandleTable->AllocationHint = tableIndex + 1;
+         return tableIndex;
+      }
+   }
+
+   return 0;
+}
 
-  ExAcquireFastMutexUnsafe (&HandleTableMutex);
-  for (tableIndex = 1; tableIndex < HandleTable->wTableSize; tableIndex++)
+static PPAGED_LOOKASIDE_LIST FASTCALL
+FindLookasideList(DWORD ObjectType)
+{
+  int Index;
+
+  for (Index = 0; Index < OBJTYPE_COUNT; Index++)
     {
-      if (NULL == HandleTable->Handles[tableIndex])
-       {
-         HandleTable->Handles[tableIndex] = (PGDIOBJHDR) -1;
-         break;
-       }
+      if (ObjSizes[Index].Type == ObjectType)
+        {
+          return HandleTable->LookasideLists + Index;
+        }
     }
-  ExReleaseFastMutexUnsafe (&HandleTableMutex);
 
-  return (tableIndex < HandleTable->wTableSize) ? tableIndex : 0;
+  DPRINT1("Can't find lookaside list for object type 0x%08x\n", ObjectType);
+
+  return NULL;
 }
 
 /*!
@@ -222,23 +304,33 @@ GDIOBJ_iGetNextOpenHandleIndex (void)
 HGDIOBJ FASTCALL
 GDIOBJ_AllocObj(WORD Size, DWORD ObjectType, GDICLEANUPPROC CleanupProc)
 {
+  PW32PROCESS W32Process;
   PGDIOBJHDR  newObject;
   WORD Index;
-  
+  PPAGED_LOOKASIDE_LIST LookasideList;
+
+  ExAcquireFastMutex(&HandleTableMutex);
   Index = GDIOBJ_iGetNextOpenHandleIndex ();
   if (0 == Index)
     {
+      ExReleaseFastMutex(&HandleTableMutex);
       DPRINT1("Out of GDI handles\n");
       return NULL;
     }
 
-  DPRINT("GDIOBJ_AllocObj: handle: %d, size: %d, type: 0x%08x\n", Index, Size, ObjectType);
-  newObject = ExAllocatePool(PagedPool, Size + sizeof (GDIOBJHDR));
-  if (newObject == NULL)
-  {
-    DPRINT1("GDIOBJ_AllocObj: failed\n");
-    return NULL;
-  }
+  LookasideList = FindLookasideList(ObjectType);
+  if (NULL == LookasideList)
+    {
+      ExReleaseFastMutex(&HandleTableMutex);
+      return NULL;
+    }
+  newObject = ExAllocateFromPagedLookasideList(LookasideList);
+  if (NULL == newObject)
+    {
+      ExReleaseFastMutex(&HandleTableMutex);
+      DPRINT1("Unable to allocate GDI object from lookaside list\n");
+      return NULL;
+    }
   RtlZeroMemory (newObject, Size + sizeof(GDIOBJHDR));
 
   newObject->wTableIndex = Index;
@@ -249,7 +341,24 @@ GDIOBJ_AllocObj(WORD Size, DWORD ObjectType, GDICLEANUPPROC CleanupProc)
   newObject->Magic = GDI_TYPE_TO_MAGIC(ObjectType);
   newObject->lockfile = NULL;
   newObject->lockline = 0;
+#ifdef GDIOBJ_USE_FASTMUTEX
+  ExInitializeFastMutex(&newObject->Lock);
+  newObject->RecursiveLockCount = 0;
+#else
+  newObject->LockTid = 0;
+  newObject->LockCount = 0;
+#endif
   HandleTable->Handles[Index] = newObject;
+#if GDI_COUNT_OBJECTS
+  HandleTable->HandlesCount++;
+#endif
+  ExReleaseFastMutex(&HandleTableMutex);
+  
+  W32Process = PsGetCurrentProcess()->Win32Process;
+  if(W32Process)
+  {
+    W32Process->GDIObjects++;
+  }
 
   return GDI_HANDLE_CREATE(Index, ObjectType);
 }
@@ -272,8 +381,10 @@ GDIOBJ_AllocObj(WORD Size, DWORD ObjectType, GDICLEANUPPROC CleanupProc)
 BOOL STDCALL
 GDIOBJ_FreeObj(HGDIOBJ hObj, DWORD ObjectType, DWORD Flag)
 {
+  PW32PROCESS W32Process;
   PGDIOBJHDR objectHeader;
   PGDIOBJ Obj;
+  PPAGED_LOOKASIDE_LIST LookasideList;
   BOOL         bRet = TRUE;
 
   objectHeader = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
@@ -309,9 +420,23 @@ GDIOBJ_FreeObj(HGDIOBJ hObj, DWORD ObjectType, DWORD Flag)
       Obj = (PGDIOBJ)((PCHAR)objectHeader + sizeof(GDIOBJHDR));
       bRet = (*(objectHeader->CleanupProc))(Obj);
     }
-
-  ExFreePool(objectHeader);
+  LookasideList = FindLookasideList(GDI_MAGIC_TO_TYPE(objectHeader->Magic));
+  if (NULL != LookasideList)
+    {
+      ExFreeToPagedLookasideList(LookasideList, objectHeader);
+    }
+  ExAcquireFastMutexUnsafe (&HandleTableMutex);
   HandleTable->Handles[GDI_HANDLE_GET_INDEX(hObj)] = NULL;
+#if GDI_COUNT_OBJECTS
+  HandleTable->HandlesCount--;
+#endif
+  ExReleaseFastMutexUnsafe (&HandleTableMutex);
+  
+  W32Process = PsGetCurrentProcess()->Win32Process;
+  if(W32Process)
+  {
+    W32Process->GDIObjects--;
+  }
 
   return bRet;
 }
@@ -395,50 +520,6 @@ GDIOBJ_UnlockMultipleObj(PGDIMULTILOCK pList, INT nObj)
   return TRUE;
 }
 
-/*!
- * Marks the object as global. (Creator process ID is set to GDI_GLOBAL_PROCESS). Global objects may be
- * accessed by any process.
- * \param      ObjectHandle - handle of the object to make global.
- *
- * \note       Only stock objects should be marked global.
-*/
-VOID FASTCALL
-GDIOBJ_MarkObjectGlobal(HGDIOBJ ObjectHandle)
-{
-  PGDIOBJHDR ObjHdr;
-
-  DPRINT("GDIOBJ_MarkObjectGlobal handle 0x%08x\n", ObjectHandle);
-  ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle));
-  if (NULL == ObjHdr)
-    {
-      return;
-    }
-
-  ObjHdr->hProcessId = GDI_GLOBAL_PROCESS;
-}
-
-/*!
- * Removes the global mark from the object. Global objects may be
- * accessed by any process.
- * \param      ObjectHandle - handle of the object to make local.
- *
- * \note       Only stock objects should be marked global.
-*/
-VOID FASTCALL
-GDIOBJ_UnmarkObjectGlobal(HGDIOBJ ObjectHandle)
-{
-  PGDIOBJHDR ObjHdr;
-
-  DPRINT("GDIOBJ_MarkObjectGlobal handle 0x%08x\n", ObjectHandle);
-  ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle));
-  if (NULL == ObjHdr || GDI_GLOBAL_PROCESS != ObjHdr->hProcessId)
-    {
-      return;
-    }
-
-  ObjHdr->hProcessId = PsGetCurrentProcessId();
-}
-
 /*!
  * Get the type of the object.
  * \param      ObjectHandle - handle of the object.
@@ -472,6 +553,8 @@ InitGdiObjectHandleTable (VOID)
   ExInitializeFastMutex (&HandleTableMutex);
   ExInitializeFastMutex (&RefCountHandling);
 
+  ShortDelay.QuadPart = -100;
+
   HandleTable = GDIOBJ_iAllocHandleTable (GDI_HANDLE_COUNT);
   DPRINT("HandleTable: %x\n", HandleTable );
 
@@ -490,16 +573,16 @@ CreateStockObjects(void)
 
   /* Create GDI Stock Objects from the logical structures we've defined */
 
-  StockObjects[WHITE_BRUSH] =  NtGdiCreateBrushIndirect(&WhiteBrush);
-  StockObjects[LTGRAY_BRUSH] = NtGdiCreateBrushIndirect(&LtGrayBrush);
-  StockObjects[GRAY_BRUSH] =   NtGdiCreateBrushIndirect(&GrayBrush);
-  StockObjects[DKGRAY_BRUSH] = NtGdiCreateBrushIndirect(&DkGrayBrush);
-  StockObjects[BLACK_BRUSH] =  NtGdiCreateBrushIndirect(&BlackBrush);
-  StockObjects[NULL_BRUSH] =   NtGdiCreateBrushIndirect(&NullBrush);
+  StockObjects[WHITE_BRUSH] =  IntGdiCreateBrushIndirect(&WhiteBrush);
+  StockObjects[LTGRAY_BRUSH] = IntGdiCreateBrushIndirect(&LtGrayBrush);
+  StockObjects[GRAY_BRUSH] =   IntGdiCreateBrushIndirect(&GrayBrush);
+  StockObjects[DKGRAY_BRUSH] = IntGdiCreateBrushIndirect(&DkGrayBrush);
+  StockObjects[BLACK_BRUSH] =  IntGdiCreateBrushIndirect(&BlackBrush);
+  StockObjects[NULL_BRUSH] =   IntGdiCreateBrushIndirect(&NullBrush);
 
-  StockObjects[WHITE_PEN] = NtGdiCreatePenIndirect(&WhitePen);
-  StockObjects[BLACK_PEN] = NtGdiCreatePenIndirect(&BlackPen);
-  StockObjects[NULL_PEN] =  NtGdiCreatePenIndirect(&NullPen);
+  StockObjects[WHITE_PEN] = IntGdiCreatePenIndirect(&WhitePen);
+  StockObjects[BLACK_PEN] = IntGdiCreatePenIndirect(&BlackPen);
+  StockObjects[NULL_PEN] =  IntGdiCreatePenIndirect(&NullPen);
 
   (void) TextIntCreateFontIndirect(&OEMFixedFont, (HFONT*)&StockObjects[OEM_FIXED_FONT]);
   (void) TextIntCreateFontIndirect(&AnsiFixedFont, (HFONT*)&StockObjects[ANSI_FIXED_FONT]);
@@ -514,7 +597,7 @@ CreateStockObjects(void)
     {
       if (NULL != StockObjects[Object])
        {
-         GDIOBJ_MarkObjectGlobal(StockObjects[Object]);
+         GDIOBJ_SetOwnership(StockObjects[Object], NULL);
 /*       GDI_HANDLE_SET_STOCKOBJ(StockObjects[Object]);*/
        }
     }
@@ -545,7 +628,8 @@ NtGdiDeleteObject(HGDIOBJ hObject)
 {
   DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
 
-  return GDIOBJ_FreeObj(hObject, GDI_OBJECT_TYPE_DONTCARE, GDIOBJFLAG_DEFAULT);
+  return NULL != hObject
+         ? GDIOBJ_FreeObj(hObject, GDI_OBJECT_TYPE_DONTCARE, GDIOBJFLAG_DEFAULT) : FALSE;
 }
 
 /*!
@@ -596,9 +680,12 @@ CleanupForProcess (struct _EPROCESS *Process, INT Pid)
 PGDIOBJ FASTCALL
 GDIOBJ_LockObjDbg (const char* file, int line, HGDIOBJ hObj, DWORD ObjectType)
 {
-  PGDIOBJ rc;
   PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
+#ifndef GDIOBJ_USE_FASTMUTEX
+  DWORD CurrentTid = (DWORD)PsGetCurrentThreadId();
+#endif
 
+  DPRINT("(%s:%i) GDIOBJ_LockObjDbg(0x%08x,0x%08x)\n", file, line, hObj, ObjectType);
   if (! GDI_VALID_OBJECT(hObj, ObjHdr, ObjectType, GDIOBJFLAG_DEFAULT))
     {
       int reason = 0;
@@ -624,21 +711,61 @@ GDIOBJ_LockObjDbg (const char* file, int line, HGDIOBJ hObj, DWORD ObjectType)
       DPRINT1("\tcalled from: %s:%i\n", file, line );
       return NULL;
     }
-  if (NULL != ObjHdr->lockfile)
+
+#ifdef GDIOBJ_USE_FASTMUTEX
+  if (ObjHdr->Lock.Owner == KeGetCurrentThread())
     {
-      DPRINT1("Caution! GDIOBJ_LockObj trying to lock object (0x%x) second time\n", hObj );
-      DPRINT1("\tcalled from: %s:%i\n", file, line );
-      DPRINT1("\tpreviously locked from: %s:%i\n", ObjHdr->lockfile, ObjHdr->lockline );
+      ObjHdr->RecursiveLockCount++;
     }
-  DPRINT("(%s:%i) GDIOBJ_LockObj(0x%08x,0x%08x)\n", file, line, hObj, ObjectType);
-  rc = GDIOBJ_LockObj(hObj, ObjectType);
-  if (rc && NULL == ObjHdr->lockfile)
+  else
+    {
+#ifdef NDEBUG    
+      ExAcquireFastMutex(&ObjHdr->Lock);
+#else /* NDEBUG */
+      if (! ExTryToAcquireFastMutex(&ObjHdr->Lock))
+        {
+          DPRINT1("Caution! GDIOBJ_LockObj trying to lock object 0x%x second time\n", hObj);
+          DPRINT1("  called from: %s:%i (thread %x)\n", file, line, KeGetCurrentThread());
+          if (NULL != ObjHdr->lockfile)
+            {
+              DPRINT1("  previously locked from: %s:%i (thread %x)\n", ObjHdr->lockfile, ObjHdr->lockline, ObjHdr->Lock.Owner);
+            }
+          ExAcquireFastMutex(&ObjHdr->Lock);
+          DPRINT1("  Disregard previous message about object 0x%x, it's ok\n", hObj);
+        }
+#endif /* NDEBUG */
+      ObjHdr->RecursiveLockCount++;
+    }
+#else
+  if (ObjHdr->LockTid == CurrentTid)
+    {
+      InterlockedIncrement(&ObjHdr->LockCount);
+    }
+  else
+    {
+      for (;;)
+        {
+          if (InterlockedCompareExchange(&ObjHdr->LockTid, CurrentTid, 0) == CurrentTid)
+            {
+              InterlockedIncrement(&ObjHdr->LockCount);
+              break;
+            }
+          /* FIXME: KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay); */
+        }
+    }
+#endif
+
+  ExAcquireFastMutex(&RefCountHandling);
+  ObjHdr->dwCount++;
+  ExReleaseFastMutex(&RefCountHandling);
+
+  if (NULL == ObjHdr->lockfile)
     {
       ObjHdr->lockfile = file;
       ObjHdr->lockline = line;
     }
 
-  return rc;
+  return (PGDIOBJ)((PCHAR)ObjHdr + sizeof(GDIOBJHDR));
 }
 #endif//GDIOBJ_LockObj
 
@@ -679,6 +806,9 @@ PGDIOBJ FASTCALL
 GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ObjectType)
 {
   PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
+#ifndef GDIOBJ_USE_FASTMUTEX
+  DWORD CurrentTid = (DWORD)PsGetCurrentThreadId();
+#endif
 
   DPRINT("GDIOBJ_LockObj: hObj: 0x%08x, type: 0x%08x, objhdr: %x\n", hObj, ObjectType, ObjHdr);
   if (! GDI_VALID_OBJECT(hObj, ObjHdr, ObjectType, GDIOBJFLAG_DEFAULT))
@@ -688,11 +818,34 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ObjectType)
       return NULL;
     }
 
-  if(0 < ObjHdr->dwCount)
+#ifdef GDIOBJ_USE_FASTMUTEX
+  if (ObjHdr->Lock.Owner == KeGetCurrentThread())
+    {
+      ObjHdr->RecursiveLockCount++;
+    }
+  else
+    {
+      ExAcquireFastMutex(&ObjHdr->Lock);
+      ObjHdr->RecursiveLockCount++;
+    }
+#else
+  if (ObjHdr->LockTid == CurrentTid)
     {
-      DPRINT1("Caution! GDIOBJ_LockObj trying to lock object (0x%x) second time\n", hObj);
-      DPRINT1("\t called from: %x\n", __builtin_return_address(0));
+      InterlockedIncrement(&ObjHdr->LockCount);
     }
+  else
+    {
+      for (;;)
+        {
+          if (InterlockedCompareExchange(&ObjHdr->LockTid, CurrentTid, 0) == CurrentTid)
+            {
+              InterlockedIncrement(&ObjHdr->LockCount);
+              break;
+            }
+          /* FIXME: KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay); */
+        }
+    }
+#endif
 
   ExAcquireFastMutex(&RefCountHandling);
   ObjHdr->dwCount++;
@@ -725,6 +878,16 @@ GDIOBJ_UnlockObj(HGDIOBJ hObj, DWORD ObjectType)
     return FALSE;
   }
 
+#ifdef GDIOBJ_USE_FASTMUTEX
+  if (--ObjHdr->RecursiveLockCount == 0)
+    ExReleaseFastMutex(&ObjHdr->Lock);
+#else
+  if (InterlockedDecrement(&ObjHdr->LockCount) == 0)
+    {
+      InterlockedExchange(&ObjHdr->LockTid, 0);
+    }
+#endif
+
   ExAcquireFastMutex(&RefCountHandling);
   if (0 == (ObjHdr->dwCount & ~0x80000000))
     {
@@ -748,4 +911,104 @@ GDIOBJ_UnlockObj(HGDIOBJ hObj, DWORD ObjectType)
   return TRUE;
 }
 
+BOOL FASTCALL
+GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle)
+{
+  PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle));
+
+  DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
+  ASSERT(GDI_VALID_OBJECT(ObjectHandle, ObjHdr, GDI_OBJECT_TYPE_DONTCARE, GDIOBJFLAG_IGNOREPID));
+
+  return ObjHdr->hProcessId == PsGetCurrentProcessId();
+}
+
+void FASTCALL
+GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
+{
+  PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle));
+  PEPROCESS OldProcess;
+  PW32PROCESS W32Process;
+  NTSTATUS Status;
+
+  DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
+  ASSERT(GDI_VALID_OBJECT(ObjectHandle, ObjHdr, GDI_OBJECT_TYPE_DONTCARE, GDIOBJFLAG_IGNOREPID));
+
+  if ((NULL == NewOwner && GDI_GLOBAL_PROCESS != ObjHdr->hProcessId)
+      || (NULL != NewOwner && ObjHdr->hProcessId != (HANDLE) NewOwner->UniqueProcessId))
+    {
+      Status = PsLookupProcessByProcessId((PVOID)ObjHdr->hProcessId, &OldProcess);
+      if (NT_SUCCESS(Status))
+        {
+          W32Process = OldProcess->Win32Process;
+          if (W32Process)
+            {
+              W32Process->GDIObjects--;
+            }
+          ObDereferenceObject(OldProcess);
+        }
+    }
+
+  if (NULL == NewOwner)
+    {
+      ObjHdr->hProcessId = GDI_GLOBAL_PROCESS;
+    }
+  else if (ObjHdr->hProcessId != (HANDLE) NewOwner->UniqueProcessId)
+    {
+      ObjHdr->hProcessId = (HANDLE) NewOwner->UniqueProcessId;
+      W32Process = NewOwner->Win32Process;
+      if (W32Process)
+        {
+          W32Process->GDIObjects++;
+        }
+    }
+}
+
+void FASTCALL
+GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
+{
+  PGDIOBJHDR ObjHdrFrom = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(CopyFrom));
+  PGDIOBJHDR ObjHdrTo = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(CopyTo));
+  NTSTATUS Status;
+  PEPROCESS ProcessFrom;
+  PEPROCESS CurrentProcess;
+
+  ASSERT(NULL != ObjHdrFrom && NULL != ObjHdrTo);
+  if (NULL != ObjHdrFrom && NULL != ObjHdrTo
+      && ObjHdrTo->hProcessId != ObjHdrFrom->hProcessId)
+    {
+      if (ObjHdrFrom->hProcessId == GDI_GLOBAL_PROCESS)
+        {
+          GDIOBJ_SetOwnership(CopyTo, NULL);
+        }
+      else
+        {
+          /* Warning: ugly hack ahead
+           *
+           * During process cleanup, we can't call PsLookupProcessByProcessId
+           * for the current process, 'cause that function will try to
+           * reference the process, and since the process is closing down
+           * that will result in a bugcheck.
+           * So, instead, we call PsGetCurrentProcess, which doesn't reference
+           * the process. If the current process is indeed the one we're
+           * looking for, we use it, otherwise we can (safely) call
+           * PsLookupProcessByProcessId
+           */
+          CurrentProcess = PsGetCurrentProcess();
+          if (ObjHdrFrom->hProcessId == (HANDLE) CurrentProcess->UniqueProcessId)
+            {
+              GDIOBJ_SetOwnership(CopyTo, CurrentProcess);
+            }
+          else
+            {
+              Status = PsLookupProcessByProcessId((PVOID) ObjHdrFrom->hProcessId, &ProcessFrom);
+              if (NT_SUCCESS(Status))
+                {
+                  GDIOBJ_SetOwnership(CopyTo, ProcessFrom);
+                  ObDereferenceObject(ProcessFrom);
+                }
+            }
+        }
+    }
+}
+
 /* EOF */