X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=subsystems%2Fwin32%2Fwin32k%2Fobjects%2Fgdiobj.c;h=2a5597ecf66902196b4d274c29bdd1e8e6b6b06d;hp=a6d470a5aa2018782defc62377abca62b1c81901;hb=b726d7355f0aa394852fa8c56e59cfc9bbc4293c;hpb=9ab4e6808d239977bcba0066e3ca3a64bec5d64b diff --git a/subsystems/win32/win32k/objects/gdiobj.c b/subsystems/win32/win32k/objects/gdiobj.c index a6d470a5aa2..2a5597ecf66 100644 --- a/subsystems/win32/win32k/objects/gdiobj.c +++ b/subsystems/win32/win32k/objects/gdiobj.c @@ -3,278 +3,259 @@ * LICENSE: GPL - See COPYING in the top level directory * FILE: subsystems/win32/win32k/objects/gdiobj.c * PURPOSE: General GDI object manipulation routines - * PROGRAMMERS: ... + * PROGRAMMERS: Timo Kreuzer */ -/** INCLUDES ******************************************************************/ +/* + * If you want to understand this code, you need to start thinking in portals. + * - gpaulRefCount is a global pointer to an allocated array of ULONG values, + * one for each handle. Bits 0 - 22 contain a reference count for the handle. + * It gets increased for each handle lock / reference. Bit 23 contains a valid + * bit. If this bit is 0, the handle got deleted and will be pushed to the free + * list, once all references are gone. Bits 24 - 31 contain the reuse value of + * the handle, which allows to check if the entry was changed before atomically + * exchanging the reference count. + * - Objects can exist with or without a handle + * - Objects with a handle can be locked either exclusively or shared. + * Both locks increase the handle reference count in gpaulRefCount. + * Exclusive locks also increase the BASEOBJECT's cExclusiveLock field + * and the first lock (can be acquired recursively) acquires a pushlock + * that is also stored in the BASEOBJECT. + * - Objects without a handle cannot have exclusive locks. Their reference + * count is tracked in the BASEOBJECT's ulShareCount field. + * - An object that is inserted in the handle table automatically has an + * exclusive lock. For objects that are "shared objects" (BRUSH, PALETTE, ...) + * this is the only way it can ever be exclusively locked. It prevents the + * object from being locked by another thread. A shared lock will simply fail, + * while an exclusive lock will succeed after the object was unlocked. + * + */ + +/* INCLUDES ******************************************************************/ #include #define NDEBUG #include -#define BASE_OBJTYPE_COUNT 32 - -#define DelayExecution() \ - DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \ - KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay) +// move to gdidbg.h +#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_LFONT_TYPE || \ + (objt) == GDIObjType_PATH_TYPE || \ + (objt) == GDIObjType_BRUSH_TYPE) +#define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt) \ + ASSERT((objt) == GDIObjType_DC_TYPE || \ + (objt) == GDIObjType_RGN_TYPE || \ + (objt) == GDIObjType_LFONT_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) +#endif -static -BOOL INTERNAL_CALL GDI_CleanupDummy(PVOID ObjectBody); +#define MmMapViewInSessionSpace MmMapViewInSystemSpace -/** GLOBALS *******************************************************************/ +#ifdef _M_IX86 +#define InterlockedOr16 _InterlockedOr16 +#endif -typedef struct -{ - BOOL bUseLookaside; - ULONG_PTR ulBodySize; - ULONG Tag; - GDICLEANUPPROC CleanupProc; -} OBJ_TYPE_INFO, *POBJ_TYPE_INFO; +#define GDIOBJ_POOL_TAG(type) ('00hG' + ((objt & 0x1f) << 24)) -static const -OBJ_TYPE_INFO ObjTypeInfo[BASE_OBJTYPE_COUNT] = +enum { - {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 */ + REF_MASK_REUSE = 0xff000000, + REF_INC_REUSE = 0x01000000, + REF_MASK_VALID = 0x00800000, + REF_MASK_COUNT = 0x007fffff, + REF_MASK_INUSE = 0x00ffffff, }; -static LARGE_INTEGER ShortDelay; -PGDI_HANDLE_TABLE GdiHandleTable = NULL; -static PSECTION_OBJECT GdiTableSection = NULL; +/* GLOBALS *******************************************************************/ -/** INTERNAL FUNCTIONS ********************************************************/ +/* Per session handle table globals */ +static PVOID gpvGdiHdlTblSection = NULL; +static PENTRY gpentHmgr; +static PULONG gpaulRefCount; +ULONG gulFirstFree; +ULONG gulFirstUnused; +static PPAGED_LOOKASIDE_LIST gpaLookasideList; -// Audit Functions -int tDC = 0; -int tBRUSH = 0; -int tBITMAP = 0; -int tFONT = 0; -int tRGN = 0; +static BOOL INTERNAL_CALL GDIOBJ_Cleanup(PVOID ObjectBody); -VOID -AllocTypeDataDump(INT TypeInfo) +static const +GDICLEANUPPROC +apfnCleanup[] = { - 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; - } -} + 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 */ +}; -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; - } -} +/* INTERNAL FUNCTIONS ********************************************************/ -/* - * Dummy GDI Cleanup Callback - */ static BOOL INTERNAL_CALL -GDI_CleanupDummy(PVOID ObjectBody) +GDIOBJ_Cleanup(PVOID ObjectBody) { return TRUE; } -/*! - * Allocate GDI object table. - * \param Size - number of entries in the object table. -*/ -INIT_FUNCTION -PGDI_HANDLE_TABLE -INTERNAL_CALL -GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject) +static +VOID +InitLookasideList(UCHAR objt, ULONG cjSize) { - PGDI_HANDLE_TABLE HandleTable = NULL; - LARGE_INTEGER htSize; - UINT ObjType; - ULONG ViewSize = 0; - NTSTATUS Status; - - ASSERT(SectionObject != NULL); - - htSize.QuadPart = sizeof(GDI_HANDLE_TABLE); + ExInitializePagedLookasideList(&gpaLookasideList[objt], + NULL, + NULL, + 0, + cjSize, + GDITAG_HMGR_LOOKASIDE_START + (objt << 24), + 0); +} - Status = MmCreateSection((PVOID*)SectionObject, +INIT_FUNCTION +NTSTATUS +NTAPI +InitGdiHandleTable(void) +{ + NTSTATUS status; + LARGE_INTEGER liSize; + PVOID pvSection; + SIZE_T cjViewSize = 0; + + /* Create a section for the shared handle table */ + liSize.QuadPart = sizeof(GDI_HANDLE_TABLE);//GDI_HANDLE_COUNT * sizeof(ENTRY); + status = MmCreateSection(&gpvGdiHdlTblSection, SECTION_ALL_ACCESS, NULL, - &htSize, + &liSize, 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)) + if (!NT_SUCCESS(status)) { - ObDereferenceObject(*SectionObject); - *SectionObject = NULL; - return NULL; + DPRINT1("INITGDI: Could not allocate a GDI handle table.\n"); + return status; } - RtlZeroMemory(HandleTable, sizeof(GDI_HANDLE_TABLE)); - - HandleTable->LookasideLists = ExAllocatePoolWithTag(NonPagedPool, - BASE_OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST), - TAG_GDIHNDTBLE); - if (HandleTable->LookasideLists == NULL) + /* Map the section in session space */ + status = MmMapViewInSessionSpace(gpvGdiHdlTblSection, + (PVOID*)&gpentHmgr, + &cjViewSize); + if (!NT_SUCCESS(status)) { - MmUnmapViewInSystemSpace(HandleTable); - ObDereferenceObject(*SectionObject); - *SectionObject = NULL; - return NULL; + DPRINT1("INITGDI: Failed to map handle table section\n"); + ObDereferenceObject(gpvGdiHdlTblSection); + return status; } - for (ObjType = 0; ObjType < BASE_OBJTYPE_COUNT; ObjType++) + /* Allocate memory for the reference counter table */ + gpaulRefCount = EngAllocSectionMem(&pvSection, + FL_ZERO_MEMORY, + GDI_HANDLE_COUNT * sizeof(ULONG), + 'frHG'); + if (!gpaulRefCount) { - if (ObjTypeInfo[ObjType].bUseLookaside) - { - ExInitializePagedLookasideList(HandleTable->LookasideLists + ObjType, - NULL, - NULL, - 0, - ObjTypeInfo[ObjType].ulBodySize, - ObjTypeInfo[ObjType].Tag, - 0); - } + DPRINT1("INITGDI: Failed to allocate reference table.\n"); + ObDereferenceObject(gpvGdiHdlTblSection); + return STATUS_INSUFFICIENT_RESOURCES; } - ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */ + gulFirstFree = 0; + gulFirstUnused = RESERVE_ENTRIES_COUNT; - HandleTable->FirstFree = 0; - HandleTable->FirstUnused = RESERVE_ENTRIES_COUNT; + GdiHandleTable = (PVOID)gpentHmgr; - return HandleTable; -} + /* Initialize the lookaside lists */ + gpaLookasideList = ExAllocatePoolWithTag(NonPagedPool, + GDIObjTypeTotal * sizeof(PAGED_LOOKASIDE_LIST), + TAG_GDIHNDTBLE); -INIT_FUNCTION -NTSTATUS -NTAPI -InitGdiHandleTable() -{ - /* Create the GDI handle table */ - GdiHandleTable = GDIOBJ_iAllocHandleTable(&GdiTableSection); - if (GdiHandleTable == NULL) - { - DPRINT1("Failed to initialize the GDI handle table.\n"); - return STATUS_UNSUCCESSFUL; - } + InitLookasideList(GDIObjType_DC_TYPE, sizeof(DC)); + InitLookasideList(GDIObjType_RGN_TYPE, sizeof(REGION)); + InitLookasideList(GDIObjType_SURF_TYPE, sizeof(SURFACE)); + InitLookasideList(GDIObjType_CLIENTOBJ_TYPE, sizeof(CLIENTOBJ)); + InitLookasideList(GDIObjType_PATH_TYPE, sizeof(PATH)); + InitLookasideList(GDIObjType_PAL_TYPE, sizeof(PALETTE)); + InitLookasideList(GDIObjType_ICMLCS_TYPE, sizeof(COLORSPACE)); + InitLookasideList(GDIObjType_LFONT_TYPE, sizeof(TEXTOBJ)); + InitLookasideList(GDIObjType_BRUSH_TYPE, sizeof(BRUSH)); return STATUS_SUCCESS; } +FORCEINLINE +VOID +IncrementGdiHandleCount(void) +{ + PPROCESSINFO ppi = PsGetCurrentProcessWin32Process(); + if (ppi) InterlockedIncrement((LONG*)&ppi->GDIHandleCount); +} -static void FASTCALL -LockErrorDebugOutput(HGDIOBJ hObj, PGDI_TABLE_ENTRY Entry, LPSTR Function) +FORCEINLINE +VOID +DecrementGdiHandleCount(void) { - 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, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n", - Function, hObj, GDI_HANDLE_GET_REUSECNT(hObj), GDI_ENTRY_GET_REUSECNT(Entry->Type)); - } - else if (GDI_HANDLE_GET_TYPE(hObj) != ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK)) - { - DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n", - Function, hObj, GDI_HANDLE_GET_TYPE(hObj), (Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK); - } - else - { - DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n", - Function, hObj, Entry->Type); - } - GDIDBG_TRACECALLER(); + PPROCESSINFO ppi = PsGetCurrentProcessWin32Process(); + if (ppi) InterlockedDecrement((LONG*)&ppi->GDIHandleCount); } -ULONG -FASTCALL -InterlockedPopFreeEntry(VOID) +static +PENTRY +ENTRY_pentPopFreeEntry(VOID) { ULONG iFirst, iNext, iPrev; - PGDI_TABLE_ENTRY pEntry; + PENTRY pentFree; DPRINT("Enter InterLockedPopFreeEntry\n"); do { /* Get the index and sequence number of the first free entry */ - iFirst = GdiHandleTable->FirstFree; + iFirst = gulFirstFree; /* Check if we have a free entry */ if (!(iFirst & GDI_HANDLE_INDEX_MASK)) { /* Increment FirstUnused and get the new index */ - iFirst = InterlockedIncrement((LONG*)&GdiHandleTable->FirstUnused) - 1; + iFirst = InterlockedIncrement((LONG*)&gulFirstUnused) - 1; /* Check if we have unused entries left */ if (iFirst >= GDI_HANDLE_COUNT) @@ -283,1497 +264,890 @@ InterlockedPopFreeEntry(VOID) return 0; } - /* Return the old index */ - return iFirst; + /* Return the old entry */ + return &gpentHmgr[iFirst]; } /* Get a pointer to the first free entry */ - pEntry = GdiHandleTable->Entries + (iFirst & GDI_HANDLE_INDEX_MASK); + pentFree = &gpentHmgr[iFirst & GDI_HANDLE_INDEX_MASK]; /* Create a new value with an increased sequence number */ - iNext = (USHORT)(ULONG_PTR)pEntry->KernelData; + iNext = (USHORT)(ULONG_PTR)pentFree->einfo.pobj; iNext |= (iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000; /* Try to exchange the FirstFree value */ - iPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree, + iPrev = InterlockedCompareExchange((LONG*)&gulFirstFree, iNext, iFirst); } while (iPrev != iFirst); /* Sanity check: is entry really free? */ - ASSERT(((ULONG_PTR)pEntry->KernelData & ~GDI_HANDLE_INDEX_MASK) == 0); + ASSERT(((ULONG_PTR)pentFree->einfo.pobj & ~GDI_HANDLE_INDEX_MASK) == 0); - return iFirst & GDI_HANDLE_INDEX_MASK; + return pentFree; } /* Pushes an entry of the handle table to the free list, - The entry must be unlocked and the base type field must be 0 */ + The entry must not have any references left */ +static VOID -FASTCALL -InterlockedPushFreeEntry(ULONG idxToFree) +ENTRY_vPushFreeEntry(PENTRY pentFree) { - ULONG iToFree, iFirst, iPrev; - PGDI_TABLE_ENTRY pFreeEntry; + ULONG iToFree, iFirst, iPrev, idxToFree; + + DPRINT("Enter ENTRY_vPushFreeEntry\n"); + + idxToFree = pentFree - gpentHmgr; + ASSERT((gpaulRefCount[idxToFree] & REF_MASK_INUSE) == 0); - DPRINT("Enter InterlockedPushFreeEntry\n"); + /* Initialize entry */ + pentFree->Objt = GDIObjType_DEF_TYPE; + pentFree->ObjectOwner.ulObj = 0; + pentFree->pUser = NULL; - pFreeEntry = GdiHandleTable->Entries + idxToFree; - ASSERT((pFreeEntry->Type & GDI_ENTRY_BASETYPE_MASK) == 0); - ASSERT(pFreeEntry->ProcessId == 0); - pFreeEntry->UserData = NULL; // FIXME - ASSERT(pFreeEntry->UserData == NULL); + /* Increase reuse counter in entry and reference counter */ + InterlockedExchangeAdd((LONG*)&gpaulRefCount[idxToFree], REF_INC_REUSE); + pentFree->FullUnique += 0x0100; do { /* Get the current first free index and sequence number */ - iFirst = GdiHandleTable->FirstFree; + iFirst = gulFirstFree; - /* Set the KernelData member to the index of the first free entry */ - pFreeEntry->KernelData = UlongToPtr(iFirst & GDI_HANDLE_INDEX_MASK); + /* Set the einfo.pobj member to the index of the first free entry */ + pentFree->einfo.pobj = UlongToPtr(iFirst & GDI_HANDLE_INDEX_MASK); /* Combine new index and increased sequence number in iToFree */ iToFree = idxToFree | ((iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000); /* Try to atomically update the first free entry */ - iPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree, + iPrev = InterlockedCompareExchange((LONG*)&gulFirstFree, iToFree, iFirst); } while (iPrev != iFirst); } - -BOOL -INTERNAL_CALL -GDIOBJ_ValidateHandle(HGDIOBJ hObj, ULONG ObjectType) +static +PENTRY +ENTRY_ReferenceEntryByHandle(HGDIOBJ hobj, FLONG fl) { - 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)) + ULONG ulIndex, cNewRefs, cOldRefs; + PENTRY pentry; + + /* Get the handle index and check if its too big */ + ulIndex = GDI_HANDLE_GET_INDEX(hobj); + if (ulIndex >= GDI_HANDLE_COUNT) return NULL; + + /* Get pointer to the entry */ + pentry = &gpentHmgr[ulIndex]; + + /* Get the current reference count */ + cOldRefs = gpaulRefCount[ulIndex]; + + do { - HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1); - if (pid == NULL || pid == PsGetCurrentProcessId()) + /* Check if the slot is deleted */ + if ((cOldRefs & REF_MASK_VALID) == 0) + { + DPRINT("GDIOBJ: slot not valid: 0x%lx, hobh=%p\n", cOldRefs, hobj); + return NULL; + } + + /* Check if the unique value matches */ + if (pentry->FullUnique != (USHORT)((ULONG_PTR)hobj >> 16)) { - return TRUE; + DPRINT("GDIOBJ: wrong unique value. Handle: 0x%4x, entry: 0x%4x\n", + (USHORT)((ULONG_PTR)hobj >> 16, pentry->FullUnique)); + return NULL; } + + /* Check if the object owner is this process or public */ + if (!(fl & GDIOBJFLAG_IGNOREPID) && + pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC && + pentry->ObjectOwner.ulObj != PtrToUlong(PsGetCurrentProcessId())) + { + DPRINT("GDIOBJ: Cannot reference foreign handle %p, pentry=%p:%lx.\n", + hobj, pentry, pentry->ObjectOwner.ulObj); + return NULL; + } + + /* Try to atomically increment the reference count */ + cNewRefs = cOldRefs + 1; + cOldRefs = InterlockedCompareExchange((PLONG)&gpaulRefCount[ulIndex], + cNewRefs, + cOldRefs); } - return FALSE; + while (cNewRefs != cOldRefs + 1); + + /* Integrity checks */ + ASSERT((pentry->FullUnique & 0x1f) == pentry->Objt); + ASSERT(pentry->einfo.pobj && pentry->einfo.pobj->hHmgr == hobj); + + return pentry; } -POBJ INTERNAL_CALL -GDIOBJ_AllocObj(UCHAR BaseType) +static +HGDIOBJ +ENTRY_hInsertObject(PENTRY pentry, POBJ pobj, UCHAR objt, ULONG ulOwner) { - POBJ pObject; + ULONG ulIndex; - ASSERT((BaseType & ~GDIObjTypeTotal) == 0); -// BaseType &= GDI_HANDLE_BASETYPE_MASK; + /* Calculate the handle index */ + ulIndex = pentry - gpentHmgr; - if (ObjTypeInfo[BaseType].bUseLookaside) - { - PPAGED_LOOKASIDE_LIST LookasideList; + /* Update the fields in the ENTRY */ + pentry->einfo.pobj = pobj; + pentry->Objt = objt & 0x1f; + pentry->FullUnique = (pentry->FullUnique & 0xff00) | objt; + pentry->ObjectOwner.ulObj = ulOwner; + + /* Make the handle valid with 1 reference */ + ASSERT((gpaulRefCount[ulIndex] & REF_MASK_INUSE) == 0); + InterlockedOr((LONG*)&gpaulRefCount[ulIndex], REF_MASK_VALID | 1); + + /* Return the handle */ + return (HGDIOBJ)(((ULONG_PTR)pentry->FullUnique << 16) | ulIndex); +} + +POBJ +NTAPI +GDIOBJ_AllocateObject(UCHAR objt, ULONG cjSize, FLONG fl) +{ + POBJ pobj; - LookasideList = GdiHandleTable->LookasideLists + BaseType; - pObject = ExAllocateFromPagedLookasideList(LookasideList); + if (fl & BASEFLAG_LOOKASIDE) + { + /* Allocate the object from a lookaside list */ + pobj = ExAllocateFromPagedLookasideList(&gpaLookasideList[objt & 0x1f]); } else { - pObject = ExAllocatePoolWithTag(PagedPool, - ObjTypeInfo[BaseType].ulBodySize, - ObjTypeInfo[BaseType].Tag); + /* Allocate the object from paged pool */ + pobj = ExAllocatePoolWithTag(PagedPool, cjSize, GDIOBJ_POOL_TAG(objt)); } - if (pObject) - { - RtlZeroMemory(pObject, ObjTypeInfo[BaseType].ulBodySize); - } + if (!pobj) return NULL; - return pObject; -} + /* Initialize the object */ + RtlZeroMemory(pobj, cjSize); + pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)objt << 16); + pobj->cExclusiveLock = 0; + pobj->ulShareCount = 1; + pobj->BaseFlags = fl & 0xffff; + DBG_INITLOG(&pobj->slhLog); + DBG_LOGEVENT(&pobj->slhLog, EVENT_ALLOCATE, 0); + return pobj; +} -/*! - * Allocate memory for GDI object and return handle to it. - * - * \param ObjectType - type of object \ref GDI object types - * - * \return Pointer to the allocated object, which is locked. -*/ -POBJ INTERNAL_CALL -GDIOBJ_AllocObjWithHandle(ULONG ObjectType) +VOID +NTAPI +GDIOBJ_vFreeObject(POBJ pobj) { - PPROCESSINFO W32Process; - POBJ newObject = NULL; - HANDLE CurrentProcessId, LockedProcessId; - UCHAR TypeIndex; - UINT Index; - PGDI_TABLE_ENTRY Entry; - LONG TypeInfo; - - GDIDBG_INITLOOPTRACE(); - - W32Process = PsGetCurrentProcessWin32Process(); - /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process - to take too many GDI objects, itself. */ - if (W32Process && W32Process->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; - } + UCHAR objt; + + DBG_CLEANUP_EVENT_LIST(&pobj->slhLog); - ASSERT(ObjectType != GDI_OBJECT_TYPE_DONTCARE); + /* Get the object type */ + objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0x1f; - TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(ObjectType); + /* Call the cleanup procedure */ + ASSERT(apfnCleanup[objt]); + apfnCleanup[objt](pobj); - newObject = GDIOBJ_AllocObj(TypeIndex); - if (!newObject) + /* Check if the object is allocated from a lookaside list */ + if (pobj->BaseFlags & BASEFLAG_LOOKASIDE) { - DPRINT1("Not enough memory to allocate gdi object!\n"); - return NULL; + ExFreeToPagedLookasideList(&gpaLookasideList[objt], pobj); } + else + { + ExFreePoolWithTag(pobj, GDIOBJ_POOL_TAG(objt)); + } +} - CurrentProcessId = PsGetCurrentProcessId(); - LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1); - -// 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); +VOID +NTAPI +GDIOBJ_vDereferenceObject(POBJ pobj) +{ + ULONG cRefs, ulIndex; - Index = InterlockedPopFreeEntry(); - if (Index != 0) + /* Check if the object has a handle */ + if (GDI_HANDLE_GET_INDEX(pobj->hHmgr)) { - HANDLE PrevProcId; + /* Calculate the index */ + ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); - Entry = &GdiHandleTable->Entries[Index]; + /* Decrement reference count */ + ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0); + cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]) & REF_MASK_INUSE; -LockHandle: - PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, 0); - if (PrevProcId == NULL) + /* Check if we reached 0 and handle bit is not set */ + if (cRefs == 0) { - PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread(); - HGDIOBJ Handle; - - Entry->KernelData = newObject; + /* Check if the handle was process owned */ + if (gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC && + gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_NONE) + { + /* Decrement the process handle count */ + ASSERT(gpentHmgr[ulIndex].ObjectOwner.ulObj == + HandleToUlong(PsGetCurrentProcessId())); + DecrementGdiHandleCount(); + } - /* copy the reuse-counter */ - TypeInfo |= Entry->Type & GDI_ENTRY_REUSE_MASK; + /* Push entry to the free list */ + ENTRY_vPushFreeEntry(&gpentHmgr[ulIndex]); + } + } + else + { + /* Decrement the objects reference count */ + ASSERT(pobj->ulShareCount > 0); + cRefs = InterlockedDecrement((LONG*)&pobj->ulShareCount); + } - /* we found a free entry, no need to exchange this field atomically - since we're holding the lock */ - Entry->Type = TypeInfo; + DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs); - /* Create a handle */ - Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT)); + /* Check if we reached 0 */ + if (cRefs == 0) + { + /* Make sure it's ok to delete the object */ + ASSERT(pobj->BaseFlags & BASEFLAG_READY_TO_DIE); - /* Initialize BaseObject fields */ - newObject->hHmgr = Handle; - newObject->ulShareCount = 0; - newObject->cExclusiveLock = 1; - newObject->Tid = Thread; -#if DBG - if (Thread) Thread->cExclusiveLocks++; -#endif + /* Free the object */ + GDIOBJ_vFreeObject(pobj); + } +} - AllocTypeDataDump(TypeInfo); +POBJ +NTAPI +GDIOBJ_ReferenceObjectByHandle( + HGDIOBJ hobj, + UCHAR objt) +{ + PENTRY pentry; + POBJ pobj; - /* unlock the entry */ - (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId); + /* Check if the handle type matches */ + ASSERT_SHARED_OBJECT_TYPE(objt); + if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt) + { + DPRINT("GDIOBJ: wrong type. handle=%p, type=%x\n", hobj, objt); + return NULL; + } - GDIDBG_CAPTUREALLOCATOR(Index); + /* Reference the handle entry */ + pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); + if (!pentry) + { + DPRINT("GDIOBJ: requested handle 0x%p is not valid.\n", hobj); + return NULL; + } - if (W32Process != NULL) - { - InterlockedIncrement(&W32Process->GDIHandleCount); - } + /* Get the pointer to the BASEOBJECT */ + pobj = pentry->einfo.pobj; - DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, newObject); - return newObject; - } - else - { - 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; - } + /* Check if the object is exclusively locked */ + if (pobj->cExclusiveLock != 0) + { + DPRINT1("GDIOBJ: Cannot reference oject %p with exclusive lock.\n", hobj); + GDIOBJ_vDereferenceObject(pobj); + DBG_DUMP_EVENT_LIST(&pobj->slhLog); + return NULL; } - GDIOBJ_FreeObj(newObject, TypeIndex); + DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, gpaulRefCount[pentry - gpentHmgr]); - DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n"); - GDIDBG_DUMPHANDLETABLE(); - - return NULL; + /* All is well, return the object */ + return pobj; } - -VOID INTERNAL_CALL -GDIOBJ_FreeObj(POBJ pObject, UCHAR BaseType) +VOID +NTAPI +GDIOBJ_vReferenceObjectByPointer(POBJ pobj) { - /* Object must not have a handle! */ - ASSERT(pObject->hHmgr == NULL); + ULONG cRefs; - if (ObjTypeInfo[BaseType].bUseLookaside) - { - PPAGED_LOOKASIDE_LIST LookasideList; + /* Must not be exclusively locked */ + ASSERT(pobj->cExclusiveLock == 0); - LookasideList = GdiHandleTable->LookasideLists + BaseType; - ExFreeToPagedLookasideList(LookasideList, pObject); + /* Check if the object has a handle */ + if (GDI_HANDLE_GET_INDEX(pobj->hHmgr)) + { + /* Increase the handle's reference count */ + ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); + ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0); + cRefs = InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]); } else { - ExFreePool(pObject); + /* Increase the object's reference count */ + cRefs = InterlockedIncrement((LONG*)&pobj->ulShareCount); } + + DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, cRefs); } -/*! - * Free memory allocated for the GDI object. For each object type this function calls the - * appropriate cleanup routine. - * - * \param hObj - handle of the object to be deleted. - * - * \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_FreeObjByHandle(HGDIOBJ hObj, DWORD ExpectedType) +PGDIOBJ +NTAPI +GDIOBJ_LockObject( + HGDIOBJ hobj, + UCHAR objt) { - PGDI_TABLE_ENTRY Entry; - HANDLE ProcessId, LockedProcessId, PrevProcId; - ULONG HandleType, HandleUpper, TypeIndex; - BOOL Silent; + PENTRY pentry; + POBJ pobj; + DWORD dwThreadId; + + /* Check if the handle type matches */ + ASSERT_EXCLUSIVE_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; + } - GDIDBG_INITLOOPTRACE(); + /* Reference the handle entry */ + pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); + if (!pentry) + { + DPRINT("GDIOBJ: requested handle 0x%p is not valid.\n", hobj); + return NULL; + } - DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj); + /* Get the pointer to the BASEOBJECT */ + pobj = pentry->einfo.pobj; - if (GDI_HANDLE_IS_STOCKOBJ(hObj)) + /* Check if we already own the lock */ + dwThreadId = PtrToUlong(PsGetCurrentThreadId()); + if (pobj->dwThreadId != dwThreadId) { - DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj); - GDIDBG_TRACECALLER(); - return FALSE; + /* Disable APCs and acquire the push lock */ + KeEnterCriticalRegion(); + ExAcquirePushLockExclusive(&pobj->pushlock); + + /* Set us as lock owner */ + ASSERT(pobj->dwThreadId == 0); + pobj->dwThreadId = dwThreadId; } - ProcessId = PsGetCurrentProcessId(); - LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1); + /* Increase lock count */ + pobj->cExclusiveLock++; + DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), hobj); + DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0); + + /* Return the object */ + return pobj; +} - Silent = (ExpectedType & GDI_OBJECT_TYPE_SILENT); - ExpectedType &= ~GDI_OBJECT_TYPE_SILENT; +VOID +NTAPI +GDIOBJ_vUnlockObject(POBJ pobj) +{ + ASSERT(pobj->cExclusiveLock > 0); - HandleType = GDI_HANDLE_GET_TYPE(hObj); - HandleUpper = GDI_HANDLE_GET_UPPER(hObj); + /* Decrease lock count */ + pobj->cExclusiveLock--; + DBG_DECREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr); - /* Check if we have the requested type */ - if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE && - HandleType != ExpectedType) || - HandleType == 0 ) + /* Check if this was the last lock */ + if (pobj->cExclusiveLock == 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; + /* Reset lock owner */ + pobj->dwThreadId = 0; + + /* Release the pushlock and reenable APCs */ + ExReleasePushLockExclusive(&pobj->pushlock); + KeLeaveCriticalRegion(); } - Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj); + /* Dereference the object */ + DBG_LOGEVENT(&pobj->slhLog, EVENT_UNLOCK, 0); + GDIOBJ_vDereferenceObject(pobj); +} -LockHandle: - /* lock the object, we must not delete global objects, so don't exchange the locking - process ID to zero when attempting to lock a global object... */ - PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId); - 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)) ) - { - POBJ Object; - PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread(); +HGDIOBJ +NTAPI +GDIOBJ_hInsertObject( + POBJ pobj, + ULONG ulOwner) +{ + PENTRY pentry; + UCHAR objt; - Object = Entry->KernelData; + /* Must have no handle and only one reference */ + ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr) == 0); + ASSERT(pobj->cExclusiveLock == 0); + ASSERT(pobj->ulShareCount == 1); - if ((Object->cExclusiveLock == 0 || Object->Tid == Thread) && - Object->ulShareCount == 0) - { - BOOL Ret; - PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process(); + /* Get a free handle entry */ + pentry = ENTRY_pentPopFreeEntry(); + if (!pentry) + { + DPRINT1("GDIOBJ: could not get a free entry.\n"); + return NULL; + } - /* 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; + /* Make the object exclusively locked */ + ExInitializePushLock(&pobj->pushlock); + KeEnterCriticalRegion(); + ExAcquirePushLockExclusive(&pobj->pushlock); + pobj->cExclusiveLock = 1; + pobj->dwThreadId = PtrToUlong(PsGetCurrentThreadId()); + DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr); - /* unlock the handle slot */ - (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL); + /* Get object type from the hHmgr field */ + objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0xff; + ASSERT(objt != GDIObjType_DEF_TYPE); - /* push this entry to the free list */ - InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable, Entry)); + /* Check if current process is requested owner */ + if (ulOwner == GDI_OBJ_HMGR_POWNED) + { + /* Increment the process handle count */ + IncrementGdiHandleCount(); - Object->hHmgr = NULL; -#if DBG - if (Thread) - { - if (Thread->cExclusiveLocks < Object->cExclusiveLock) - { - DPRINT1("cExclusiveLocks = %ld, object: %ld\n", - Thread->cExclusiveLocks, Object->cExclusiveLock); - ASSERT(FALSE); - } - Thread->cExclusiveLocks -= Object->cExclusiveLock; - } -#endif + /* Use Process id */ + ulOwner = HandleToUlong(PsGetCurrentProcessId()); + } - if (W32Process != NULL) - { - InterlockedDecrement(&W32Process->GDIHandleCount); - } + /* Insert the object into the handle table */ + pobj->hHmgr = ENTRY_hInsertObject(pentry, pobj, objt, ulOwner); + + /* Return the handle */ + DPRINT("GDIOBJ: Created handle: %p\n", pobj->hHmgr); + DBG_LOGEVENT(&pobj->slhLog, EVENT_CREATE_HANDLE, 0); + return pobj->hHmgr; +} - /* call the cleanup routine. */ - TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(HandleType); - Ret = ObjTypeInfo[TypeIndex].CleanupProc(Object); +VOID +NTAPI +GDIOBJ_vSetObjectOwner( + POBJ pobj, + ULONG ulOwner) +{ + PENTRY pentry; - DeAllocTypeDataDump(HandleType); + /* This is a ugly hack, need 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); + return; + } - /* Now it's time to free the memory */ - GDIOBJ_FreeObj(Object, TypeIndex); + /* Get the handle entry */ + ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr)); + pentry = &gpentHmgr[GDI_HANDLE_GET_INDEX(pobj->hHmgr)]; - GDIDBG_CAPTUREDELETER(hObj); - return Ret; - } - else if (Object->ulShareCount != 0) - { - NTSTATUS Status; - PEPROCESS OldProcess; - Object->BaseFlags |= BASEFLAG_READY_TO_DIE; - DPRINT("Object %p, ulShareCount = %d\n", Object->hHmgr, Object->ulShareCount); - /* Set NULL owner. Do the work here to avoid race conditions */ - Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess); - if (NT_SUCCESS(Status)) - { - PPROCESSINFO W32Process = (PPROCESSINFO)OldProcess->Win32Process; - if (W32Process != NULL) - { - InterlockedDecrement(&W32Process->GDIHandleCount); - } - ObDereferenceObject(OldProcess); - } - (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL); - /* Don't wait on shared locks */ - return FALSE; - } - else - { - /* - * The object is currently locked by another thread, so freeing is forbidden! - */ - DPRINT1("Object->cExclusiveLock = %d\n", Object->cExclusiveLock); - GDIDBG_TRACECALLER(); - GDIDBG_TRACELOCKER(hObj); - (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId); - /* do not assert here for it will call again from dxg.sys it being call twice */ - - DelayExecution(); - goto LockHandle; - } - } - else + /* Is the current process requested? */ + if (ulOwner == GDI_OBJ_HMGR_POWNED) + { + /* Use process id */ + ulOwner = HandleToUlong(PsGetCurrentProcessId()); + if (pentry->ObjectOwner.ulObj != ulOwner) { - LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj"); - (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId); + IncrementGdiHandleCount(); } } - else if (PrevProcId == LockedProcessId) - { - GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId); - /* the object is currently locked, wait some time and try again. - FIXME - we shouldn't loop forever! Give up after some time! */ - DelayExecution(); - /* try again */ - goto LockHandle; - } - else + // HACK + if (ulOwner == GDI_OBJ_HMGR_NONE) + ulOwner = GDI_OBJ_HMGR_PUBLIC; + + if (ulOwner == GDI_OBJ_HMGR_PUBLIC || + ulOwner == GDI_OBJ_HMGR_NONE) { - if (!Silent) + /* 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) { - 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(hObj); + DecrementGdiHandleCount(); } } - return FALSE; + /* Set new owner */ + pentry->ObjectOwner.ulObj = ulOwner; } +/* Locks 2 or 3 objects at a time */ BOOL -FASTCALL -IsObjectDead(HGDIOBJ hObject) +NTAPI +GDIOBJ_bLockMultipleObjects( + IN ULONG ulCount, + IN HGDIOBJ* ahObj, + OUT PGDIOBJ* apObj, + IN UCHAR objt) { - 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. - } -} + UINT auiIndices[3] = {0, 1, 2}; + UINT i, j, tmp; -/* - * Process Environment Cached GDI Handles - * - * What types of GDI handle objects that are cached in the GDI handle buffer? - * Brushes set to BS_SOLID, Pens with widths of zero or set to PS_SOLID, and - * Regions that are set to NULLREGION or SIMPLEREGION. - */ -BOOL -FASTCALL -bPEBCacheHandle(HGDIOBJ Handle, int oType, PVOID pAttr) -{ - PGDIHANDLECACHE GdiHandleCache; - HGDIOBJ *hPtr; - HANDLE Lock; - int Number, Offset, MaxNum = CACHE_PEN_ENTRIES; - BOOL Ret = FALSE; - - GdiHandleCache = (PGDIHANDLECACHE)NtCurrentTeb()->ProcessEnvironmentBlock->GdiHandleBuffer; - - switch (oType) - { - case hctBrushHandle: - Offset = 0; - MaxNum = CACHE_BRUSH_ENTRIES; - 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 ) - { - if ( Number < MaxNum ) - { // This object is cached and waiting for it's resurrection by the users. - ((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; -} + ASSERT(ulCount <= 3); -/*! - * Delete GDI object - * \param hObject object handle - * \return if the function fails the returned value is FALSE. -*/ -BOOL -FASTCALL -GreDeleteObject(HGDIOBJ hObject) -{ - INT Index; - PGDI_TABLE_ENTRY Entry; - DWORD dwObjectType; - INT ihct; - 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: - ihct = hctBrushHandle; - break; - - case GDI_OBJECT_TYPE_PEN: - ihct = hctPenHandle; - break; - - case GDI_OBJECT_TYPE_REGION: - ihct = hctRegionHandle; - break; - } - - switch (dwObjectType) - { -// case GDI_OBJECT_TYPE_BRUSH: -// case GDI_OBJECT_TYPE_PEN: - case GDI_OBJECT_TYPE_REGION: - /* If pAttr NULL, the probability is high for System GDI handle object. */ - if ( pAttr && - bPEBCacheHandle(hObject, ihct, 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 + /* Sort the handles */ + for (i = 0; i < ulCount - 1; i++) { - DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject); - return TRUE; // return true and move on. + for (j = i + 1; j < ulCount; j++) + { + if ((ULONG_PTR)ahObj[auiIndices[i]] < + (ULONG_PTR)ahObj[auiIndices[j]]) + { + tmp = auiIndices[i]; + auiIndices[i] = auiIndices[j]; + auiIndices[j] = tmp; + } + } } -} - -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) + /* Lock the objects in safe order */ + for (i = 0; i < ulCount; i++) { - ProcId = Process->UniqueProcessId; + /* Skip NULL handles */ + if (ahObj[auiIndices[i]] == NULL) + { + apObj[auiIndices[i]] = NULL; + continue; + } - /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj - we should delete it directly here! */ + /* Lock the object */ + apObj[auiIndices[i]] = GDIOBJ_LockObject(ahObj[auiIndices[i]], objt); - End = &GdiHandleTable->Entries[GDI_HANDLE_COUNT]; - for (Entry = &GdiHandleTable->Entries[RESERVE_ENTRIES_COUNT]; - Entry != End; - Entry++, Index++) + /* Check for failure */ + if (apObj[auiIndices[i]] == NULL) { - /* ignore the lock bit */ - if ( (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId) + /* Cleanup */ + while (i--) { - 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; - } - } + if (apObj[auiIndices[i]]) + GDIOBJ_vUnlockObject(apObj[auiIndices[i]]); } + return FALSE; } } -} + return TRUE; +} -/*! - * Internal function. Called when the process is destroyed to free the remaining GDI handles. - * \param Process - PID of the process that will be destroyed. -*/ -BOOL INTERNAL_CALL -GDI_CleanupForProcess(struct _EPROCESS *Process) +PVOID +NTAPI +GDIOBJ_pvGetObjectAttr(POBJ pobj) { - PEPROCESS CurrentProcess; - PPROCESSINFO W32Process; - - DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId); - CurrentProcess = PsGetCurrentProcess(); - if (CurrentProcess != Process) - { - KeAttachProcess(&Process->Pcb); - } - - W32Process = (PPROCESSINFO)CurrentProcess->Win32Process; - - /* Delete objects. Begin with types that are not referenced by other types */ - IntDeleteHandlesForProcess(Process, GDILoObjType_LO_DC_TYPE); - IntDeleteHandlesForProcess(Process, GDILoObjType_LO_BRUSH_TYPE); - IntDeleteHandlesForProcess(Process, GDILoObjType_LO_BITMAP_TYPE); - - /* Finally finish with what's left */ - IntDeleteHandlesForProcess(Process, GDI_OBJECT_TYPE_DONTCARE); - - if (CurrentProcess != Process) - { - KeDetachProcess(); - } - -#ifdef GDI_DEBUG - GdiDbgHTIntegrityCheck(); -#endif - - DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId); - if (W32Process->GDIHandleCount > 0) - { - DPRINT1("Leaking %d handles!\n", W32Process->GDIHandleCount); - } - - return TRUE; + ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); + return gpentHmgr[ulIndex].pUser; } -/*! - * Return pointer to the object by handle. - * - * \param hObj Object handle - * \return Pointer to the object. - * - * \note Process can only get pointer to the objects it created or global objects. - * - * \todo Get rid of the ExpectedType parameter! -*/ -PGDIOBJ INTERNAL_CALL -GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType) +VOID +NTAPI +GDIOBJ_vSetObjectAttr(POBJ pobj, PVOID pvObjAttr) { - ULONG HandleIndex; - PGDI_TABLE_ENTRY Entry; - HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId; - POBJ Object = NULL; - ULONG HandleType, HandleUpper; - - /* Check for dummy call */ - if(hObj == NULL) - return NULL ; + ULONG ulIndex; - GDIDBG_INITLOOPTRACE(); - - HandleIndex = GDI_HANDLE_GET_INDEX(hObj); - HandleType = GDI_HANDLE_GET_TYPE(hObj); - HandleUpper = GDI_HANDLE_GET_UPPER(hObj); - - /* Check that the handle index is valid. */ - if (HandleIndex >= GDI_HANDLE_COUNT ) - 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; - } + ASSERT(pobj->hHmgr); - ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1); + /* Get the handle index */ + ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); - /* - * Prevent the thread from being terminated during the locking process. - * It would result in undesired effects and inconsistency of the global - * handle table. - */ + /* Set pointer to the usermode attribute */ + gpentHmgr[ulIndex].pUser = pvObjAttr; +} - KeEnterCriticalRegion(); +VOID +NTAPI +GDIOBJ_vDeleteObject(POBJ pobj) +{ + ULONG ulIndex; - /* - * Loop until we either successfully lock the handle entry & object or - * fail some of the check. - */ + /* Set the object's delete flag */ + InterlockedOr16((SHORT*)&pobj->BaseFlags, BASEFLAG_READY_TO_DIE); + DBG_LOGEVENT(&pobj->slhLog, EVENT_DELETE, 0); - for (;;) + /* Get the handle index */ + ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); + if (ulIndex) { - HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1); - - /* Check for invalid owner. */ - if (ProcessId != HandleProcessId && HandleProcessId != NULL) - { - DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj, ProcessId, HandleProcessId); - GDIDBG_TRACECALLER(); - GDIDBG_TRACEALLOCATOR(hObj); - break; - } - - /* Lock the handle table entry. */ - LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1); - PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, - LockedProcessId, - HandleProcessId); + /* Reset the handle valid bit */ + InterlockedAnd((LONG*)&gpaulRefCount[ulIndex], ~REF_MASK_VALID); - if (PrevProcId == HandleProcessId) + /* Check if the object is exclusively locked */ + if (pobj->cExclusiveLock != 0) { - /* - * We're locking an object that belongs to our process or it's a - * global object if HandleProcessId is 0 here. - */ + /* Reset lock owner and lock count */ + pobj->dwThreadId = 0; + pobj->cExclusiveLock = 0; - if ( (Entry->KernelData != NULL) && - ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) ) - { - PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread(); - Object = Entry->KernelData; - - if (Object->cExclusiveLock == 0) - { - Object->Tid = Thread; - Object->cExclusiveLock = 1; - GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj)) -#if DBG - if (Thread) Thread->cExclusiveLocks++; -#endif - } - else - { - if (Object->Tid != Thread) - { - /* Unlock the handle table entry. */ - (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId); - - DelayExecution(); - continue; - } - InterlockedIncrement((PLONG)&Object->cExclusiveLock); -#if DBG - if (Thread) Thread->cExclusiveLocks++; -#endif - } - } - else - { - /* - * Debugging code. Report attempts to lock deleted handles and - * locking type mismatches. - */ - LockErrorDebugOutput(hObj, Entry, "GDIOBJ_LockObj"); - } - - /* Unlock the handle table entry. */ - (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId); - - break; - } - else - { - /* - * The handle is currently locked, wait some time and try again. - */ - GDIDBG_TRACELOOP(hObj, PrevProcId, NULL); - - DelayExecution(); - continue; + /* Release the pushlock and reenable APCs */ + ExReleasePushLockExclusive(&pobj->pushlock); + KeLeaveCriticalRegion(); } } - KeLeaveCriticalRegion(); - - return Object; + /* Dereference the object (will take care of deletion) */ + GDIOBJ_vDereferenceObject(pobj); } - -/*! - * Return pointer to the object by handle (and allow sharing of the handle - * across threads). - * - * \param hObj Object handle - * \return Pointer to the object. - * - * \note Process can only get pointer to the objects it created or global objects. - * - * \todo Get rid of the ExpectedType parameter! -*/ -PGDIOBJ INTERNAL_CALL -GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType) +BOOL +NTAPI +GreIsHandleValid(HGDIOBJ hobj) { - ULONG HandleIndex; - PGDI_TABLE_ENTRY Entry; - HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId; - POBJ Object = NULL; - ULONG_PTR HandleType, HandleUpper; - - /* Check for dummy call */ - if(hObj == NULL) - return NULL ; - - HandleIndex = GDI_HANDLE_GET_INDEX(hObj); - HandleType = GDI_HANDLE_GET_TYPE(hObj); - HandleUpper = GDI_HANDLE_GET_UPPER(hObj); - - /* Check that the handle index is valid. */ - if (HandleIndex >= GDI_HANDLE_COUNT) - return NULL; + PENTRY pentry; - /* 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 = &GdiHandleTable->Entries[HandleIndex]; + pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); + if (!pentry) return FALSE; + GDIOBJ_vDereferenceObject(pentry->einfo.pobj); + return TRUE; +} - ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1); - HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1); +BOOL +NTAPI +GreDeleteObject(HGDIOBJ hobj) +{ + PENTRY pentry; - /* Check for invalid owner. */ - if (ProcessId != HandleProcessId && HandleProcessId != NULL) + /* Check for stock objects */ + if (GDI_HANDLE_IS_STOCKOBJ(hobj)) { - return NULL; + DPRINT1("GreDeleteObject: Cannot delete stock object %p.\n", hobj); + return FALSE; } - /* - * 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 (;;) + /* Reference the handle entry */ + pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); + if (!pentry) { - /* 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 - 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; - } + DPRINT1("GreDeleteObject: Trying to delete invalid object %p\n", hobj); + return FALSE; } - KeLeaveCriticalRegion(); - - return Object; -} - -BOOL INTERNAL_CALL -GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle) -{ - PGDI_TABLE_ENTRY Entry; - HANDLE ProcessId; - BOOL Ret; - - DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle); - - if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle)) + /* Check for public owner */ + if (pentry->ObjectOwner.ulObj == GDI_OBJ_HMGR_PUBLIC) { - ProcessId = PsGetCurrentProcessId(); - - 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; + DPRINT1("GreDeleteObject: Trying to delete global object %p\n", hobj); + GDIOBJ_vDereferenceObject(pentry->einfo.pobj); + return FALSE; } - return FALSE; + /* Delete the object */ + GDIOBJ_vDeleteObject(pentry->einfo.pobj); + return TRUE; } -BOOL INTERNAL_CALL -GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj) +ULONG +NTAPI +GreGetObjectOwner(HGDIOBJ hobj) { - /* - * 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; - - GDIDBG_INITLOOPTRACE(); + ULONG ulIndex, ulOwner; - ASSERT(phObj); - hObj = *phObj; + /* Get the handle index */ + ulIndex = GDI_HANDLE_GET_INDEX(hobj); - DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj); - - Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread(); - - if (!GDI_HANDLE_IS_STOCKOBJ(hObj)) + /* Check if the handle is valid */ + if (ulIndex >= GDI_HANDLE_COUNT || + gpentHmgr[ulIndex].Objt == GDIObjType_DEF_TYPE || + ((ULONG_PTR)hobj >> 16) != gpentHmgr[ulIndex].FullUnique) { - ProcessId = PsGetCurrentProcessId(); - LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1); + DPRINT1("GreGetObjectOwner: invalid handle 0x%p.\n", hobj); + return GDI_OBJ_HMGR_RESTRICTED; + } - Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj); + /* Get the object owner */ + ulOwner = gpentHmgr[ulIndex].ObjectOwner.ulObj; -LockHandle: - /* lock the object, we must not convert stock objects, so don't check!!! */ - PrevProcId = InterlockedCompareExchangePointer((PVOID*)&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) - { - 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; - } - } - 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); + if (ulOwner == HandleToUlong(PsGetCurrentProcessId())) + return GDI_OBJ_HMGR_POWNED; - /* 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); - } - } + if (ulOwner == GDI_OBJ_HMGR_PUBLIC) + return GDI_OBJ_HMGR_PUBLIC; - return FALSE; + return GDI_OBJ_HMGR_RESTRICTED; } -BOOL INTERNAL_CALL -GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS NewOwner) +BOOL +NTAPI +GreSetObjectOwner( + HGDIOBJ hobj, + ULONG ulOwner) { - PGDI_TABLE_ENTRY Entry; - HANDLE ProcessId, LockedProcessId, PrevProcId; - PTHREADINFO Thread; - BOOL Ret = TRUE; - - GDIDBG_INITLOOPTRACE(); - - DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0)); + PENTRY pentry; - Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread(); + /* Check for stock objects */ + if (GDI_HANDLE_IS_STOCKOBJ(hobj)) + { + DPRINT("GreSetObjectOwner: got stock object %p\n", hobj); + return FALSE; + } - if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle)) + /* Reference the handle entry */ + pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); + if (!pentry) { - ProcessId = PsGetCurrentProcessId(); - LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1); + DPRINT("GreSetObjectOwner: invalid handle 0x%p.\n", hobj); + return FALSE; + } - Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle); + /* Call internal function */ + GDIOBJ_vSetObjectOwner(pentry->einfo.pobj, ulOwner); -LockHandle: - /* lock the object, we must not convert stock objects, so don't check!!! */ - PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, ProcessId, LockedProcessId); - if (PrevProcId == ProcessId) - { - PTHREADINFO PrevThread; + /* Dereference the object */ + GDIOBJ_vDereferenceObject(pentry->einfo.pobj); - if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0) - { - POBJ Object = Entry->KernelData; - - PrevThread = Object->Tid; - if (Object->cExclusiveLock == 0 || PrevThread == Thread) - { - PEPROCESS OldProcess; - PPROCESSINFO W32Process; - NTSTATUS Status; - - if (NewOwner != NULL) - { - ProcessId = PsGetProcessId(NewOwner); - } - else - ProcessId = 0; - - if((ULONG_PTR)ProcessId == ((ULONG_PTR)PrevProcId & ~0x1)) - { - DPRINT("Setting same process than previous one, nothing to do\n"); - goto done; - } - - /* dereference the process' object counter */ - /* FIXME */ - if ((ULONG_PTR)PrevProcId & ~0x1) - { - 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) - { - /* Increase the new process' object counter */ - W32Process = (PPROCESSINFO)NewOwner->Win32Process; - if (W32Process != NULL) - { - InterlockedIncrement(&W32Process->GDIHandleCount); - } - } - - done: - /* 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; - } - } - 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); - Ret = FALSE; - } - } - else if (PrevProcId == LockedProcessId) - { - GDIDBG_TRACELOOP(ObjectHandle, PrevProcId, ProcessId); - - /* the object is currently locked, wait some time and try again. - FIXME - we shouldn't loop forever! Give up after some time! */ - DelayExecution(); - /* 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 - { - DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle); - Ret = FALSE; - } - } - return Ret; + return TRUE; } -BOOL INTERNAL_CALL -GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo) +INT +NTAPI +GreGetObject( + IN HGDIOBJ hobj, + IN INT cbCount, + IN PVOID pvBuffer) { - PGDI_TABLE_ENTRY FromEntry; - PTHREADINFO Thread; - HANDLE FromProcessId, FromLockedProcessId, FromPrevProcId; - BOOL Ret = TRUE; - - GDIDBG_INITLOOPTRACE(); - - DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo); - - Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread(); + PVOID pvObj; + UCHAR objt; + INT iResult = 0; + + /* Verify object type */ + objt = ((ULONG_PTR)hobj >> 16) & 0x1f; + if (objt != GDIObjType_BRUSH_TYPE && + objt != GDIObjType_SURF_TYPE && + objt != GDIObjType_LFONT_TYPE && + objt != GDIObjType_PAL_TYPE) + { + DPRINT1("GreGetObject: invalid object type\n"); + return 0; + } - if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo)) + pvObj = GDIOBJ_ReferenceObjectByHandle(hobj, objt); + if (!pvObj) { - FromEntry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, CopyFrom); + DPRINT("GreGetObject: Could not lock object\n"); + EngSetLastError(ERROR_INVALID_HANDLE); + return 0; + } - FromProcessId = (HANDLE)((ULONG_PTR)FromEntry->ProcessId & ~0x1); - FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1); + switch (GDI_HANDLE_GET_TYPE(hobj)) + { + case GDILoObjType_LO_PEN_TYPE: + case GDILoObjType_LO_EXTPEN_TYPE: + iResult = PEN_GetObject(pvObj, cbCount, pvBuffer); + break; -LockHandleFrom: - /* lock the object, we must not convert stock objects, so don't check!!! */ - FromPrevProcId = InterlockedCompareExchangePointer((PVOID*)&FromEntry->ProcessId, FromProcessId, FromLockedProcessId); - if (FromPrevProcId == FromProcessId) - { - PTHREADINFO PrevThread; - POBJ Object; + case GDILoObjType_LO_BRUSH_TYPE: + iResult = BRUSH_GetObject(pvObj, cbCount, pvBuffer); + break; - if ((FromEntry->Type & GDI_ENTRY_BASETYPE_MASK) != 0) - { - 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 + case GDILoObjType_LO_BITMAP_TYPE: + iResult = BITMAP_GetObject(pvObj, cbCount, pvBuffer); + break; + case GDILoObjType_LO_FONT_TYPE: + iResult = FontGetObject(pvObj, cbCount, pvBuffer); +#if 0 + // Fix the LOGFONT structure for the stock fonts + if (FIRST_STOCK_HANDLE <= hobj && hobj <= LAST_STOCK_HANDLE) { - DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom); - Ret = FALSE; + FixStockFontSizeW(hobj, cbCount, pvBuffer); } - } - else if (FromPrevProcId == FromLockedProcessId) - { - GDIDBG_TRACELOOP(CopyFrom, FromPrevProcId, FromProcessId); +#endif + break; - /* 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); - Ret = FALSE; - } + case GDILoObjType_LO_PALETTE_TYPE: + iResult = PALETTE_GetObject(pvObj, cbCount, pvBuffer); + break; + + default: + DPRINT1("GDI object type of 0x%p not implemented\n", hobj); + break; } - return Ret; + + GDIOBJ_vDereferenceObject(pvObj); + return iResult; } -PVOID INTERNAL_CALL -GDI_MapHandleTable(PEPROCESS Process) +W32KAPI +INT +APIENTRY +NtGdiExtGetObjectW( + IN HANDLE hobj, + IN INT cbCount, + OUT LPVOID lpBuffer) { - PVOID MappedView = NULL; - NTSTATUS Status; - LARGE_INTEGER Offset; - ULONG ViewSize = sizeof(GDI_HANDLE_TABLE); - - Offset.QuadPart = 0; - - ASSERT(GdiTableSection != NULL); - ASSERT(Process != NULL); - - Status = MmMapViewOfSection(GdiTableSection, - Process, - &MappedView, - 0, - 0, - &Offset, - &ViewSize, - ViewUnmap, - SEC_NO_CHANGE, - PAGE_READONLY); - - if (!NT_SUCCESS(Status)) - return NULL; + INT iRetCount = 0; + INT cbCopyCount; + union + { + BITMAP bitmap; + DIBSECTION dibsection; + LOGPEN logpen; + LOGBRUSH logbrush; + LOGFONTW logfontw; + EXTLOGFONTW extlogfontw; + ENUMLOGFONTEXDVW enumlogfontexdvw; + } object; - return MappedView; -} + /* Normalize to the largest supported object size */ + cbCount = min((UINT)cbCount, sizeof(object)); -/* Locks 2 or 3 objects at a time */ -VOID -INTERNAL_CALL -GDIOBJ_LockMultipleObjs(ULONG ulCount, - IN HGDIOBJ* ahObj, - OUT PGDIOBJ* apObj) -{ - UINT auiIndices[3] = {0,1,2}; - UINT i, tmp ; - BOOL bUnsorted = TRUE; + /* Now do the actual call */ + iRetCount = GreGetObject(hobj, cbCount, lpBuffer ? &object : NULL); + cbCopyCount = min((UINT)cbCount, (UINT)iRetCount); - /* First is greatest */ - while(bUnsorted) + /* Make sure we have a buffer and a copy size */ + if ((cbCopyCount) && (lpBuffer)) { - bUnsorted = FALSE; - for(i=1; iEntries[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; + /* Return the count */ + return iRetCount; } W32KAPI HANDLE APIENTRY NtGdiCreateClientObj( - IN ULONG ulType -) + IN ULONG ulType) { POBJ pObject; HANDLE handle; - /* Mask out everything that would change the type in a wrong manner */ - ulType &= (GDI_HANDLE_TYPE_MASK & ~GDI_HANDLE_BASETYPE_MASK); - /* Allocate a new object */ - pObject = GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ | ulType); + pObject = GDIOBJ_AllocateObject(GDIObjType_CLIENTOBJ_TYPE, + sizeof(CLIENTOBJ), + BASEFLAG_LOOKASIDE); if (!pObject) { + DPRINT1("NtGdiCreateClientObj: Could not allocate a clientobj.\n"); return NULL; } - /* get the handle */ - handle = pObject->hHmgr; + /* Mask out everything that would change the type in a wrong manner */ + ulType &= (GDI_HANDLE_TYPE_MASK & ~GDI_HANDLE_BASETYPE_MASK); + + /* Set the real object type */ + pObject->hHmgr = UlongToHandle(ulType | GDILoObjType_LO_CLIENTOBJ_TYPE); + + /* Create a handle */ + handle = GDIOBJ_hInsertObject(pObject, GDI_OBJ_HMGR_POWNED); + if (!handle) + { + DPRINT1("NtGdiCreateClientObj Could not create a handle.\n"); + GDIOBJ_vFreeObject(pObject); + return NULL; + } /* Unlock it */ - GDIOBJ_UnlockObjByPtr(pObject); + GDIOBJ_vUnlockObject(pObject); return handle; } @@ -1782,127 +1156,185 @@ W32KAPI BOOL APIENTRY NtGdiDeleteClientObj( - IN HANDLE h -) + IN HANDLE hobj) { /* We first need to get the real type from the handle */ - ULONG type = GDI_HANDLE_GET_TYPE(h); + ULONG ulType = GDI_HANDLE_GET_TYPE(hobj); /* Check if it's really a CLIENTOBJ */ - if ((type & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE) + if ((ulType & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE) { /* FIXME: SetLastError? */ return FALSE; } - return GDIOBJ_FreeObjByHandle(h, type); + + return GreDeleteObject(hobj); } -INT -FASTCALL -IntGdiGetObject(IN HANDLE Handle, - IN INT cbCount, - IN LPVOID lpBuffer) + + +PGDI_HANDLE_TABLE GdiHandleTable = NULL; + +PGDIOBJ INTERNAL_CALL +GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType) { - PVOID pGdiObject; - INT Result = 0; - DWORD dwObjectType; + if (ExpectedType == GDI_OBJECT_TYPE_DONTCARE) + ExpectedType = GDI_HANDLE_GET_TYPE(hObj); + return GDIOBJ_ReferenceObjectByHandle(hObj, (ExpectedType >> 16) & 0x1f); +} - pGdiObject = GDIOBJ_LockObj(Handle, GDI_OBJECT_TYPE_DONTCARE); - if (!pGdiObject) +// This function is not safe to use with concurrent deleting attempts +// That shouldn't be a problem, since we don't have any processes yet, +// that could delete the handle +BOOL +INTERNAL_CALL +GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj) +{ + PENTRY pentry; + POBJ pobj; + + /* Reference the handle entry */ + pentry = ENTRY_ReferenceEntryByHandle(*phObj, 0); + if (!pentry) { - EngSetLastError(ERROR_INVALID_HANDLE); - return 0; + DPRINT1("GDIOBJ: requested handle 0x%p is not valid.\n", *phObj); + return FALSE; } - 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; + /* Update the entry */ + pentry->FullUnique |= GDI_ENTRY_STOCK_MASK; + pentry->ObjectOwner.ulObj = 0; - case GDI_OBJECT_TYPE_PALETTE: - Result = PALETTE_GetObject((PPALETTE) pGdiObject, cbCount, lpBuffer); - break; + /* Get the pointer to the BASEOBJECT */ + pobj = pentry->einfo.pobj; - default: - DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType); - break; - } + /* Calculate the new handle */ + pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)pobj->hHmgr | GDI_HANDLE_STOCK_MASK); + + /* Return the new handle */ + *phObj = pobj->hHmgr; - GDIOBJ_UnlockObjByPtr(pGdiObject); + /* Dereference the handle */ + GDIOBJ_vDereferenceObject(pobj); - return Result; + return TRUE; } +POBJ INTERNAL_CALL +GDIOBJ_AllocObjWithHandle(ULONG ObjectType, ULONG cjSize) +{ + POBJ pobj; + FLONG fl = 0; + UCHAR objt = ObjectType >> 16; + + if ((objt == GDIObjType_DC_TYPE && cjSize == sizeof(DC)) || + (objt == GDIObjType_PAL_TYPE && cjSize == sizeof(PALETTE)) || + (objt == GDIObjType_RGN_TYPE && cjSize == sizeof(REGION)) || + (objt == GDIObjType_SURF_TYPE && cjSize == sizeof(SURFACE)) || + (objt == GDIObjType_PATH_TYPE && cjSize == sizeof(PATH))) + { + fl |= BASEFLAG_LOOKASIDE; + } + pobj = GDIOBJ_AllocateObject(objt, cjSize, fl); + if (!GDIOBJ_hInsertObject(pobj, GDI_OBJ_HMGR_POWNED)) + { + GDIOBJ_vFreeObject(pobj); + return NULL; + } + return pobj; +} -W32KAPI -INT -APIENTRY -NtGdiExtGetObjectW(IN HANDLE hGdiObj, - IN INT cbCount, - OUT LPVOID lpBuffer) +PVOID INTERNAL_CALL +GDI_MapHandleTable(PEPROCESS pProcess) { - INT iRetCount = 0; - INT cbCopyCount; - union - { - BITMAP bitmap; - DIBSECTION dibsection; - LOGPEN logpen; - LOGBRUSH logbrush; - LOGFONTW logfontw; - EXTLOGFONTW extlogfontw; - ENUMLOGFONTEXDVW enumlogfontexdvw; - } Object; + PVOID pvMappedView = NULL; + NTSTATUS Status; + LARGE_INTEGER liOffset; + ULONG cjViewSize = sizeof(GDI_HANDLE_TABLE); - // Normalize to the largest supported object size - cbCount = min((UINT)cbCount, sizeof(Object)); + liOffset.QuadPart = 0; - // Now do the actual call - iRetCount = IntGdiGetObject(hGdiObj, cbCount, lpBuffer ? &Object : NULL); - cbCopyCount = min((UINT)cbCount, (UINT)iRetCount); + ASSERT(gpvGdiHdlTblSection != NULL); + ASSERT(pProcess != NULL); - // Make sure we have a buffer and a copy size - if ((cbCopyCount) && (lpBuffer)) + Status = MmMapViewOfSection(gpvGdiHdlTblSection, + pProcess, + &pvMappedView, + 0, + 0, + &liOffset, + &cjViewSize, + ViewUnmap, + SEC_NO_CHANGE, + PAGE_READONLY); + + if (!NT_SUCCESS(Status)) + return NULL; + + return pvMappedView; +} + +BOOL INTERNAL_CALL +GDI_CleanupForProcess(struct _EPROCESS *Process) +{ + PENTRY pentry; + ULONG ulIndex; + DWORD dwProcessId; + PPROCESSINFO ppi; + + DPRINT("CleanupForProcess prochandle %x Pid %d\n", + Process, Process->UniqueProcessId); + + ASSERT(Process == PsGetCurrentProcess()); + + /* Get the current process Id */ + dwProcessId = PtrToUlong(PsGetCurrentProcessId()); + + /* Loop all handles in the handle table */ + for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++) { - // Enter SEH for buffer transfer - _SEH2_TRY + pentry = &gpentHmgr[ulIndex]; + + /* Check if the object is owned by the process */ + if (pentry->ObjectOwner.ulObj == dwProcessId) { - // Probe the buffer and copy it - ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD)); - RtlCopyMemory(lpBuffer, &Object, cbCopyCount); + ASSERT(pentry->einfo.pobj->cExclusiveLock == 0); + + /* Reference the object and delete it */ + InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]); + GDIOBJ_vDeleteObject(pentry->einfo.pobj); } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + } + +//#ifdef GDI_DEBUG + DbgGdiHTIntegrityCheck(); +//#endif + + ppi = PsGetCurrentProcessWin32Process(); + DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId); + if (ppi->GDIHandleCount != 0) + { + DPRINT1("Leaking %d handles!\n", ppi->GDIHandleCount); + ASSERT(FALSE); + } + + /* Loop all handles in the handle table */ + for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++) + { + pentry = &gpentHmgr[ulIndex]; + + /* Check if the object is owned by the process */ + if (pentry->ObjectOwner.ulObj == dwProcessId) { - // Clear the return value. - // Do *NOT* set last error here! - iRetCount = 0; + DPRINT1("Leaking object. Index=%lx, type=0x%x, refcount=%lx\n", + ulIndex, pentry->Objt, gpaulRefCount[ulIndex]); + DBG_DUMP_EVENT_LIST(&pentry->einfo.pobj->slhLog); + //DBG_CLEANUP_EVENT_LIST(&pentry->einfo.pobj->slhLog); + ASSERT(FALSE); } - _SEH2_END; } - // Return the count - return iRetCount; + + return TRUE; } -/* EOF */