[WIN32K]
[reactos.git] / reactos / win32ss / gdi / ntgdi / gdiobj.c
index 7d294c5..7cfbf47 100644 (file)
 #define NDEBUG
 #include <debug.h>
 
-// Move to gdidbg.h
+
+FORCEINLINE
+void
+INCREASE_THREAD_LOCK_COUNT(
+    _In_ HANDLE hobj)
+{
+    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+    DBG_UNREFERENCED_PARAMETER(hobj);
+    if (pti)
+    {
+#if DBG
+        pti->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]++;
+#endif
+        pti->cExclusiveLocks++;
+    }
+}
+
+FORCEINLINE
+void
+DECREASE_THREAD_LOCK_COUNT(
+    _In_ HANDLE hobj)
+{
+    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+    DBG_UNREFERENCED_PARAMETER(hobj);
+    if (pti)
+    {
+#if DBG
+        pti->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]--;
+#endif
+        pti->cExclusiveLocks--;
+    }
+}
+
 #if DBG
-#define DBG_INCREASE_LOCK_COUNT(pti, hobj) \
-    if (pti) ((PTHREADINFO)pti)->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]++;
-#define DBG_DECREASE_LOCK_COUNT(pti, hobj) \
-    if (pti) ((PTHREADINFO)pti)->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]--;
 #define ASSERT_SHARED_OBJECT_TYPE(objt) \
     ASSERT((objt) == GDIObjType_SURF_TYPE || \
            (objt) == GDIObjType_PAL_TYPE || \
            (objt) == GDIObjType_BRUSH_TYPE)
 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt) \
     ASSERT((objt) == GDIObjType_DC_TYPE || \
-           (objt) == GDIObjType_RGN_TYPE || \
-           (objt) == GDIObjType_LFONT_TYPE)
+           (objt) == GDIObjType_RGN_TYPE)
+#define ASSERT_TRYLOCK_OBJECT_TYPE(objt) \
+    ASSERT((objt) == GDIObjType_DRVOBJ_TYPE)
 #else
-#define DBG_INCREASE_LOCK_COUNT(ppi, hobj)
-#define DBG_DECREASE_LOCK_COUNT(x, y)
 #define ASSERT_SHARED_OBJECT_TYPE(objt)
 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt)
+#define ASSERT_TRYLOCK_OBJECT_TYPE(objt)
 #endif
 
 #if defined(_M_IX86) || defined(_M_AMD64)
@@ -79,59 +107,60 @@ enum
 
 /* Per session handle table globals */
 static PVOID gpvGdiHdlTblSection = NULL;
-static PENTRY gpentHmgr;
-static PULONG gpaulRefCount;
+PENTRY gpentHmgr;
+PULONG gpaulRefCount;
 ULONG gulFirstFree;
 ULONG gulFirstUnused;
 static PPAGED_LOOKASIDE_LIST gpaLookasideList;
 
