/*
- * 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 <w32k.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);
-#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 */ /* FIXME: -fno-unit-at-a-time breaks this */
+BOOL INTERNAL_CALL GDI_CleanupDummy(PVOID ObjectBody);
+
+/** GLOBALS *******************************************************************/
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), GDI_OBJECT_TAG_DC, DC_Cleanup}, /* 01 DC */
- {1, 0, 0, 0}, /* 02 DD_DDRAW, should be moved away from gdi objects */
- {1, 0, 0, 0}, /* 03 DD_SURFACE, should be moved away from gdi objects */
- {1, sizeof(ROSRGNDATA), GDI_OBJECT_TAG_REGION, RGNDATA_Cleanup}, /* 04 REGION */
- {1, sizeof(BITMAPOBJ), GDI_OBJECT_TAG_BITMAP, BITMAP_Cleanup}, /* 05 BITMAP */
- {0, sizeof(DC), GDI_OBJECT_TAG_CLIOBJ, GDI_CleanupDummy}, /* 06 CLIOBJ: METADC,... FIXME: don't use DC struct */
- {0, 0, GDI_OBJECT_TAG_PATH, NULL}, /* 07 PATH, unused */
- {1, sizeof(PALGDI), GDI_OBJECT_TAG_PALETTE, PALETTE_Cleanup}, /* 08 PALETTE */
- {0, 0, GDI_OBJECT_TAG_COLSPC, NULL}, /* 09 COLORSPACE, unused */
- {1, sizeof(TEXTOBJ), GDI_OBJECT_TAG_FONT, GDI_CleanupDummy}, /* 0a FONT */
- {0, 0, 0, NULL}, /* 0b RFONT, unused */
- {0, 0, 0, NULL}, /* 0c PFE, unused */
- {0, 0, 0, NULL}, /* 0d PFT, unused */
- {0, 0, 0, NULL}, /* 0e ICMCXF, unused */
- {0, 0, 0, NULL}, /* 0f ICMDLL, unused */
- {1, sizeof(GDIBRUSHOBJ), GDI_OBJECT_TAG_BRUSH, BRUSH_Cleanup}, /* 10 BRUSH, PEN, EXTPEN */
- {0, 0, 0, NULL}, /* 11 D3D_HANDLE, unused */
- {0, 0, 0, NULL}, /* 12 DD_VPORT, unused */
- {0, 0, 0, NULL}, /* 13 SPACE, unused */
- {0, 0, 0, NULL}, /* 14 DD_MOTION, unused */
- {0, 0, 0, NULL}, /* 15 META, unused */
- {0, 0, 0, NULL}, /* 16 ENUMFONT, unused */
- {0, 0, 0, NULL}, /* 17 BMFD, unused */
- {0, 0, 0, NULL}, /* 18 VTFD, unused */
- {0, 0, 0, NULL}, /* 19 TTFD, unused */
- {0, 0, 0, NULL}, /* 1a RC, unused */
- {0, 0, 0, NULL}, /* 1b TEMP, unused */
- {0, 0, 0, NULL}, /* 1c DRVOBJ, unused */
- {0, 0, 0, NULL}, /* 1d DCIOBJ, unused */
- {0, 0, 0, NULL}, /* 1e SPOOL, unused */
+ {0, 0, 0, NULL}, /* 00 reserved entry */
+ {1, sizeof(DC), TAG_DC, DC_Cleanup}, /* 01 DC */
+ {1, 0, 0, NULL}, /* 02 UNUSED1 */
+ {1, 0, 0, NULL}, /* 03 UNUSED2 */
+ {1, sizeof(ROSRGNDATA), TAG_REGION, REGION_Cleanup}, /* 04 RGN */
+ {1, sizeof(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, sizeof(GDICLRXFORM), TAG_ICMCXF, GDI_CleanupDummy}, /* 0e ICMCXF, */
+ {0, 0, TAG_SPRITE, NULL}, /* 0f SPRITE, unused */
+ {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 */
+ {0, 0, 0, NULL}, /* 14 UNUSED5 */
+ {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_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, 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 */ /* FIXME: -fno-unit-at-a-time breaks this */
+BOOL INTERNAL_CALL
+GDI_CleanupDummy(PVOID ObjectBody)
+{
+ return TRUE;
+}
/*!
* Allocate GDI object table.
PGDI_HANDLE_TABLE INTERNAL_CALL
GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject)
{
- PGDI_HANDLE_TABLE HandleTable = NULL;
- LARGE_INTEGER htSize;
- UINT ObjType;
- ULONG ViewSize = 0;
- NTSTATUS Status;
-
- ASSERT(SectionObject != NULL);
-
- htSize.QuadPart = sizeof(GDI_HANDLE_TABLE);
-
- Status = MmCreateSection((PVOID*)SectionObject,
- SECTION_ALL_ACCESS,
- NULL,
- &htSize,
- PAGE_READWRITE,
- SEC_COMMIT,
- NULL,
- NULL);
- if (!NT_SUCCESS(Status))
- return NULL;
-
- /* FIXME - use MmMapViewInSessionSpace once available! */
- Status = MmMapViewInSystemSpace(*SectionObject,
- (PVOID*)&HandleTable,
- &ViewSize);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(*SectionObject);
- *SectionObject = NULL;
- return NULL;
- }
+ PGDI_HANDLE_TABLE HandleTable = NULL;
+ LARGE_INTEGER htSize;
+ UINT ObjType;
+ ULONG ViewSize = 0;
+ NTSTATUS Status;
- RtlZeroMemory(HandleTable, sizeof(GDI_HANDLE_TABLE));
+ ASSERT(SectionObject != NULL);
- HandleTable->LookasideLists = ExAllocatePoolWithTag(NonPagedPool,
- BASE_OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST),
- TAG_GDIHNDTBLE);
- if(HandleTable->LookasideLists == NULL)
- {
- MmUnmapViewInSystemSpace(HandleTable);
- ObDereferenceObject(*SectionObject);
- *SectionObject = NULL;
- return NULL;
- }
+ htSize.QuadPart = sizeof(GDI_HANDLE_TABLE);
- for(ObjType = 0; ObjType < BASE_OBJTYPE_COUNT; ObjType++)
- {
- if (ObjTypeInfo[ObjType].bUseLookaside)
+ Status = MmCreateSection((PVOID*)SectionObject,
+ SECTION_ALL_ACCESS,
+ NULL,
+ &htSize,
+ PAGE_READWRITE,
+ SEC_COMMIT,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ return NULL;
+
+ /* FIXME - use MmMapViewInSessionSpace once available! */
+ Status = MmMapViewInSystemSpace(*SectionObject,
+ (PVOID*)&HandleTable,
+ &ViewSize);
+ if (!NT_SUCCESS(Status))
{
- ExInitializePagedLookasideList(HandleTable->LookasideLists + ObjType, NULL, NULL, 0,
- ObjTypeInfo[ObjType].ulBodySize + sizeof(GDIOBJHDR), ObjTypeInfo[ObjType].Tag, 0);
+ ObDereferenceObject(*SectionObject);
+ *SectionObject = NULL;
+ return NULL;
}
- }
-
- ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */
-
- HandleTable->FirstFree = 0;
- HandleTable->FirstUnused = RESERVE_ENTRIES_COUNT;
-
- return HandleTable;
-}
-static __inline PPAGED_LOOKASIDE_LIST
-FindLookasideList(PGDI_HANDLE_TABLE HandleTable,
- ULONG TypeIndex)
-{
- return HandleTable->LookasideLists + TypeIndex;
-}
+ RtlZeroMemory(HandleTable, sizeof(GDI_HANDLE_TABLE));
-static __inline BOOL
-RunCleanupCallback(PGDIOBJ pObj, ULONG TypeIndex)
-{
- return ((GDICLEANUPPROC)ObjTypeInfo[TypeIndex].CleanupProc)(pObj);
-}
+ HandleTable->LookasideLists = ExAllocatePoolWithTag(NonPagedPool,
+ BASE_OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST),
+ TAG_GDIHNDTBLE);
+ if (HandleTable->LookasideLists == NULL)
+ {
+ MmUnmapViewInSystemSpace(HandleTable);
+ ObDereferenceObject(*SectionObject);
+ *SectionObject = NULL;
+ return NULL;
+ }
-static __inline ULONG
-GetObjectSize(ULONG TypeIndex)
-{
- return ObjTypeInfo[TypeIndex].ulBodySize;
-}
+ for (ObjType = 0; ObjType < BASE_OBJTYPE_COUNT; ObjType++)
+ {
+ if (ObjTypeInfo[ObjType].bUseLookaside)
+ {
+ ExInitializePagedLookasideList(HandleTable->LookasideLists + ObjType,
+ NULL,
+ NULL,
+ 0,
+ ObjTypeInfo[ObjType].ulBodySize,
+ ObjTypeInfo[ObjType].Tag,
+ 0);
+ }
+ }
-#ifdef GDI_DEBUG
+ ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */
-static int leak_reported = 0;
-#define GDI_STACK_LEVELS 12
-static ULONG GDIHandleAllocator[GDI_HANDLE_COUNT][GDI_STACK_LEVELS];
-static ULONG GDIHandleLocker[GDI_HANDLE_COUNT][GDI_STACK_LEVELS];
-struct DbgOpenGDIHandle
-{
- ULONG idx;
- int count;
-};
-#define H 1024
-static struct DbgOpenGDIHandle h[H];
+ HandleTable->FirstFree = 0;
+ HandleTable->FirstUnused = RESERVE_ENTRIES_COUNT;
-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" );
+ return HandleTable;
}
-#endif /* GDI_DEBUG */
-
static void FASTCALL
LockErrorDebugOutput(HGDIOBJ hObj, PGDI_TABLE_ENTRY Entry, LPSTR Function)
{
- if (Entry->KernelData == NULL)
+ 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))
{
DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
Function, hObj, Entry->Type);
}
- KeRosDumpStackFrames(NULL, 20);
+ GDIDBG_TRACECALLER();
}
ULONG
FASTCALL
-InterlockedPopFreeEntry(PGDI_HANDLE_TABLE HandleTable)
+InterlockedPopFreeEntry(VOID)
{
- ULONG idxFirstFree, idxNextFree, idxPrev;
- PGDI_TABLE_ENTRY pFreeEntry;
-
- DPRINT("Enter InterLockedPopFreeEntry\n");
-
- do
- {
- idxFirstFree = HandleTable->FirstFree;
- if (idxFirstFree)
- {
- pFreeEntry = HandleTable->Entries + idxFirstFree;
- ASSERT(((ULONG)pFreeEntry->KernelData & ~GDI_HANDLE_INDEX_MASK) == 0);
- idxNextFree = (ULONG)pFreeEntry->KernelData;
- idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&HandleTable->FirstFree, idxNextFree, idxFirstFree);
- }
- else
- {
- idxFirstFree = HandleTable->FirstUnused;
- idxNextFree = idxFirstFree + 1;
- if (idxNextFree >= GDI_HANDLE_COUNT)
- {
- DPRINT1("No more gdi handles left!\n");
- return 0;
- }
- idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&HandleTable->FirstUnused, idxNextFree, idxFirstFree);
- }
- }
- while (idxPrev != idxFirstFree);
-
- return idxFirstFree;
+ ULONG idxFirst, idxNext, idxPrev;
+ PGDI_TABLE_ENTRY pEntry;
+ DWORD PrevProcId;
+
+ DPRINT("Enter InterLockedPopFreeEntry\n");
+
+ while (TRUE)
+ {
+ idxFirst = GdiHandleTable->FirstFree;
+
+ if (!idxFirst)
+ {
+ /* 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;
+ }
+
+ /* 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;
+ }
+ }
+
+ return idxFirst;
}
/* Pushes an entry of the handle table to the free list,
The entry must be unlocked and the base type field must be 0 */
VOID
FASTCALL
-InterlockedPushFreeEntry(PGDI_HANDLE_TABLE HandleTable, ULONG idxToFree)
+InterlockedPushFreeEntry(ULONG idxToFree)
{
- ULONG idxFirstFree, idxPrev;
- PGDI_TABLE_ENTRY pFreeEntry;
+ ULONG idxFirstFree, idxPrev;
+ PGDI_TABLE_ENTRY pFreeEntry;
- DPRINT("Enter InterlockedPushFreeEntry\n");
+ DPRINT("Enter InterlockedPushFreeEntry\n");
- pFreeEntry = HandleTable->Entries + idxToFree;
- ASSERT((pFreeEntry->Type & GDI_ENTRY_BASETYPE_MASK) == 0);
- ASSERT(pFreeEntry->ProcessId == 0);
- pFreeEntry->UserData = NULL;
+ pFreeEntry = GdiHandleTable->Entries + idxToFree;
+ ASSERT((pFreeEntry->Type & GDI_ENTRY_BASETYPE_MASK) == 0);
+ ASSERT(pFreeEntry->ProcessId == 0);
+ pFreeEntry->UserData = NULL;
- do
- {
- idxFirstFree = HandleTable->FirstFree;
- pFreeEntry->KernelData = (PVOID)idxFirstFree;
+ do
+ {
+ idxFirstFree = GdiHandleTable->FirstFree;
+ pFreeEntry->KernelData = (PVOID)(ULONG_PTR)idxFirstFree;
- idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&HandleTable->FirstFree, idxToFree, idxFirstFree);
- }
- while (idxPrev != idxFirstFree);
+ idxPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree,
+ idxToFree,
+ idxFirstFree);
+ }
+ while (idxPrev != idxFirstFree);
}
INTERNAL_CALL
GDIOBJ_ValidateHandle(HGDIOBJ hObj, ULONG ObjectType)
{
- PGDI_TABLE_ENTRY Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
- if((((ULONG_PTR)hObj & GDI_HANDLE_TYPE_MASK) == ObjectType) &&
- (Entry->Type << GDI_ENTRY_UPPER_SHIFT) == GDI_HANDLE_GET_UPPER(hObj))
- {
- HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
- if(pid == NULL || pid == PsGetCurrentProcessId())
+ PGDI_TABLE_ENTRY Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
+ if ((((ULONG_PTR)hObj & GDI_HANDLE_TYPE_MASK) == ObjectType) &&
+ (Entry->Type << GDI_ENTRY_UPPER_SHIFT) == GDI_HANDLE_GET_UPPER(hObj))
{
- return TRUE;
+ HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
+ if (pid == NULL || pid == PsGetCurrentProcessId())
+ {
+ return TRUE;
+ }
}
- }
- return FALSE;
+ 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(PGDI_HANDLE_TABLE HandleTable, ULONG ObjectType)
+POBJ INTERNAL_CALL
+GDIOBJ_AllocObjWithHandle(ULONG ObjectType)
{
- PW32PROCESS W32Process;
- PGDIOBJHDR newObject = NULL;
- PPAGED_LOOKASIDE_LIST LookasideList = NULL;
- HANDLE CurrentProcessId, LockedProcessId;
- ULONG TypeIndex;
-#ifdef GDI_DEBUG
- ULONG Attempts = 0;
-#endif
+ PPROCESSINFO W32Process;
+ POBJ newObject = NULL;
+ HANDLE CurrentProcessId, LockedProcessId;
+ UCHAR TypeIndex;
+ UINT Index;
+ PGDI_TABLE_ENTRY Entry;
+ LONG TypeInfo;
- 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 )
- return NULL;
+ 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->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);
+ ASSERT(ObjectType != GDI_OBJECT_TYPE_DONTCARE);
- TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(ObjectType);
- if (ObjTypeInfo[TypeIndex].bUseLookaside)
- {
- LookasideList = FindLookasideList(HandleTable, TypeIndex);
- if(LookasideList != NULL)
+ TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(ObjectType);
+
+ newObject = GDIOBJ_AllocObj(TypeIndex);
+ if (!newObject)
{
- newObject = ExAllocateFromPagedLookasideList(LookasideList);
+ DPRINT1("Not enough memory to allocate gdi object!\n");
+ return NULL;
}
- }
- else
- {
- newObject = ExAllocatePoolWithTag(PagedPool,
- ObjTypeInfo[TypeIndex].ulBodySize + sizeof(GDIOBJHDR),
- ObjTypeInfo[TypeIndex].Tag);
- }
- if(newObject != NULL)
- {
- UINT Index;
- PGDI_TABLE_ENTRY Entry;
- PGDIOBJ ObjectBody;
- LONG TypeInfo;
CurrentProcessId = PsGetCurrentProcessId();
LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1);
- newObject->LockingThread = NULL;
- newObject->Locks = 0;
-
- ObjectBody = GDIHdrToBdy(newObject);
-
- RtlZeroMemory(ObjectBody, 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);
- Index = InterlockedPopFreeEntry(HandleTable);
+ Index = InterlockedPopFreeEntry();
if (Index != 0)
{
- HANDLE PrevProcId;
+ HANDLE PrevProcId;
- Entry = &HandleTable->Entries[Index];
+ Entry = &GdiHandleTable->Entries[Index];
LockHandle:
- PrevProcId = InterlockedCompareExchangePointer(&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 = ObjectBody;
+ 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(&Entry->ProcessId, CurrentProcessId);
+ /* Create a handle */
+ Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT));
-#ifdef GDI_DEBUG
- memset ( GDIHandleAllocator[Index], 0x00, GDI_STACK_LEVELS * sizeof(ULONG) );
- RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleAllocator[Index], NULL);
-#endif /* GDI_DEBUG */
+ /* 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, ObjectBody);
- return Handle;
- }
- else
- {
-#ifdef GDI_DEBUG
- if(++Attempts > 20)
+ /* unlock the entry */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId);
+
+ GDIDBG_CAPTUREALLOCATOR(Index);
+
+ if (W32Process != NULL)
+ {
+ InterlockedIncrement(&W32Process->GDIHandleCount);
+ }
+
+ DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, newObject);
+ return newObject;
+ }
+ else
{
- DPRINT1("[%d]Waiting on handle in index 0x%x\n", Attempts, Index);
+ 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;
}
-#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;
- }
}
- if (ObjTypeInfo[TypeIndex].bUseLookaside)
+ 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)
{
- ExFreeToPagedLookasideList(LookasideList, newObject);
+ PPAGED_LOOKASIDE_LIST LookasideList;
+
+ LookasideList = GdiHandleTable->LookasideLists + BaseType;
+ ExFreeToPagedLookasideList(LookasideList, pObject);
}
else
{
- ExFreePool(newObject);
+ ExFreePool(pObject);
}
- DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
-#ifdef GDI_DEBUG
- IntDumpHandleTable(HandleTable);
-#endif /* GDI_DEBUG */
- }
- else
- {
- DPRINT1("Not enough memory to allocate gdi object!\n");
- }
- return NULL;
}
/*!
* \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(PGDI_HANDLE_TABLE HandleTable, 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
+ PGDI_TABLE_ENTRY Entry;
+ HANDLE ProcessId, LockedProcessId, PrevProcId;
+ ULONG HandleType, HandleUpper, TypeIndex;
+ BOOL Silent;
- DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj);
+ GDIDBG_INITLOOPTRACE();
- if(GDI_HANDLE_IS_STOCKOBJ(hObj))
- {
- DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj);
-#ifdef GDI_DEBUG
- DPRINT1("-> called from:\n");
- KeRosDumpStackFrames(NULL, 20);
-#endif
- return FALSE;
- }
+ DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj);
- ProcessId = PsGetCurrentProcessId();
- LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
+ if (GDI_HANDLE_IS_STOCKOBJ(hObj))
+ {
+ DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj);
+ GDIDBG_TRACECALLER();
+ return FALSE;
+ }
- Silent = (ExpectedType & GDI_OBJECT_TYPE_SILENT);
- ExpectedType &= ~GDI_OBJECT_TYPE_SILENT;
+ ProcessId = PsGetCurrentProcessId();
+ LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
- HandleType = GDI_HANDLE_GET_TYPE(hObj);
- HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
+ Silent = (ExpectedType & GDI_OBJECT_TYPE_SILENT);
+ ExpectedType &= ~GDI_OBJECT_TYPE_SILENT;
- /* Check if we have the requested type */
- if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
- HandleType != ExpectedType) ||
- HandleType == 0 )
- {
- DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
- hObj, HandleType, ExpectedType);
- return FALSE;
- }
+ HandleType = GDI_HANDLE_GET_TYPE(hObj);
+ HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
+
+ /* Check if we have the requested type */
+ if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
+ HandleType != ExpectedType) ||
+ HandleType == 0 )
+ {
+ DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
+ hObj, HandleType, ExpectedType);
+ GDIDBG_TRACECALLER();
+ return FALSE;
+ }
- Entry = GDI_HANDLE_GET_ENTRY(HandleTable, hObj);
+ Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
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(&Entry->ProcessId, LockedProcessId, ProcessId);
- if(PrevProcId == ProcessId)
- {
- if( (Entry->KernelData != NULL) &&
- ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) &&
- ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == (HandleUpper & GDI_ENTRY_BASETYPE_MASK)) )
+ /* 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);
+ if (PrevProcId == ProcessId)
{
- PGDIOBJHDR GdiHdr;
+ if ( (Entry->KernelData != NULL) &&
+ ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) &&
+ ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == (HandleUpper & GDI_ENTRY_BASETYPE_MASK)) )
+ {
+ POBJ Object;
+
+ Object = Entry->KernelData;
- GdiHdr = GDIBdyToHdr(Entry->KernelData);
+ if ((Object->cExclusiveLock == 0 ||
+ Object->Tid == (PTHREADINFO)PsGetCurrentThreadWin32Thread()) &&
+ Object->ulShareCount == 0)
+ {
+ BOOL Ret;
+ PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process();
- if(GdiHdr->Locks == 0)
- {
- BOOL Ret;
- PW32PROCESS 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;
- /* 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);
- /* unlock the handle slot */
- (void)InterlockedExchangePointer(&Entry->ProcessId, NULL);
+ /* push this entry to the free list */
+ InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable, Entry));
- /* push this entry to the free list */
- InterlockedPushFreeEntry(HandleTable, GDI_ENTRY_TO_INDEX(HandleTable, Entry));
+ Object->hHmgr = NULL;
- if(W32Process != NULL)
- {
- InterlockedDecrement(&W32Process->GDIObjects);
- }
+ if (W32Process != NULL)
+ {
+ InterlockedDecrement(&W32Process->GDIHandleCount);
+ }
- /* call the cleanup routine. */
- TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(HandleType);
- Ret = RunCleanupCallback(GDIHdrToBdy(GdiHdr), TypeIndex);
+ /* call the cleanup routine. */
+ TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(HandleType);
+ Ret = ObjTypeInfo[TypeIndex].CleanupProc(Object);
- /* Now it's time to free the memory */
- if (ObjTypeInfo[TypeIndex].bUseLookaside)
- {
- LookasideList = FindLookasideList(HandleTable, TypeIndex);
- if(LookasideList != NULL)
- {
- ExFreeToPagedLookasideList(LookasideList, GdiHdr);
- }
+ DeAllocTypeDataDump(HandleType);
+
+ /* Now it's time to free the memory */
+ GDIOBJ_FreeObj(Object, TypeIndex);
+
+ GDIDBG_CAPTUREDELETER(hObj);
+ return Ret;
+ }
+ else if (Object->ulShareCount != 0)
+ {
+ Object->BaseFlags |= BASEFLAG_READY_TO_DIE;
+ DPRINT("Object %p, ulShareCount = %d\n", Object->hHmgr, Object->ulShareCount);
+ //GDIDBG_TRACECALLER();
+ //GDIDBG_TRACESHARELOCKER(GDI_HANDLE_GET_INDEX(hObj));
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+ /* Don't wait on shared locks */
+ return FALSE;
+ }
+ else
+ {
+ /*
+ * The object is currently locked by another thread, so freeing is forbidden!
+ */
+ DPRINT1("Object->cExclusiveLock = %d\n", Object->cExclusiveLock);
+ GDIDBG_TRACECALLER();
+ GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj));
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+ /* do not assert here for it will call again from dxg.sys it being call twice */
+
+ DelayExecution();
+ goto LockHandle;
+ }
}
else
{
- ExFreePool(GdiHdr);
+ LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj");
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
}
+ }
+ else if (PrevProcId == LockedProcessId)
+ {
+ GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
- return Ret;
- }
- else
- {
- /*
- * The object is currently locked, so freeing is forbidden!
- */
- DPRINT1("GdiHdr->Locks: %d\n", GdiHdr->Locks);
-#ifdef GDI_DEBUG
-// DPRINT1("Locked from:\n");
-// KeRosDumpStackFrames(GDIHandleLocker[GDI_HANDLE_GET_INDEX(hObj)], GDI_STACK_LEVELS);
-#endif
- ASSERT(FALSE);
- }
+ /* the object is currently locked, wait some time and try again.
+ FIXME - we shouldn't loop forever! Give up after some time! */
+ DelayExecution();
+ /* try again */
+ goto LockHandle;
}
else
{
- LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj");
- (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
+ if (!Silent)
+ {
+ 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);
+ }
+ 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));
+ }
}
- }
- else if(PrevProcId == LockedProcessId)
- {
-#ifdef GDI_DEBUG
- if(++Attempts > 20)
- {
- DPRINT1("[%d]Waiting on 0x%x\n", Attempts, hObj);
- }
-#endif
- /* the object is currently locked, wait some time and try again.
- FIXME - we shouldn't loop forever! Give up after some time! */
- DelayExecution();
- /* try again */
- goto LockHandle;
- }
- else
- {
- if(!Silent)
- {
- 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);
- }
-#ifdef GDI_DEBUG
- DPRINT1("-> called from:\n");
- KeRosDumpStackFrames(NULL, 20);
-// DPRINT1("Allocated from:\n");
-// KeRosDumpStackFrames(GDIHandleAllocator[GDI_HANDLE_GET_INDEX(hObj)], GDI_STACK_LEVELS);
-#endif
- }
- }
- return FALSE;
+ return FALSE;
}
BOOL
FASTCALL
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)
- return FALSE;
- else
+ 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_BASETYPE_MASK) != 0)
+ return FALSE;
+ else
+ {
+ DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject);
+ return TRUE; // return true and move on.
+ }
+}
+
+
+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)
{
- DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject);
- return TRUE; // return true and move on.
+ 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
*/
BOOL
FASTCALL
-NtGdiDeleteObject(HGDIOBJ hObject)
+GreDeleteObject(HGDIOBJ hObject)
{
- DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
- if(!IsObjectDead(hObject))
- {
- return NULL != hObject
- ? GDIOBJ_FreeObj(GdiHandleTable, hObject, GDI_OBJECT_TYPE_DONTCARE) : FALSE;
- }
- else
- {
- DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject);
- return TRUE; // return true and move on.
- }
+ INT Index;
+ PGDI_TABLE_ENTRY Entry;
+ DWORD dwObjectType;
+ PVOID pAttr = NULL;
+
+ DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
+ if (!IsObjectDead(hObject))
+ {
+ 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
+ {
+ DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject);
+ return TRUE; // return true and move on.
+ }
}
+VOID
+FASTCALL
+IntDeleteHandlesForProcess(struct _EPROCESS *Process, ULONG ObjectType)
+{
+ PGDI_TABLE_ENTRY Entry, End;
+ ULONG Index = RESERVE_ENTRIES_COUNT;
+ HANDLE ProcId;
+ PPROCESSINFO W32Process;
+
+ W32Process = (PPROCESSINFO)Process->Win32Process;
+ ASSERT(W32Process);
+
+ if (W32Process->GDIHandleCount > 0)
+ {
+ 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++)
+ {
+ /* ignore the lock bit */
+ if ( (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId)
+ {
+ 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));
+
+ 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 (PGDI_HANDLE_TABLE HandleTable, struct _EPROCESS *Process)
+GDI_CleanupForProcess(struct _EPROCESS *Process)
{
- PGDI_TABLE_ENTRY Entry, End;
- PEPROCESS CurrentProcess;
- PW32PROCESS W32Process;
- HANDLE ProcId;
- ULONG Index = RESERVE_ENTRIES_COUNT;
-
- DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId);
- CurrentProcess = PsGetCurrentProcess();
- if (CurrentProcess != Process)
+ PEPROCESS CurrentProcess;
+ PPROCESSINFO W32Process;
+
+ DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId);
+ CurrentProcess = PsGetCurrentProcess();
+ if (CurrentProcess != Process)
{
- KeAttachProcess(&Process->Pcb);
+ KeAttachProcess(&Process->Pcb);
}
- W32Process = (PW32PROCESS)Process->Win32Process;
- ASSERT(W32Process);
- if(W32Process->GDIObjects > 0)
- {
- /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
- we should delete it directly here! */
- ProcId = Process->UniqueProcessId;
+ 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);
- End = &HandleTable->Entries[GDI_HANDLE_COUNT];
- for(Entry = &HandleTable->Entries[RESERVE_ENTRIES_COUNT];
- Entry != End;
- Entry++, Index++)
+ /* Finally finish with what's left */
+ IntDeleteHandlesForProcess(Process, GDI_OBJECT_TYPE_DONTCARE);
+
+ if (CurrentProcess != Process)
{
- /* ignore the lock bit */
- if((HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId && (Entry->Type & ~GDI_ENTRY_REUSE_MASK) != 0)
- {
- 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));
-
- if(GDIOBJ_FreeObj(HandleTable, ObjectHandle, GDI_OBJECT_TYPE_DONTCARE) &&
- W32Process->GDIObjects == 0)
- {
- /* there are no more gdi handles for this process, bail */
- break;
- }
- }
+ KeDetachProcess();
}
- }
- if (CurrentProcess != Process)
+#ifdef GDI_DEBUG
+ GdiDbgHTIntegrityCheck();
+#endif
+
+ DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);
+ if (W32Process->GDIHandleCount > 0)
{
- KeDetachProcess();
+ DPRINT1("Leaking %d handles!\n", W32Process->GDIHandleCount);
}
- DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);
-
- return TRUE;
+ return TRUE;
}
/*!
* \todo Get rid of the ExpectedType parameter!
*/
PGDIOBJ INTERNAL_CALL
-GDIOBJ_LockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
+GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
{
- ULONG HandleIndex;
- PGDI_TABLE_ENTRY Entry;
- HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
- PGDIOBJ Object = NULL;
- ULONG HandleType, HandleUpper;
-
- 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)
- return NULL;
-
- Entry = &HandleTable->Entries[HandleIndex];
-
- /* Check if we have the requested type */
- if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
- HandleType != ExpectedType) ||
- HandleType == 0 )
- {
- DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
- hObj, HandleType, ExpectedType);
-#ifdef GDI_DEBUG
- KeRosDumpStackFrames(NULL, 20);
-// DPRINT1("Allocated from:\n");
-// KeRosDumpStackFrames(GDIHandleAllocator[GDI_HANDLE_GET_INDEX(hObj)], GDI_STACK_LEVELS);
-#endif
- return NULL;
- }
-
- ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
- HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
-
- /* Check for invalid owner. */
- if (ProcessId != HandleProcessId && HandleProcessId != NULL)
- {
- return NULL;
- }
-
- /*
- * Prevent the thread from being terminated during the locking process.
- * It would result in undesired effects and inconsistency of the global
- * handle table.
- */
-
- KeEnterCriticalRegion();
-
- /*
- * Loop until we either successfully lock the handle entry & object or
- * fail some of the check.
- */
-
- for (;;)
- {
- /* Lock the handle table entry. */
- LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
- PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId,
- LockedProcessId,
- HandleProcessId);
-
- if (PrevProcId == HandleProcessId)
- {
- /*
- * We're locking an object that belongs to our process or it's a
- * global object if HandleProcessId is 0 here.
- */
-
- if ( (Entry->KernelData != NULL) &&
- ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
- {
- PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
- PETHREAD Thread = PsGetCurrentThread();
-
- if (GdiHdr->Locks == 0)
+ ULONG HandleIndex;
+ PGDI_TABLE_ENTRY Entry;
+ HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
+ POBJ Object = NULL;
+ ULONG HandleType, HandleUpper;
+
+ 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)
+ return NULL;
+
+ Entry = &GdiHandleTable->Entries[HandleIndex];
+
+ /* Check if we have the requested type */
+ if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
+ HandleType != ExpectedType) ||
+ HandleType == 0 )
+ {
+ 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);
+ GDIDBG_TRACEDELETER(hObj);
+ return NULL;
+ }
+
+ 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.
+ * It would result in undesired effects and inconsistency of the global
+ * handle table.
+ */
+
+ KeEnterCriticalRegion();
+
+ /*
+ * Loop until we either successfully lock the handle entry & object or
+ * fail some of the check.
+ */
+
+ for (;;)
+ {
+ /* Lock the handle table entry. */
+ LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
+ LockedProcessId,
+ HandleProcessId);
+
+ if (PrevProcId == HandleProcessId)
+ {
+ /*
+ * We're locking an object that belongs to our process or it's a
+ * global object if HandleProcessId is 0 here.
+ */
+
+ if ( (Entry->KernelData != NULL) &&
+ ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
{
- GdiHdr->LockingThread = Thread;
- GdiHdr->Locks = 1;
-#ifdef GDI_DEBUG
- memset(GDIHandleLocker[GDI_HANDLE_GET_INDEX(hObj)], 0x00, GDI_STACK_LEVELS * sizeof(ULONG));
- RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleLocker[GDI_HANDLE_GET_INDEX(hObj)], NULL);
-#endif
- Object = Entry->KernelData;
+ PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
+ Object = Entry->KernelData;
+
+ if (Object->cExclusiveLock == 0)
+ {
+ Object->Tid = Thread;
+ Object->cExclusiveLock = 1;
+ GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj))
+ }
+ else
+ {
+ if (Object->Tid != Thread)
+ {
+ /* Unlock the handle table entry. */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+
+ DelayExecution();
+ continue;
+ }
+ InterlockedIncrement((PLONG)&Object->cExclusiveLock);
+ }
}
else
{
- InterlockedIncrement((PLONG)&GdiHdr->Locks);
- if (GdiHdr->LockingThread != Thread)
- {
- InterlockedDecrement((PLONG)&GdiHdr->Locks);
-
- /* Unlock the handle table entry. */
- (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
-
- DelayExecution();
- continue;
- }
- Object = Entry->KernelData;
+ /*
+ * Debugging code. Report attempts to lock deleted handles and
+ * locking type mismatches.
+ */
+ LockErrorDebugOutput(hObj, Entry, "GDIOBJ_LockObj");
}
- }
- else
- {
- /*
- * Debugging code. Report attempts to lock deleted handles and
- * locking type mismatches.
- */
- LockErrorDebugOutput(hObj, Entry, "GDIOBJ_LockObj");
-
-#ifdef GDI_DEBUG
- DPRINT1("-> called from:\n");
- KeRosDumpStackFrames(NULL, 20);
-#endif
- }
- /* Unlock the handle table entry. */
- (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
+ /* Unlock the handle table entry. */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
- break;
- }
- else
- {
- /*
- * The handle is currently locked, wait some time and try again.
- */
+ break;
+ }
+ else
+ {
+ /*
+ * The handle is currently locked, wait some time and try again.
+ */
- DelayExecution();
- continue;
- }
- }
+ DelayExecution();
+ continue;
+ }
+ }
- KeLeaveCriticalRegion();
+ KeLeaveCriticalRegion();
- return Object;
+ return Object;
}
* \todo Get rid of the ExpectedType parameter!
*/
PGDIOBJ INTERNAL_CALL
-GDIOBJ_ShareLockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
+GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
{
- ULONG HandleIndex;
- PGDI_TABLE_ENTRY Entry;
- HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
- PGDIOBJ Object = NULL;
- ULONG_PTR HandleType, HandleUpper;
-
- 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)
- return NULL;
-
- /* Check if we have the requested type */
- if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
- HandleType != ExpectedType) ||
- HandleType == 0 )
- {
- DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
- hObj, HandleType, ExpectedType);
- return NULL;
- }
-
- Entry = &HandleTable->Entries[HandleIndex];
-
- ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
- HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
-
- /* Check for invalid owner. */
- if (ProcessId != HandleProcessId && HandleProcessId != NULL)
- {
- return NULL;
- }
-
- /*
- * Prevent the thread from being terminated during the locking process.
- * It would result in undesired effects and inconsistency of the global
- * handle table.
- */
-
- KeEnterCriticalRegion();
-
- /*
- * Loop until we either successfully lock the handle entry & object or
- * fail some of the check.
- */
-
- for (;;)
- {
- /* Lock the handle table entry. */
- LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
- PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId,
- LockedProcessId,
- HandleProcessId);
-
- if (PrevProcId == HandleProcessId)
- {
- /*
- * We're locking an object that belongs to our process or it's a
- * global object if HandleProcessId is 0 here.
- */
-
- if ( (Entry->KernelData != NULL) &&
- (HandleUpper == (Entry->Type << GDI_ENTRY_UPPER_SHIFT)) )
- {
- PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
+ ULONG HandleIndex;
+ PGDI_TABLE_ENTRY Entry;
+ HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
+ POBJ Object = NULL;
+ ULONG_PTR HandleType, HandleUpper;
-#ifdef GDI_DEBUG
- if (InterlockedIncrement((PLONG)&GdiHdr->Locks) == 1)
- {
- memset(GDIHandleLocker[HandleIndex], 0x00, GDI_STACK_LEVELS * sizeof(ULONG));
- RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleLocker[HandleIndex], NULL);
- }
-#else
- InterlockedIncrement((PLONG)&GdiHdr->Locks);
-#endif
- Object = Entry->KernelData;
- }
- else
- {
- /*
- * Debugging code. Report attempts to lock deleted handles and
- * locking type mismatches.
- */
- LockErrorDebugOutput(hObj, Entry, "GDIOBJ_ShareLockObj");
+ HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
+ HandleType = GDI_HANDLE_GET_TYPE(hObj);
+ HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
-#ifdef GDI_DEBUG
- DPRINT1("-> called from:\n");
- KeRosDumpStackFrames(NULL, 20);
-#endif
- }
+ /* Check that the handle index is valid. */
+ if (HandleIndex >= GDI_HANDLE_COUNT)
+ return NULL;
- /* Unlock the handle table entry. */
- (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
+ /* Check if we have the requested type */
+ if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
+ HandleType != ExpectedType) ||
+ HandleType == 0 )
+ {
+ DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
+ hObj, HandleType, ExpectedType);
+ return NULL;
+ }
- break;
- }
- else
- {
- /*
- * The handle is currently locked, wait some time and try again.
- */
+ Entry = &GdiHandleTable->Entries[HandleIndex];
- DelayExecution();
- continue;
- }
- }
+ ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
+ HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
- KeLeaveCriticalRegion();
+ /* Check for invalid owner. */
+ if (ProcessId != HandleProcessId && HandleProcessId != NULL)
+ {
+ return NULL;
+ }
- return Object;
-}
+ /*
+ * Prevent the thread from being terminated during the locking process.
+ * It would result in undesired effects and inconsistency of the global
+ * handle table.
+ */
+ KeEnterCriticalRegion();
-/*!
- * 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.
+ /*
+ * Loop until we either successfully lock the handle entry & object or
+ * fail some of the check.
+ */
- * \param Object Object pointer (as returned by GDIOBJ_LockObj).
- */
-VOID INTERNAL_CALL
-GDIOBJ_UnlockObjByPtr(PGDI_HANDLE_TABLE HandleTable, PGDIOBJ Object)
-{
- PGDIOBJHDR GdiHdr = GDIBdyToHdr(Object);
-#ifdef GDI_DEBUG
- if (InterlockedDecrement((PLONG)&GdiHdr->Locks) == 0)
- {
- memset(GDIHandleLocker[GDI_HANDLE_GET_INDEX(Object)], 0x00, GDI_STACK_LEVELS * sizeof(ULONG));
- RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleLocker[GDI_HANDLE_GET_INDEX(Object)], NULL);
- }
+ for (;;)
+ {
+ /* Lock the handle table entry. */
+ LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
+ LockedProcessId,
+ HandleProcessId);
+
+ if (PrevProcId == HandleProcessId)
+ {
+ /*
+ * We're locking an object that belongs to our process or it's a
+ * global object if HandleProcessId is 0 here.
+ */
+
+ if ( (Entry->KernelData != NULL) &&
+ (HandleUpper == (Entry->Type << GDI_ENTRY_UPPER_SHIFT)) )
+ {
+ Object = (POBJ)Entry->KernelData;
+
+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*)GDIHandleShareLocker[HandleIndex], NULL);
+ }
#else
- if (InterlockedDecrement((PLONG)&GdiHdr->Locks) < 0)
- DPRINT1("Trying to unlock non-existant object\n");
+ InterlockedIncrement((PLONG)&Object->ulShareCount);
#endif
+ }
+ else
+ {
+ /*
+ * Debugging code. Report attempts to lock deleted handles and
+ * locking type mismatches.
+ */
+ LockErrorDebugOutput(hObj, Entry, "GDIOBJ_ShareLockObj");
+ }
+
+ /* Unlock the handle table entry. */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+
+ break;
+ }
+ else
+ {
+ /*
+ * The handle is currently locked, wait some time and try again.
+ */
+
+ DelayExecution();
+ continue;
+ }
+ }
+
+ KeLeaveCriticalRegion();
+
+ return Object;
}
BOOL INTERNAL_CALL
-GDIOBJ_OwnedByCurrentProcess(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ ObjectHandle)
+GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle)
{
- PGDI_TABLE_ENTRY Entry;
- HANDLE ProcessId;
- BOOL Ret;
+ PGDI_TABLE_ENTRY Entry;
+ HANDLE ProcessId;
+ BOOL Ret;
- DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
+ DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
- if(!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
- {
- ProcessId = PsGetCurrentProcessId();
+ if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
+ {
+ ProcessId = PsGetCurrentProcessId();
- Entry = GDI_HANDLE_GET_ENTRY(HandleTable, ObjectHandle);
- Ret = Entry->KernelData != NULL &&
- (Entry->Type & ~GDI_ENTRY_REUSE_MASK) != 0 &&
- (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcessId;
+ Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
+ Ret = Entry->KernelData != NULL &&
+ (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
+ (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcessId;
- return Ret;
- }
+ return Ret;
+ }
- return FALSE;
+ return FALSE;
}
BOOL INTERNAL_CALL
-GDIOBJ_ConvertToStockObj(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ *phObj)
+GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
{
-/*
- * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
- * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
- */
- PGDI_TABLE_ENTRY Entry;
- HANDLE ProcessId, LockedProcessId, PrevProcId;
- PETHREAD Thread;
- HGDIOBJ hObj;
-#ifdef GDI_DEBUG
- ULONG Attempts = 0;
-#endif
+ /*
+ * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
+ * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
+ */
+ PGDI_TABLE_ENTRY Entry;
+ HANDLE ProcessId, LockedProcessId, PrevProcId;
+ PTHREADINFO Thread;
+ HGDIOBJ hObj;
- ASSERT(phObj);
- hObj = *phObj;
+ GDIDBG_INITLOOPTRACE();
- DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj);
+ ASSERT(phObj);
+ hObj = *phObj;
- Thread = PsGetCurrentThread();
+ DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj);
- if(!GDI_HANDLE_IS_STOCKOBJ(hObj))
- {
- ProcessId = PsGetCurrentProcessId();
- LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
+ Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
+
+ if (!GDI_HANDLE_IS_STOCKOBJ(hObj))
+ {
+ ProcessId = PsGetCurrentProcessId();
+ LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
- Entry = GDI_HANDLE_GET_ENTRY(HandleTable, hObj);
+ Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
LockHandle:
- /* lock the object, we must not convert stock objects, so don't check!!! */
- PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, ProcessId);
- if(PrevProcId == ProcessId)
- {
- LONG NewType, PrevType, OldType;
-
- /* we're locking an object that belongs to our process. First calculate
- the new object type including the stock object flag and then try to
- exchange it.*/
- /* 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) */
- OldType = ((ULONG)hObj & GDI_HANDLE_BASETYPE_MASK) | ((ULONG)hObj >> GDI_ENTRY_UPPER_SHIFT);
- /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
- we copy them as we can't get them from the handle */
- OldType |= Entry->Type & GDI_ENTRY_FLAGS_MASK;
-
- /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
- 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);
- if(PrevType == OldType && Entry->KernelData != NULL)
- {
- PETHREAD PrevThread;
- PGDIOBJHDR GdiHdr;
-
- /* We successfully set the stock object flag.
- KernelData should never be NULL here!!! */
- ASSERT(Entry->KernelData);
-
- GdiHdr = GDIBdyToHdr(Entry->KernelData);
-
- PrevThread = GdiHdr->LockingThread;
- if(GdiHdr->Locks == 0 || PrevThread == Thread)
+ /* lock the object, we must not convert stock objects, so don't check!!! */
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
+ if (PrevProcId == ProcessId)
{
- /* dereference the process' object counter */
- if(PrevProcId != GDI_GLOBAL_PROCESS)
- {
- PEPROCESS OldProcess;
- PW32PROCESS W32Process;
- NTSTATUS Status;
-
- /* FIXME */
- Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
- if(NT_SUCCESS(Status))
+ LONG NewType, PrevType, OldType;
+
+ /* we're locking an object that belongs to our process. First calculate
+ the new object type including the stock object flag and then try to
+ exchange it.*/
+ /* 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) */
+ OldType = ((ULONG)hObj & GDI_HANDLE_BASETYPE_MASK) | ((ULONG)hObj >> GDI_ENTRY_UPPER_SHIFT);
+ /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
+ we copy them as we can't get them from the handle */
+ OldType |= Entry->Type & GDI_ENTRY_FLAGS_MASK;
+
+ /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
+ 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);
+ if (PrevType == OldType && Entry->KernelData != NULL)
{
- W32Process = (PW32PROCESS)OldProcess->Win32Process;
- if(W32Process != NULL)
- {
- InterlockedDecrement(&W32Process->GDIObjects);
- }
- ObDereferenceObject(OldProcess);
+ PTHREADINFO PrevThread;
+ POBJ Object;
+
+ /* We successfully set the stock object flag.
+ KernelData should never be NULL here!!! */
+ ASSERT(Entry->KernelData);
+
+ Object = Entry->KernelData;
+
+ PrevThread = Object->Tid;
+ if (Object->cExclusiveLock == 0 || PrevThread == Thread)
+ {
+ /* dereference the process' object counter */
+ if (PrevProcId != GDI_GLOBAL_PROCESS)
+ {
+ PEPROCESS OldProcess;
+ PPROCESSINFO W32Process;
+ NTSTATUS Status;
+
+ /* FIXME */
+ Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
+ if (NT_SUCCESS(Status))
+ {
+ W32Process = (PPROCESSINFO)OldProcess->Win32Process;
+ if (W32Process != NULL)
+ {
+ InterlockedDecrement(&W32Process->GDIHandleCount);
+ }
+ ObDereferenceObject(OldProcess);
+ }
+ }
+
+ 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
+ {
+ 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);
+
+ DelayExecution();
+ goto LockHandle;
+ }
}
- }
-
- /* remove the process id lock and make it global */
- (void)InterlockedExchangePointer(&Entry->ProcessId, GDI_GLOBAL_PROCESS);
-
- hObj = (HGDIOBJ)((ULONG)(hObj) | GDI_HANDLE_STOCK_MASK);
- *phObj = hObj;
+ else
+ {
+ DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj);
+ DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType, Entry->Type, NewType, Entry->KernelData);
+ }
+ }
+ else if (PrevProcId == LockedProcessId)
+ {
+ GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
- /* we're done, successfully converted the object */
- return TRUE;
+ /* the object is currently locked, wait some time and try again.
+ FIXME - we shouldn't loop forever! Give up after some time! */
+ DelayExecution();
+ /* try again */
+ goto LockHandle;
}
else
{
-#ifdef GDI_DEBUG
- if(++Attempts > 20)
- {
- if(GdiHdr->lockfile != NULL)
- {
- DPRINT1("[%d]Locked by 0x%x (we're 0x%x)\n", Attempts, PrevThread, Thread);
- }
- }
-#endif
- /* 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(&Entry->ProcessId, PrevProcId);
-
- DelayExecution();
- goto LockHandle;
+ DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj);
}
- }
- else
- {
- DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj);
- DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType, Entry->Type, NewType, Entry->KernelData);
- }
- }
- else if(PrevProcId == LockedProcessId)
- {
-#ifdef GDI_DEBUG
- if(++Attempts > 20)
- {
- DPRINT1("[%d]Waiting on 0x%x\n", Attempts, hObj);
}
-#endif
- /* the object is currently locked, wait some time and try again.
- FIXME - we shouldn't loop forever! Give up after some time! */
- DelayExecution();
- /* try again */
- goto LockHandle;
- }
- else
- {
- DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj);
- }
- }
- return FALSE;
+ return FALSE;
}
-void INTERNAL_CALL
-GDIOBJ_SetOwnership(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
+BOOL INTERNAL_CALL
+GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
{
- PGDI_TABLE_ENTRY Entry;
- HANDLE ProcessId, LockedProcessId, PrevProcId;
- PETHREAD Thread;
-#ifdef GDI_DEBUG
- ULONG Attempts = 0;
-#endif
+ PGDI_TABLE_ENTRY Entry;
+ HANDLE ProcessId, LockedProcessId, PrevProcId;
+ PTHREADINFO Thread;
+ BOOL Ret = TRUE;
- DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0));
+ GDIDBG_INITLOOPTRACE();
- Thread = PsGetCurrentThread();
+ DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0));
- if(!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
- {
- ProcessId = PsGetCurrentProcessId();
- LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
-
- Entry = GDI_HANDLE_GET_ENTRY(HandleTable, ObjectHandle);
+ Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
-LockHandle:
- /* lock the object, we must not convert stock objects, so don't check!!! */
- PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, ProcessId, LockedProcessId);
- if(PrevProcId == ProcessId)
+ if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
{
- PETHREAD PrevThread;
+ ProcessId = PsGetCurrentProcessId();
+ LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
- if((Entry->Type & ~GDI_ENTRY_REUSE_MASK) != 0 && Entry->KernelData != NULL)
- {
- PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
+ Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
- PrevThread = GdiHdr->LockingThread;
- if(GdiHdr->Locks == 0 || PrevThread == Thread)
+LockHandle:
+ /* lock the object, we must not convert stock objects, so don't check!!! */
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, ProcessId, LockedProcessId);
+ if (PrevProcId == ProcessId)
{
- PEPROCESS OldProcess;
- PW32PROCESS W32Process;
- NTSTATUS Status;
+ PTHREADINFO PrevThread;
- /* dereference the process' object counter */
- /* FIXME */
- if((ULONG_PTR)PrevProcId & ~0x1)
- {
- Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
- if(NT_SUCCESS(Status))
+ if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
{
- W32Process = (PW32PROCESS)OldProcess->Win32Process;
- if(W32Process != NULL)
- {
- InterlockedDecrement(&W32Process->GDIObjects);
- }
- ObDereferenceObject(OldProcess);
+ POBJ Object = Entry->KernelData;
+
+ PrevThread = Object->Tid;
+ if (Object->cExclusiveLock == 0 || PrevThread == Thread)
+ {
+ PEPROCESS OldProcess;
+ PPROCESSINFO W32Process;
+ NTSTATUS Status;
+
+ /* dereference the process' object counter */
+ /* FIXME */
+ if ((ULONG_PTR)PrevProcId & ~0x1)
+ {
+ Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
+ if (NT_SUCCESS(Status))
+ {
+ W32Process = (PPROCESSINFO)OldProcess->Win32Process;
+ if (W32Process != NULL)
+ {
+ InterlockedDecrement(&W32Process->GDIHandleCount);
+ }
+ ObDereferenceObject(OldProcess);
+ }
+ }
+
+ if (NewOwner != NULL)
+ {
+ ProcessId = PsGetProcessId(NewOwner);
+
+ /* Increase the new process' object counter */
+ W32Process = (PPROCESSINFO)NewOwner->Win32Process;
+ if (W32Process != NULL)
+ {
+ InterlockedIncrement(&W32Process->GDIHandleCount);
+ }
+ }
+ else
+ ProcessId = 0;
+
+ /* remove the process id lock and change it to the new process id */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, ProcessId);
+
+ /* we're done! */
+ return Ret;
+ }
+ else
+ {
+ 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);
+
+ DelayExecution();
+ goto LockHandle;
+ }
}
- }
-
- if(NewOwner != NULL)
- {
- ProcessId = PsGetProcessId(NewOwner);
-
- /* Increase the new process' object counter */
- W32Process = (PW32PROCESS)NewOwner->Win32Process;
- if(W32Process != NULL)
+ else
{
- InterlockedIncrement(&W32Process->GDIObjects);
+ 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
- ProcessId = 0;
-
- /* remove the process id lock and change it to the new process id */
- (void)InterlockedExchangePointer(&Entry->ProcessId, ProcessId);
+ }
+ else if (PrevProcId == LockedProcessId)
+ {
+ GDIDBG_TRACELOOP(ObjectHandle, PrevProcId, ProcessId);
- /* we're done! */
- return;
+ /* the object is currently locked, wait some time and try again.
+ FIXME - we shouldn't loop forever! Give up after some time! */
+ DelayExecution();
+ /* try again */
+ goto LockHandle;
+ }
+ else if (((ULONG_PTR)PrevProcId & ~0x1) == 0)
+ {
+ /* allow changing ownership of global objects */
+ ProcessId = NULL;
+ LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
+ goto 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
{
-#ifdef GDI_DEBUG
- if(++Attempts > 20)
- {
- DPRINT1("[%d]Locked by 0x%x (we're 0x%x)\n", Attempts, PrevThread, Thread);
- }
-#endif
- /* 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(&Entry->ProcessId, PrevProcId);
-
- DelayExecution();
- goto LockHandle;
+ DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle);
+ Ret = FALSE;
}
- }
- else
- {
- 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);
- }
}
- else if(PrevProcId == LockedProcessId)
- {
-#ifdef GDI_DEBUG
- if(++Attempts > 20)
- {
- DPRINT1("[%d]Waiting on 0x%x\n", Attempts, ObjectHandle);
- }
-#endif
- /* the object is currently locked, wait some time and try again.
- FIXME - we shouldn't loop forever! Give up after some time! */
- DelayExecution();
- /* try again */
- goto LockHandle;
- }
- else if(((ULONG_PTR)PrevProcId & ~0x1) == 0)
- {
- /* allow changing ownership of global objects */
- ProcessId = NULL;
- LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
- goto 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());
- }
- else
- {
- DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle);
- }
- }
+ return Ret;
}
-void INTERNAL_CALL
-GDIOBJ_CopyOwnership(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
+BOOL INTERNAL_CALL
+GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
{
- PGDI_TABLE_ENTRY FromEntry;
- PETHREAD Thread;
- HANDLE FromProcessId, FromLockedProcessId, FromPrevProcId;
-#ifdef GDI_DEBUG
- ULONG Attempts = 0;
-#endif
-
- DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo);
+ PGDI_TABLE_ENTRY FromEntry;
+ PTHREADINFO Thread;
+ HANDLE FromProcessId, FromLockedProcessId, FromPrevProcId;
+ BOOL Ret = TRUE;
- Thread = PsGetCurrentThread();
+ GDIDBG_INITLOOPTRACE();
- if(!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo))
- {
- FromEntry = GDI_HANDLE_GET_ENTRY(HandleTable, CopyFrom);
+ DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo);
- FromProcessId = (HANDLE)((ULONG_PTR)FromEntry->ProcessId & ~0x1);
- FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
+ Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
-LockHandleFrom:
- /* lock the object, we must not convert stock objects, so don't check!!! */
- FromPrevProcId = InterlockedCompareExchangePointer(&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
- if(FromPrevProcId == FromProcessId)
+ if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo))
{
- PETHREAD PrevThread;
- PGDIOBJHDR GdiHdr;
+ FromEntry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, CopyFrom);
- if((FromEntry->Type & ~GDI_ENTRY_REUSE_MASK) != 0 && FromEntry->KernelData != NULL)
- {
- GdiHdr = GDIBdyToHdr(FromEntry->KernelData);
+ FromProcessId = (HANDLE)((ULONG_PTR)FromEntry->ProcessId & ~0x1);
+ FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
- /* save the pointer to the calling thread so we know it was this thread
- that locked the object */
- PrevThread = GdiHdr->LockingThread;
- if(GdiHdr->Locks == 0 || PrevThread == Thread)
+LockHandleFrom:
+ /* lock the object, we must not convert stock objects, so don't check!!! */
+ FromPrevProcId = InterlockedCompareExchangePointer((PVOID*)&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
+ if (FromPrevProcId == FromProcessId)
{
- /* now let's change the ownership of the target object */
+ PTHREADINFO PrevThread;
+ POBJ Object;
- if(((ULONG_PTR)FromPrevProcId & ~0x1) != 0)
- {
- PEPROCESS ProcessTo;
- /* FIXME */
- if(NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1), &ProcessTo)))
+ if ((FromEntry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
{
- GDIOBJ_SetOwnership(HandleTable, CopyTo, ProcessTo);
- ObDereferenceObject(ProcessTo);
+ Object = FromEntry->KernelData;
+
+ /* save the pointer to the calling thread so we know it was this thread
+ that locked the object */
+ PrevThread = Object->Tid;
+ if (Object->cExclusiveLock == 0 || PrevThread == Thread)
+ {
+ /* now let's change the ownership of the target object */
+
+ if (((ULONG_PTR)FromPrevProcId & ~0x1) != 0)
+ {
+ PEPROCESS ProcessTo;
+ /* FIXME */
+ if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1), &ProcessTo)))
+ {
+ GDIOBJ_SetOwnership(CopyTo, ProcessTo);
+ ObDereferenceObject(ProcessTo);
+ }
+ }
+ else
+ {
+ /* mark the object as global */
+ GDIOBJ_SetOwnership(CopyTo, NULL);
+ }
+
+ (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
+ }
+ else
+ {
+ 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);
+
+ DelayExecution();
+ goto LockHandleFrom;
+ }
}
- }
- else
- {
- /* mark the object as global */
- GDIOBJ_SetOwnership(HandleTable, CopyTo, NULL);
- }
+ else
+ {
+ DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom);
+ Ret = FALSE;
+ }
+ }
+ else if (FromPrevProcId == FromLockedProcessId)
+ {
+ GDIDBG_TRACELOOP(CopyFrom, FromPrevProcId, FromProcessId);
- (void)InterlockedExchangePointer(&FromEntry->ProcessId, FromPrevProcId);
+ /* the object is currently locked, wait some time and try again.
+ FIXME - we shouldn't loop forever! Give up after some time! */
+ DelayExecution();
+ /* try again */
+ goto LockHandleFrom;
+ }
+ else if ((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1) != PsGetCurrentProcessId())
+ {
+ /* FIXME - should we really allow copying ownership from objects that we don't even own? */
+ DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom, (ULONG_PTR)FromPrevProcId & ~0x1, PsGetCurrentProcessId());
+ FromProcessId = (HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1);
+ FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
+ goto LockHandleFrom;
}
else
{
-#ifdef GDI_DEBUG
- if(++Attempts > 20)
- {
- DPRINT1("[%d]Locked by 0x%x (we're 0x%x)\n", Attempts, PrevThread, Thread);
- }
-#endif
- /* 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(&FromEntry->ProcessId, FromPrevProcId);
-
- DelayExecution();
- goto LockHandleFrom;
+ DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom);
+ Ret = FALSE;
}
- }
- else
- {
- DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom);
- }
- }
- else if(FromPrevProcId == FromLockedProcessId)
- {
-#ifdef GDI_DEBUG
- if(++Attempts > 20)
- {
- DPRINT1("[%d]Waiting on 0x%x\n", Attempts, CopyFrom);
- }
-#endif
- /* the object is currently locked, wait some time and try again.
- FIXME - we shouldn't loop forever! Give up after some time! */
- DelayExecution();
- /* try again */
- goto LockHandleFrom;
- }
- else if((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1) != PsGetCurrentProcessId())
- {
- /* FIXME - should we really allow copying ownership from objects that we don't even own? */
- DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom, (ULONG_PTR)FromPrevProcId & ~0x1, PsGetCurrentProcessId());
- FromProcessId = (HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1);
- FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
- goto LockHandleFrom;
- }
- else
- {
- DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom);
}
- }
+ return Ret;
}
PVOID INTERNAL_CALL
return MappedView;
}
+/** PUBLIC FUNCTIONS **********************************************************/
+
+BOOL
+FASTCALL
+IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
+{
+ INT Index;
+ PGDI_TABLE_ENTRY Entry;
+/*
+ System Regions:
+ These regions do not use attribute sections and when allocated, use gdiobj
+ level functions.
+ */
+ // FIXME! HAX!!! Remove this once we get everything right!
+ Index = GDI_HANDLE_GET_INDEX(hRgn);
+ Entry = &GdiHandleTable->Entries[Index];
+ if (Entry->UserData) FreeObjectAttr(Entry->UserData);
+ Entry->UserData = NULL;
+ //
+ if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
+ {
+ return GDIOBJ_SetOwnership(hRgn, NULL);
+ }
+ if (OwnerMask == GDI_OBJ_HMGR_POWNED)
+ {
+ return GDIOBJ_SetOwnership((HGDIOBJ) hRgn, PsGetCurrentProcess() );
+ }
+ return FALSE;
+}
+
+BOOL
+FASTCALL
+IntGdiSetBrushOwner(PBRUSH pbr, DWORD OwnerMask)
+{
+ HBRUSH hBR;
+ PEPROCESS Owner = NULL;
+ PGDI_TABLE_ENTRY pEntry = NULL;
+
+ if (!pbr) return FALSE;
+
+ hBR = pbr->BaseObject.hHmgr;
+
+ if (!hBR || (GDI_HANDLE_GET_TYPE(hBR) != GDI_OBJECT_TYPE_BRUSH))
+ return FALSE;
+ else
+ {
+ INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hBR);
+ pEntry = &GdiHandleTable->Entries[Index];
+ }
+
+ if (pbr->flAttrs & GDIBRUSH_IS_GLOBAL)
+ {
+ GDIOBJ_ShareUnlockObjByPtr((POBJ)pbr);
+ return TRUE;
+ }
+
+ if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
+ {
+ // Set this Brush to inaccessible mode and to an Owner of NONE.
+// if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
+
+ if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, Owner))
+ return FALSE;
+
+ // Deny user access to User Data.
+ pEntry->UserData = NULL; // This hBR is inaccessible!
+ }
+
+ if (OwnerMask == GDI_OBJ_HMGR_POWNED)
+ {
+ if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, PsGetCurrentProcess() ))
+ return FALSE;
+
+ // Allow user access to User Data.
+ pEntry->UserData = pbr->pBrushAttr;
+ }
+ return TRUE;
+}
+
+BOOL
+FASTCALL
+IntGdiSetDCOwnerEx( HDC hDC, DWORD OwnerMask, BOOL NoSetBrush)
+{
+ PDC pDC;
+ BOOL Ret = FALSE;
+
+ if (!hDC || (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_DC)) return FALSE;
+
+ if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
+ {
+ pDC = DC_LockDc ( hDC );
+ MmCopyFromCaller(&pDC->dcattr, pDC->pdcattr, sizeof(DC_ATTR));
+ DC_UnlockDc( pDC );
+
+ DC_FreeDcAttr( hDC ); // Free the dcattr!
+
+ if (!DC_SetOwnership( hDC, NULL )) // This hDC is inaccessible!
+ return Ret;
+ }
+
+ if (OwnerMask == GDI_OBJ_HMGR_POWNED)
+ {
+ pDC = DC_LockDc ( hDC );
+ ASSERT(pDC->pdcattr == &pDC->dcattr);
+ DC_UnlockDc( pDC );
+
+ if (!DC_SetOwnership( hDC, PsGetCurrentProcess() )) return Ret;
+
+ DC_AllocateDcAttr( hDC ); // Allocate new dcattr
+
+ DCU_SynchDcAttrtoUser( hDC ); // Copy data from dc to dcattr
+ }
+
+ if ((OwnerMask != GDI_OBJ_HMGR_NONE) && !NoSetBrush)
+ {
+ pDC = DC_LockDc ( hDC );
+ if (IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrFill, OwnerMask))
+ IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrLine, OwnerMask);
+ DC_UnlockDc( pDC );
+ }
+ return TRUE;
+}
+
+INT
+FASTCALL
+GreGetObjectOwner(HGDIOBJ Handle, GDIOBJTYPE ObjType)
+{
+ INT Ret = GDI_OBJ_HMGR_RESTRICTED;
+
+ if ( GDI_HANDLE_GET_INDEX(Handle) < GDI_HANDLE_COUNT )
+ {
+ PGDI_TABLE_ENTRY pEntry = &GdiHandleTable->Entries[GDI_HANDLE_GET_INDEX(Handle)];
+
+ if (pEntry->ObjectType == ObjType)
+ {
+ if (pEntry->FullUnique == (GDI_HANDLE_GET_UPPER(Handle) >> GDI_ENTRY_UPPER_SHIFT))
+ Ret = pEntry->ProcessId & ~1;
+ }
+ }
+ return Ret;
+}
+
W32KAPI
HANDLE
APIENTRY
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(GdiHandleTable, 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);
- return handle;
+ 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;
}
W32KAPI
APIENTRY
NtGdiDeleteClientObj(
IN HANDLE h
- )
+)
+{
+ /* 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)
{
- return GDIOBJ_FreeObj(GdiHandleTable, h, GDI_OBJECT_TYPE_CLIOBJ);
+ 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 */