-static BOOL NTAPI GDIOBJ_Cleanup(PVOID ObjectBody);
+static VOID NTAPI GDIOBJ_vCleanup(PVOID ObjectBody);
 
 static const
 GDICLEANUPPROC
 apfnCleanup[] =
 {
-    NULL,             /* 00 GDIObjType_DEF_TYPE */
-    DC_Cleanup,       /* 01 GDIObjType_DC_TYPE */
-    NULL,             /* 02 GDIObjType_UNUSED1_TYPE */
-    NULL,             /* 03 GDIObjType_UNUSED2_TYPE */
-    REGION_Cleanup,   /* 04 GDIObjType_RGN_TYPE */
-    SURFACE_Cleanup,  /* 05 GDIObjType_SURF_TYPE */
-    GDIOBJ_Cleanup,   /* 06 GDIObjType_CLIENTOBJ_TYPE */
-    GDIOBJ_Cleanup,   /* 07 GDIObjType_PATH_TYPE */
-    PALETTE_Cleanup,  /* 08 GDIObjType_PAL_TYPE */
-    GDIOBJ_Cleanup,   /* 09 GDIObjType_ICMLCS_TYPE */
-    GDIOBJ_Cleanup,   /* 0a GDIObjType_LFONT_TYPE */
-    NULL,             /* 0b GDIObjType_RFONT_TYPE, unused */
-    NULL,             /* 0c GDIObjType_PFE_TYPE, unused */
-    NULL,             /* 0d GDIObjType_PFT_TYPE, unused */
-    GDIOBJ_Cleanup,   /* 0e GDIObjType_ICMCXF_TYPE */
-    NULL,             /* 0f GDIObjType_SPRITE_TYPE, unused */
-    BRUSH_Cleanup,    /* 10 GDIObjType_BRUSH_TYPE, BRUSH, PEN, EXTPEN */
-    NULL,             /* 11 GDIObjType_UMPD_TYPE, unused */
-    NULL,             /* 12 GDIObjType_UNUSED4_TYPE */
-    NULL,             /* 13 GDIObjType_SPACE_TYPE, unused */
-    NULL,             /* 14 GDIObjType_UNUSED5_TYPE */
-    NULL,             /* 15 GDIObjType_META_TYPE, unused */
-    NULL,             /* 16 GDIObjType_EFSTATE_TYPE, unused */
-    NULL,             /* 17 GDIObjType_BMFD_TYPE, unused */
-    NULL,             /* 18 GDIObjType_VTFD_TYPE, unused */
-    NULL,             /* 19 GDIObjType_TTFD_TYPE, unused */
-    NULL,             /* 1a GDIObjType_RC_TYPE, unused */
-    NULL,             /* 1b GDIObjType_TEMP_TYPE, unused */
-    DRIVEROBJ_Cleanup,/* 1c GDIObjType_DRVOBJ_TYPE */
-    NULL,             /* 1d GDIObjType_DCIOBJ_TYPE, unused */
-    NULL,             /* 1e GDIObjType_SPOOL_TYPE, unused */
-    NULL,             /* 1f reserved entry */
+    NULL,              /* 00 GDIObjType_DEF_TYPE */
+    DC_vCleanup,       /* 01 GDIObjType_DC_TYPE */
+    NULL,              /* 02 GDIObjType_UNUSED1_TYPE */
+    NULL,              /* 03 GDIObjType_UNUSED2_TYPE */
+    REGION_vCleanup,   /* 04 GDIObjType_RGN_TYPE */
+    SURFACE_vCleanup,  /* 05 GDIObjType_SURF_TYPE */
+    GDIOBJ_vCleanup,   /* 06 GDIObjType_CLIENTOBJ_TYPE */
+    GDIOBJ_vCleanup,   /* 07 GDIObjType_PATH_TYPE */
+    PALETTE_vCleanup,  /* 08 GDIObjType_PAL_TYPE */
+    GDIOBJ_vCleanup,   /* 09 GDIObjType_ICMLCS_TYPE */
+    GDIOBJ_vCleanup,   /* 0a GDIObjType_LFONT_TYPE */
+    NULL,              /* 0b GDIObjType_RFONT_TYPE, unused */
+    NULL,              /* 0c GDIObjType_PFE_TYPE, unused */
+    NULL,              /* 0d GDIObjType_PFT_TYPE, unused */
+    GDIOBJ_vCleanup,   /* 0e GDIObjType_ICMCXF_TYPE */
+    NULL,              /* 0f GDIObjType_SPRITE_TYPE, unused */
+    BRUSH_vCleanup,    /* 10 GDIObjType_BRUSH_TYPE, BRUSH, PEN, EXTPEN */
+    NULL,              /* 11 GDIObjType_UMPD_TYPE, unused */
+    NULL,              /* 12 GDIObjType_UNUSED4_TYPE */
+    NULL,              /* 13 GDIObjType_SPACE_TYPE, unused */
+    NULL,              /* 14 GDIObjType_UNUSED5_TYPE */
+    NULL,              /* 15 GDIObjType_META_TYPE, unused */
+    NULL,              /* 16 GDIObjType_EFSTATE_TYPE, unused */
+    NULL,              /* 17 GDIObjType_BMFD_TYPE, unused */
+    NULL,              /* 18 GDIObjType_VTFD_TYPE, unused */
+    NULL,              /* 19 GDIObjType_TTFD_TYPE, unused */
+    NULL,              /* 1a GDIObjType_RC_TYPE, unused */
+    NULL,              /* 1b GDIObjType_TEMP_TYPE, unused */
+    DRIVEROBJ_vCleanup,/* 1c GDIObjType_DRVOBJ_TYPE */
+    NULL,              /* 1d GDIObjType_DCIOBJ_TYPE, unused */
+    NULL,              /* 1e GDIObjType_SPOOL_TYPE, unused */
+    NULL,              /* 1f reserved entry */
 };
 
 /* INTERNAL FUNCTIONS ********************************************************/
 
 static
-BOOL NTAPI
-GDIOBJ_Cleanup(PVOID ObjectBody)
+VOID
+NTAPI
+GDIOBJ_vCleanup(PVOID ObjectBody)
 {
-    return TRUE;
+    /* Nothing to do */
 }
 
 static
@@ -223,7 +252,7 @@ InitGdiHandleTable(void)
 
 FORCEINLINE
 VOID
-IncrementGdiHandleCount(void)
+IncrementCurrentProcessGdiHandleCount(void)
 {
     PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
     if (ppi) InterlockedIncrement((LONG*)&ppi->GDIHandleCount);
@@ -231,12 +260,44 @@ IncrementGdiHandleCount(void)
 
 FORCEINLINE
 VOID
-DecrementGdiHandleCount(void)
+DecrementCurrentProcessGdiHandleCount(void)
 {
     PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
     if (ppi) InterlockedDecrement((LONG*)&ppi->GDIHandleCount);
 }
 
+FORCEINLINE
+VOID
+IncrementGdiHandleCount(ULONG ulProcessId)
+{
+    PEPROCESS pep;
+    PPROCESSINFO ppi;
+    NTSTATUS Status;
+
+    Status = PsLookupProcessByProcessId(ULongToHandle(ulProcessId), &pep);
+    NT_ASSERT(NT_SUCCESS(Status));
+
+    ppi = PsGetProcessWin32Process(pep);
+    if (ppi) InterlockedIncrement((LONG*)&ppi->GDIHandleCount);
+    if (NT_SUCCESS(Status)) ObDereferenceObject(pep);
+}
+
+FORCEINLINE
+VOID
+DecrementGdiHandleCount(ULONG ulProcessId)
+{
+    PEPROCESS pep;
+    PPROCESSINFO ppi;
+    NTSTATUS Status;
+
+    Status = PsLookupProcessByProcessId(ULongToHandle(ulProcessId), &pep);
+    NT_ASSERT(NT_SUCCESS(Status));
+
+    ppi = PsGetProcessWin32Process(pep);
+    if (ppi) InterlockedDecrement((LONG*)&ppi->GDIHandleCount);
+    if (NT_SUCCESS(Status)) ObDereferenceObject(pep);
+}
+
 static
 PENTRY
 ENTRY_pentPopFreeEntry(VOID)
@@ -498,7 +559,7 @@ GDIOBJ_vDereferenceObject(POBJ pobj)
                 /* Decrement the process handle count */
                 ASSERT(gpentHmgr[ulIndex].ObjectOwner.ulObj ==
                        HandleToUlong(PsGetCurrentProcessId()));
-                DecrementGdiHandleCount();
+                DecrementCurrentProcessGdiHandleCount();
             }
 
             /* Push entry to the free list */
@@ -590,6 +651,72 @@ GDIOBJ_vReferenceObjectByPointer(POBJ pobj)
     DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, cRefs);
 }
 
+PGDIOBJ
+NTAPI
+GDIOBJ_TryLockObject(
+    HGDIOBJ hobj,
+    UCHAR objt)
+{
+    PENTRY pentry;
+    POBJ pobj;
+    DWORD dwThreadId;
+
+    /* Check if the handle type matches */
+    ASSERT_TRYLOCK_OBJECT_TYPE(objt);
+    if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt)
+    {
+        DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj, objt);
+        return NULL;
+    }
+
+    /* Reference the handle entry */
+    pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
+    if (!pentry)
+    {
+        DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj);
+        return NULL;
+    }
+
+    /* Get the pointer to the BASEOBJECT */
+    pobj = pentry->einfo.pobj;
+
+    /* Check if we already own the lock */
+    dwThreadId = PtrToUlong(PsGetCurrentThreadId());
+    if (pobj->dwThreadId != dwThreadId)
+    {
+        /* Disable APCs and try acquiring the push lock */
+        KeEnterCriticalRegion();
+        if(!ExTryAcquirePushLockExclusive(&pobj->pushlock))
+        {
+            ULONG cRefs, ulIndex;
+            /* Already owned. Clean up and leave. */
+            KeLeaveCriticalRegion();
+
+            /* Calculate the index */
+            ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
+
+            /* Decrement reference count */
+            ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
+            cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]);
+            ASSERT(cRefs & REF_MASK_VALID);
+
+            return NULL;
+        }
+
+        /* Set us as lock owner */
+        ASSERT(pobj->dwThreadId == 0);
+        pobj->dwThreadId = dwThreadId;
+    }
+
+    /* Increase lock count */
+    pobj->cExclusiveLock++;
+    INCREASE_THREAD_LOCK_COUNT(hobj);
+    DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0);
+
+    /* Return the object */
+    return pobj;
+}
+
 PGDIOBJ
 NTAPI
 GDIOBJ_LockObject(
@@ -634,7 +761,7 @@ GDIOBJ_LockObject(
 
     /* Increase lock count */
     pobj->cExclusiveLock++;
-    DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), hobj);
+    INCREASE_THREAD_LOCK_COUNT(hobj);
     DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0);
 
     /* Return the object */
@@ -650,7 +777,7 @@ GDIOBJ_vUnlockObject(POBJ pobj)
 
     /* Decrease lock count */
     pobj->cExclusiveLock--;
-    DBG_DECREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
+    DECREASE_THREAD_LOCK_COUNT(pobj->hHmgr);
     DBG_LOGEVENT(&pobj->slhLog, EVENT_UNLOCK, 0);
 
     /* Check if this was the last lock */
@@ -701,7 +828,7 @@ GDIOBJ_hInsertObject(
     ExAcquirePushLockExclusive(&pobj->pushlock);
     pobj->cExclusiveLock = 1;
     pobj->dwThreadId = PtrToUlong(PsGetCurrentThreadId());
-    DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
+    INCREASE_THREAD_LOCK_COUNT(pobj->hHmgr);
 
     /* Get object type from the hHmgr field */
     objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0xff;
@@ -711,7 +838,7 @@ GDIOBJ_hInsertObject(
     if (ulOwner == GDI_OBJ_HMGR_POWNED)
     {
         /* Increment the process handle count */
-        IncrementGdiHandleCount();
+        IncrementCurrentProcessGdiHandleCount();
 
         /* Use Process id */
         ulOwner = HandleToUlong(PsGetCurrentProcessId());
@@ -730,50 +857,64 @@ VOID
 NTAPI
 GDIOBJ_vSetObjectOwner(
     POBJ pobj,
-    ULONG ulOwner)
+    ULONG ulNewOwner)
 {
     PENTRY pentry;
+    ULONG ulOldOwner;
 
     /* This is a ugly HACK, needed to fix IntGdiSetDCOwnerEx */
     if (GDI_HANDLE_IS_STOCKOBJ(pobj->hHmgr))
     {
-        DPRINT("Trying to set ownership of stock object %p to %lx\n", pobj->hHmgr, ulOwner);
+        DPRINT("Trying to set ownership of stock object %p to %lx\n", pobj->hHmgr, ulNewOwner);
         return;
     }
 
     /* Get the handle entry */
-    ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr));
+    NT_ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr));
     pentry = &gpentHmgr[GDI_HANDLE_GET_INDEX(pobj->hHmgr)];
 
+    /* Check if the new owner is the same as the old one */
+    ulOldOwner = pentry->ObjectOwner.ulObj;
+    if (ulOldOwner == ulNewOwner)
+    {
+        /* Nothing to do */
+        return;
+    }
+
     /* Is the current process requested? */
-    if (ulOwner == GDI_OBJ_HMGR_POWNED)
+    if (ulNewOwner == GDI_OBJ_HMGR_POWNED)
     {
         /* Use process id */
-        ulOwner = HandleToUlong(PsGetCurrentProcessId());
-        if (pentry->ObjectOwner.ulObj != ulOwner)
-        {
-            IncrementGdiHandleCount();
-        }
+        ulNewOwner = HandleToUlong(PsGetCurrentProcessId());
     }
 
     // HACK
-    if (ulOwner == GDI_OBJ_HMGR_NONE)
-        ulOwner = GDI_OBJ_HMGR_PUBLIC;
+    if (ulNewOwner == GDI_OBJ_HMGR_NONE)
+        ulNewOwner = GDI_OBJ_HMGR_PUBLIC;
+
+    /* Was the object process owned? */
+    if ((ulOldOwner != GDI_OBJ_HMGR_PUBLIC) &&
+        (ulOldOwner != GDI_OBJ_HMGR_NONE))
+    {
+        /* Decrement the previous owners handle count */
+        DecrementGdiHandleCount(ulOldOwner);
+    }
 
-    if (ulOwner == GDI_OBJ_HMGR_PUBLIC ||
-        ulOwner == GDI_OBJ_HMGR_NONE)
+    /* Is the new owner a process? */
+    if ((ulNewOwner != GDI_OBJ_HMGR_PUBLIC) &&
+        (ulNewOwner != GDI_OBJ_HMGR_NONE))
+    {
+        /* Increment the new owners handle count */
+        IncrementGdiHandleCount(ulNewOwner);
+    }
+    else
     {
         /* Make sure we don't leak user mode memory */
-        ASSERT(pentry->pUser == NULL);
-        if (pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC &&
-            pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_NONE)
-        {
-            DecrementGdiHandleCount();
-        }
+        NT_ASSERT(pentry->pUser == NULL);
     }
 
     /* Set new owner */
-    pentry->ObjectOwner.ulObj = ulOwner;
+    pentry->ObjectOwner.ulObj = ulNewOwner;
     DBG_LOGEVENT(&pobj->slhLog, EVENT_SET_OWNER, 0);
 }
 
@@ -885,7 +1026,7 @@ GDIOBJ_vDeleteObject(POBJ pobj)
             /* Release the pushlock and reenable APCs */
             ExReleasePushLockExclusive(&pobj->pushlock);
             KeLeaveCriticalRegion();
-            DBG_DECREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
+            DECREASE_THREAD_LOCK_COUNT(pobj->hHmgr);
         }
     }
 
@@ -971,9 +1112,10 @@ GreGetObjectOwner(HGDIOBJ hobj)
 
 BOOL
 NTAPI
-GreSetObjectOwner(
+GreSetObjectOwnerEx(
     HGDIOBJ hobj,
-    ULONG ulOwner)
+    ULONG ulOwner,
+    ULONG Flags)
 {
     PENTRY pentry;
 
@@ -985,7 +1127,7 @@ GreSetObjectOwner(
     }
 
     /* Reference the handle entry */
-    pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
+    pentry = ENTRY_ReferenceEntryByHandle(hobj, Flags);
     if (!pentry)
     {
         DPRINT("GreSetObjectOwner: Invalid handle 0x%p.\n", hobj);
@@ -1001,6 +1143,15 @@ GreSetObjectOwner(
     return TRUE;
 }
 
+BOOL
+NTAPI
+GreSetObjectOwner(
+    HGDIOBJ hobj,
+    ULONG ulOwner)
+{
+    return GreSetObjectOwnerEx(hobj, ulOwner, 0);
+}
+
 INT
 NTAPI
 GreGetObject(
@@ -1067,11 +1218,10 @@ INT
 APIENTRY
 NtGdiExtGetObjectW(
     IN HANDLE hobj,
-    IN INT cbCount,
+    IN INT cjBufferSize,
     OUT LPVOID lpBuffer)
 {
-    INT iRetCount = 0;
-    INT cbCopyCount;
+    UINT iResult, cjMaxSize;
     union
     {
         BITMAP bitmap;
@@ -1084,33 +1234,33 @@ NtGdiExtGetObjectW(
     } object;
 
     /* Normalize to the largest supported object size */
-    cbCount = min((UINT)cbCount, sizeof(object));
+    cjMaxSize = min((UINT)cjBufferSize, sizeof(object));
 
     /* Now do the actual call */
-    iRetCount = GreGetObject(hobj, cbCount, lpBuffer ? &object : NULL);
-    cbCopyCount = min((UINT)cbCount, (UINT)iRetCount);
+    iResult = GreGetObject(hobj, cjMaxSize, lpBuffer ? &object : NULL);
 
-    /* Make sure we have a buffer and a copy size */
-    if ((cbCopyCount) && (lpBuffer))
+    /* Check if we have a buffer and data */
+    if ((lpBuffer != NULL) && (iResult != 0))
     {
         /* Enter SEH for buffer transfer */
         _SEH2_TRY
         {
             /* Probe the buffer and copy it */
-            ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD));
-            RtlCopyMemory(lpBuffer, &object, cbCopyCount);
+            cjMaxSize = min(cjMaxSize, iResult);
+            ProbeForWrite(lpBuffer, cjMaxSize, sizeof(WORD));
+            RtlCopyMemory(lpBuffer, &object, cjMaxSize);
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
             /* Clear the return value.
              * Do *NOT* set last error here! */
-            iRetCount = 0;
+            iResult = 0;
         }
         _SEH2_END;
     }
 
     /* Return the count */
-    return iRetCount;
+    return iResult;
 }
 
 W32KAPI
@@ -1238,6 +1388,11 @@ GDIOBJ_AllocObjWithHandle(ULONG ObjectType, ULONG cjSize)
     }
 
     pobj = GDIOBJ_AllocateObject(objt, cjSize, fl);
+    if (!pobj)
+    {
+        return NULL;
+    }
+
     if (!GDIOBJ_hInsertObject(pobj, GDI_OBJ_HMGR_POWNED))
     {
         GDIOBJ_vFreeObject(pobj);
@@ -1341,4 +1496,5 @@ GDI_CleanupForProcess(struct _EPROCESS *Process)
     return TRUE;
 }
 
+
 /* EOF */