/** INCLUDES ******************************************************************/
-#include <w32k.h>
+#define GDI_DEBUG
+
+#include <win32k.h>
#define NDEBUG
#include <debug.h>
/* apparently the first 10 entries are never used in windows as they are empty */
#define RESERVE_ENTRIES_COUNT 10
+#define BASE_OBJTYPE_COUNT 32
+
#define DelayExecution() \
DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
-static BOOL INTERNAL_CALL GDI_CleanupDummy(PVOID ObjectBody);
+#include "gdidbg.c"
+
+static
+BOOL INTERNAL_CALL GDI_CleanupDummy(PVOID ObjectBody);
/** GLOBALS *******************************************************************/
} 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), 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(BITMAPOBJ), TAG_SURFACE, BITMAP_Cleanup}, /* 05 SURFACE */
+ {1, sizeof(SURFACE), TAG_SURFACE, SURFACE_Cleanup}, /* 05 SURFACE */
{1, sizeof(CLIENTOBJ), TAG_CLIENTOBJ, GDI_CleanupDummy}, /* 06 CLIENTOBJ: METADC,... */
- {0, 0, TAG_PATH, NULL}, /* 07 PATH, unused */
- {1, sizeof(PALGDI), TAG_PALETTE, PALETTE_Cleanup}, /* 08 PAL */
+ {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_PFT, NULL}, /* 0d PFT, unused */
{0, sizeof(GDICLRXFORM), TAG_ICMCXF, GDI_CleanupDummy}, /* 0e ICMCXF, */
{0, 0, TAG_SPRITE, NULL}, /* 0f SPRITE, unused */
- {1, sizeof(GDIBRUSHOBJ), TAG_BRUSH, BRUSH_Cleanup}, /* 10 BRUSH, PEN, EXTPEN */
+ {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, TAG_TTFD, NULL}, /* 19 TTFD, unused */
{0, 0, TAG_RC, NULL}, /* 1a RC, unused */
{0, 0, TAG_TEMP, NULL}, /* 1b TEMP, unused */
- {0, 0, TAG_DRVOBJ, NULL}, /* 1c DRVOBJ, 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;
-/** DEBUGGING *****************************************************************/
-//#define GDI_DEBUG
-#include "gdidbg.c"
-
/** 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 BOOL INTERNAL_CALL
+static
+BOOL INTERNAL_CALL
GDI_CleanupDummy(PVOID ObjectBody)
{
return TRUE;
ULONG
FASTCALL
-InterlockedPopFreeEntry()
+InterlockedPopFreeEntry(VOID)
{
- ULONG idxFirstFree, idxNextFree, idxPrev;
- PGDI_TABLE_ENTRY pFreeEntry;
+ ULONG idxFirst, idxNext, idxPrev;
+ PGDI_TABLE_ENTRY pEntry;
+ DWORD PrevProcId;
DPRINT("Enter InterLockedPopFreeEntry\n");
- do
+ while (TRUE)
{
- idxFirstFree = GdiHandleTable->FirstFree;
- if (idxFirstFree)
- {
- pFreeEntry = GdiHandleTable->Entries + idxFirstFree;
- ASSERT(((ULONG)pFreeEntry->KernelData & ~GDI_HANDLE_INDEX_MASK) == 0);
- idxNextFree = (ULONG)pFreeEntry->KernelData;
- idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree, idxNextFree, idxFirstFree);
- }
- else
+ idxFirst = GdiHandleTable->FirstFree;
+
+ if (!idxFirst)
{
- idxFirstFree = GdiHandleTable->FirstUnused;
- idxNextFree = idxFirstFree + 1;
- if (idxNextFree >= GDI_HANDLE_COUNT)
+ /* 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;
}
- idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstUnused, idxNextFree, idxFirstFree);
+
+ /* 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;
}
}
- while (idxPrev != idxFirstFree);
- return idxFirstFree;
+ return idxFirst;
}
/* Pushes an entry of the handle table to the free list,
do
{
idxFirstFree = GdiHandleTable->FirstFree;
- pFreeEntry->KernelData = (PVOID)idxFirstFree;
+ pFreeEntry->KernelData = (PVOID)(ULONG_PTR)idxFirstFree;
- idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree, idxToFree, idxFirstFree);
+ idxPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree,
+ idxToFree,
+ idxFirstFree);
}
while (idxPrev != idxFirstFree);
}
POBJ INTERNAL_CALL
GDIOBJ_AllocObjWithHandle(ULONG ObjectType)
{
- PW32PROCESS W32Process;
+ 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->GDIObjects >= 0x2710)
+ 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;
}
return NULL;
}
- UINT Index;
- PGDI_TABLE_ENTRY Entry;
- LONG TypeInfo;
-
CurrentProcessId = PsGetCurrentProcessId();
LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1);
Entry = &GdiHandleTable->Entries[Index];
LockHandle:
- PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, 0);
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, 0);
if (PrevProcId == NULL)
{
- PW32THREAD Thread = PsGetCurrentThreadWin32Thread();
+ PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
HGDIOBJ Handle;
Entry->KernelData = newObject;
newObject->cExclusiveLock = 1;
newObject->Tid = Thread;
+ AllocTypeDataDump(TypeInfo);
+
/* unlock the entry */
- (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId);
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId);
GDIDBG_CAPTUREALLOCATOR(Index);
if (W32Process != NULL)
{
- _InterlockedIncrement(&W32Process->GDIObjects);
+ InterlockedIncrement(&W32Process->GDIHandleCount);
}
DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, newObject);
* \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)
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);
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
if (PrevProcId == ProcessId)
{
if ( (Entry->KernelData != NULL) &&
Object = Entry->KernelData;
- if (Object->cExclusiveLock == 0)
+ if ((Object->cExclusiveLock == 0 ||
+ Object->Tid == (PTHREADINFO)PsGetCurrentThreadWin32Thread()) &&
+ Object->ulShareCount == 0)
{
BOOL Ret;
- PW32PROCESS W32Process = PsGetCurrentProcessWin32Process();
+ PPROCESSINFO 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;
/* unlock the handle slot */
- (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL);
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL);
/* push this entry to the free list */
InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable, Entry));
if (W32Process != NULL)
{
- _InterlockedDecrement(&W32Process->GDIObjects);
+ InterlockedDecrement(&W32Process->GDIHandleCount);
}
/* call the cleanup routine. */
TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(HandleType);
Ret = ObjTypeInfo[TypeIndex].CleanupProc(Object);
+ DeAllocTypeDataDump(HandleType);
+
/* Now it's time to free the memory */
GDIOBJ_FreeObj(Object, TypeIndex);
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, so freeing is forbidden!
+ * 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);
+ 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 */
- //ASSERT(FALSE);
+
+ DelayExecution();
+ goto LockHandle;
}
}
else
{
LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj");
- (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
}
}
else if (PrevProcId == LockedProcessId)
}
DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry->Type, Entry->KernelData, Entry->ProcessId);
GDIDBG_TRACECALLER();
- GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj));
+ GDIDBG_TRACEALLOCATOR(hObj);
}
}
}
+BOOL
+FASTCALL
+bPEBCacheHandle(HGDIOBJ Handle, int oType, PVOID pAttr)
+{
+ PGDIHANDLECACHE GdiHandleCache;
+ HGDIOBJ *hPtr;
+ BOOL Ret = FALSE;
+ int Offset = 0, Number;
+ HANDLE Lock;
+
+ GdiHandleCache = (PGDIHANDLECACHE)NtCurrentTeb()->ProcessEnvironmentBlock->GdiHandleBuffer;
+
+ switch (oType)
+ {
+ case hctBrushHandle:
+ Offset = 0;
+ break;
+
+ case hctPenHandle:
+ Offset = CACHE_BRUSH_ENTRIES;
+ break;
+
+ case hctRegionHandle:
+ Offset = CACHE_BRUSH_ENTRIES+CACHE_PEN_ENTRIES;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ Lock = InterlockedCompareExchangePointer( (PVOID*)&GdiHandleCache->ulLock,
+ NtCurrentTeb(),
+ NULL );
+ if (Lock) return FALSE;
+
+ _SEH2_TRY
+ {
+ Number = GdiHandleCache->ulNumHandles[oType];
+
+ hPtr = GdiHandleCache->Handle + Offset;
+
+ if ( pAttr && oType == hctRegionHandle)
+ {
+ if ( Number < CACHE_REGION_ENTRIES )
+ {
+ ((PRGN_ATTR)pAttr)->AttrFlags |= ATTR_CACHED;
+ hPtr[Number] = Handle;
+ GdiHandleCache->ulNumHandles[oType]++;
+ DPRINT("Put Handle Count %d PEB 0x%x\n", GdiHandleCache->ulNumHandles[oType], NtCurrentTeb()->ProcessEnvironmentBlock);
+ Ret = TRUE;
+ }
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Ret = FALSE;
+ }
+ _SEH2_END;
+
+ (void)InterlockedExchangePointer((PVOID*)&GdiHandleCache->ulLock, Lock);
+ return Ret;
+}
+
/*!
* Delete GDI object
* \param hObject object handle
*/
BOOL
FASTCALL
-NtGdiDeleteObject(HGDIOBJ hObject)
+GreDeleteObject(HGDIOBJ hObject)
{
+ INT Index;
+ PGDI_TABLE_ENTRY Entry;
+ DWORD dwObjectType;
+ PVOID pAttr = NULL;
+
DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
if (!IsObjectDead(hObject))
{
- return NULL != hObject
- ? GDIOBJ_FreeObjByHandle(hObject, GDI_OBJECT_TYPE_DONTCARE) : FALSE;
+ dwObjectType = GDIOBJ_GetObjectType(hObject);
+
+ Index = GDI_HANDLE_GET_INDEX(hObject);
+ Entry = &GdiHandleTable->Entries[Index];
+ pAttr = Entry->UserData;
+
+ switch (dwObjectType)
+ {
+ case GDI_OBJECT_TYPE_BRUSH:
+ break;
+
+ case GDI_OBJECT_TYPE_REGION:
+ /* If pAttr NULL, the probability is high for System Region. */
+ if ( pAttr &&
+ bPEBCacheHandle(hObject, hctRegionHandle, pAttr))
+ {
+ /* User space handle only! */
+ return TRUE;
+ }
+ if (pAttr)
+ {
+ FreeObjectAttr(pAttr);
+ Entry->UserData = NULL;
+ }
+ break;
+
+ case GDI_OBJECT_TYPE_DC:
+// DC_FreeDcAttr(hObject);
+ break;
+ }
+
+ return NULL != hObject
+ ? GDIOBJ_FreeObjByHandle(hObject, dwObjectType) : FALSE;
}
else
{
PGDI_TABLE_ENTRY Entry, End;
ULONG Index = RESERVE_ENTRIES_COUNT;
HANDLE ProcId;
- PW32PROCESS W32Process;
+ PPROCESSINFO W32Process;
- W32Process = (PW32PROCESS)Process->Win32Process;
+ W32Process = (PPROCESSINFO)Process->Win32Process;
ASSERT(W32Process);
- if (W32Process->GDIObjects > 0)
+ if (W32Process->GDIHandleCount > 0)
{
ProcId = Process->UniqueProcessId;
simply ignore this fact here. */
ObjectHandle = (HGDIOBJ)(Index | (Entry->Type << GDI_ENTRY_UPPER_SHIFT));
- if (GDIOBJ_FreeObjByHandle(ObjectHandle, GDI_OBJECT_TYPE_DONTCARE) &&
- W32Process->GDIObjects == 0)
+ 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;
GDI_CleanupForProcess(struct _EPROCESS *Process)
{
PEPROCESS CurrentProcess;
+ PPROCESSINFO W32Process;
DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId);
CurrentProcess = PsGetCurrentProcess();
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);
#endif
DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);
+ if (W32Process->GDIHandleCount > 0)
+ {
+ DPRINT1("Leaking %d handles!\n", W32Process->GDIHandleCount);
+ }
return TRUE;
}
POBJ Object = NULL;
ULONG HandleType, HandleUpper;
+ /* Check for dummy call */
+ if(hObj == NULL)
+ return NULL ;
+
+ GDIDBG_INITLOOPTRACE();
+
HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
HandleType = GDI_HANDLE_GET_TYPE(hObj);
HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
/* Check that the handle index is valid. */
- if (HandleIndex >= GDI_HANDLE_COUNT)
+ if (HandleIndex >= GDI_HANDLE_COUNT )
return NULL;
Entry = &GdiHandleTable->Entries[HandleIndex];
HandleType != ExpectedType) ||
HandleType == 0 )
{
- DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
+ DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
hObj, HandleType, ExpectedType);
GDIDBG_TRACECALLER();
GDIDBG_TRACEALLOCATOR(hObj);
{
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));
+ GDIDBG_TRACEALLOCATOR(hObj);
return NULL;
}
{
/* Lock the handle table entry. */
LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
- PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
LockedProcessId,
HandleProcessId);
if ( (Entry->KernelData != NULL) &&
((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
{
- PW32THREAD Thread = PsGetCurrentThreadWin32Thread();
+ PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
Object = Entry->KernelData;
if (Object->cExclusiveLock == 0)
if (Object->Tid != Thread)
{
/* Unlock the handle table entry. */
- (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
DelayExecution();
continue;
}
- _InterlockedIncrement((PLONG)&Object->cExclusiveLock);
+ InterlockedIncrement((PLONG)&Object->cExclusiveLock);
}
}
else
}
/* Unlock the handle table entry. */
- (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
break;
}
/*
* The handle is currently locked, wait some time and try again.
*/
+ GDIDBG_TRACELOOP(hObj, PrevProcId, NULL);
DelayExecution();
continue;
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);
{
/* Lock the handle table entry. */
LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
- PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
LockedProcessId,
HandleProcessId);
{
Object = (POBJ)Entry->KernelData;
-#ifdef GDI_DEBUG
- if (_InterlockedIncrement((PLONG)&Object->ulShareCount) == 1)
+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*)GDIHandleLocker[HandleIndex], NULL);
+ RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleShareLocker[HandleIndex], NULL);
}
#else
- _InterlockedIncrement((PLONG)&Object->ulShareCount);
+ InterlockedIncrement((PLONG)&Object->ulShareCount);
#endif
}
else
}
/* Unlock the handle table entry. */
- (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
break;
}
return Object;
}
-
-/*!
- * 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.
-
- * \param Object Object pointer (as returned by GDIOBJ_LockObj).
- */
-VOID INTERNAL_CALL
-GDIOBJ_UnlockObjByPtr(POBJ Object)
-{
- if (_InterlockedDecrement((PLONG)&Object->cExclusiveLock) < 0)
- {
- DPRINT1("Trying to unlock non-existant object\n");
- }
-}
-
-VOID INTERNAL_CALL
-GDIOBJ_ShareUnlockObjByPtr(POBJ Object)
-{
- if (_InterlockedDecrement((PLONG)&Object->ulShareCount) < 0)
- {
- DPRINT1("Trying to unlock non-existant object\n");
- }
-}
-
BOOL INTERNAL_CALL
GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle)
{
*/
PGDI_TABLE_ENTRY Entry;
HANDLE ProcessId, LockedProcessId, PrevProcId;
- PW32THREAD Thread;
+ PTHREADINFO Thread;
HGDIOBJ hObj;
GDIDBG_INITLOOPTRACE();
DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj);
- Thread = PsGetCurrentThreadWin32Thread();
+ Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
if (!GDI_HANDLE_IS_STOCKOBJ(hObj))
{
LockHandle:
/* lock the object, we must not convert stock objects, so don't check!!! */
- PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
if (PrevProcId == ProcessId)
{
LONG NewType, PrevType, OldType;
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);
+ PrevType = InterlockedCompareExchange(&Entry->Type, NewType, OldType);
if (PrevType == OldType && Entry->KernelData != NULL)
{
- PW32THREAD PrevThread;
+ PTHREADINFO PrevThread;
POBJ Object;
/* We successfully set the stock object flag.
if (PrevProcId != GDI_GLOBAL_PROCESS)
{
PEPROCESS OldProcess;
- PW32PROCESS W32Process;
+ PPROCESSINFO W32Process;
NTSTATUS Status;
/* FIXME */
Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
if (NT_SUCCESS(Status))
{
- W32Process = (PW32PROCESS)OldProcess->Win32Process;
+ W32Process = (PPROCESSINFO)OldProcess->Win32Process;
if (W32Process != NULL)
{
- _InterlockedDecrement(&W32Process->GDIObjects);
+ InterlockedDecrement(&W32Process->GDIHandleCount);
}
ObDereferenceObject(OldProcess);
}
Object->hHmgr = hObj;
/* remove the process id lock and make it global */
- (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, GDI_GLOBAL_PROCESS);
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, GDI_GLOBAL_PROCESS);
/* we're done, successfully converted the object */
return TRUE;
/* 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);
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
DelayExecution();
goto LockHandle;
{
PGDI_TABLE_ENTRY Entry;
HANDLE ProcessId, LockedProcessId, PrevProcId;
- PW32THREAD Thread;
+ PTHREADINFO Thread;
BOOL Ret = TRUE;
GDIDBG_INITLOOPTRACE();
DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0));
- Thread = PsGetCurrentThreadWin32Thread();
+ Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
{
LockHandle:
/* lock the object, we must not convert stock objects, so don't check!!! */
- PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, ProcessId, LockedProcessId);
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, ProcessId, LockedProcessId);
if (PrevProcId == ProcessId)
{
- PW32THREAD PrevThread;
+ PTHREADINFO PrevThread;
if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
{
if (Object->cExclusiveLock == 0 || PrevThread == Thread)
{
PEPROCESS OldProcess;
- PW32PROCESS W32Process;
+ 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 = (PW32PROCESS)OldProcess->Win32Process;
+ W32Process = (PPROCESSINFO)OldProcess->Win32Process;
if (W32Process != NULL)
{
- _InterlockedDecrement(&W32Process->GDIObjects);
+ InterlockedDecrement(&W32Process->GDIHandleCount);
}
ObDereferenceObject(OldProcess);
}
if (NewOwner != NULL)
{
- ProcessId = PsGetProcessId(NewOwner);
-
/* Increase the new process' object counter */
- W32Process = (PW32PROCESS)NewOwner->Win32Process;
+ W32Process = (PPROCESSINFO)NewOwner->Win32Process;
if (W32Process != NULL)
{
- _InterlockedIncrement(&W32Process->GDIObjects);
+ InterlockedIncrement(&W32Process->GDIHandleCount);
}
}
- else
- ProcessId = 0;
+ done:
/* remove the process id lock and change it to the new process id */
- (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, ProcessId);
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, ProcessId);
/* we're done! */
return Ret;
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);
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
DelayExecution();
goto LockHandle;
GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
{
PGDI_TABLE_ENTRY FromEntry;
- PW32THREAD Thread;
+ PTHREADINFO Thread;
HANDLE FromProcessId, FromLockedProcessId, FromPrevProcId;
BOOL Ret = TRUE;
DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo);
- Thread = PsGetCurrentThreadWin32Thread();
+ Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo))
{
LockHandleFrom:
/* lock the object, we must not convert stock objects, so don't check!!! */
- FromPrevProcId = _InterlockedCompareExchangePointer((PVOID*)&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
+ FromPrevProcId = InterlockedCompareExchangePointer((PVOID*)&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
if (FromPrevProcId == FromProcessId)
{
- PW32THREAD PrevThread;
+ PTHREADINFO PrevThread;
POBJ Object;
if ((FromEntry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
GDIOBJ_SetOwnership(CopyTo, NULL);
}
- (void)_InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
+ (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
}
else
{
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);
+ (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
DelayExecution();
goto LockHandleFrom;
return MappedView;
}
-/** PUBLIC FUNCTIONS **********************************************************/
-
-/*
- Since Brush/Pen and Region objects are sharable,,, we can just use
- UserHeapAlloc to allocate the small attribute objects.
-
- Example Allocating:
-
- // Save Kernel Space Pointer
- (PGDIBRUSHOBJ)->pBrushAttr = IntGdiAllocObjAttr(GDIObjType_BRUSH_TYPE);
+/* Locks 2 or 3 objects at a time */
+VOID
+INTERNAL_CALL
+GDIOBJ_LockMultipleObjs(ULONG ulCount,
+ IN HGDIOBJ* ahObj,
+ OUT PGDIOBJ* apObj)
+{
+ UINT auiIndices[3] = {0,1,2};
+ UINT i, tmp ;
+ BOOL bUnsorted = TRUE;
- // Kernel Space to User Space Pointer
- (PGDI_TABLE_ENTRY)->UserData = pBrushAttr;
- // Gdi will adjust for heap delta.
+ /* First is greatest */
+ while(bUnsorted)
+ {
+ bUnsorted = FALSE;
+ for(i=1; i<ulCount; i++)
+ {
+ if((ULONG_PTR)ahObj[auiIndices[i-1]] < (ULONG_PTR)ahObj[auiIndices[i]])
+ {
+ tmp = auiIndices[i-1];
+ auiIndices[i-1] = auiIndices[i];
+ auiIndices[i] = tmp;
+ bUnsorted = TRUE;
+ }
+ }
+ }
- Example Freeing:
+ for(i=0;i<ulCount;i++)
+ apObj[auiIndices[i]] = GDIOBJ_LockObj(ahObj[auiIndices[i]], GDI_OBJECT_TYPE_DONTCARE);
+}
- (PGDI_TABLE_ENTRY)->UserData = NULL; // Zero the user ptr.
- UserHeapFree((PGDIBRUSHOBJ)->pBrushAttr); // Free from kernel ptr.
- (PGDIBRUSHOBJ)->pBrushAttr = NULL;
- Notes:
- Testing with DC_ATTR works but has drawing difficulties.
- Base on observation, (Over looking the obvious) we need to supply heap delta
- to user space gdi. Now, with testing, looks all normal.
+/** PUBLIC FUNCTIONS **********************************************************/
- */
-PVOID
+BOOL
FASTCALL
-IntGdiAllocObjAttr(GDIOBJTYPE Type)
+IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
{
- PVOID pMemAttr = NULL;
-
- switch( Type )
+ INT Index;
+ PGDI_TABLE_ENTRY Entry;
+/*
+ System Regions:
+ These regions do not use attribute sections and when allocated, use gdiobj
+ level functions.
+ */
+ // FIXME! HAX!!! Remove this once we get everything right!
+ Index = GDI_HANDLE_GET_INDEX(hRgn);
+ Entry = &GdiHandleTable->Entries[Index];
+ if (Entry->UserData) FreeObjectAttr(Entry->UserData);
+ Entry->UserData = NULL;
+ //
+ if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
{
- case GDIObjType_DC_TYPE:
- pMemAttr = UserHeapAlloc(sizeof(DC_ATTR));
- if (pMemAttr) RtlZeroMemory(pMemAttr, sizeof(DC_ATTR));
- break;
- case GDIObjType_RGN_TYPE:
- pMemAttr = UserHeapAlloc(sizeof(RGN_ATTR));
- if (pMemAttr) RtlZeroMemory(pMemAttr, sizeof(RGN_ATTR));
- break;
- case GDIObjType_BRUSH_TYPE:
- pMemAttr = UserHeapAlloc(sizeof(BRUSH_ATTR));
- if (pMemAttr) RtlZeroMemory(pMemAttr, sizeof(BRUSH_ATTR));
- break;
- default:
- break;
+ return GDIOBJ_SetOwnership(hRgn, NULL);
}
- return pMemAttr;
+ if (OwnerMask == GDI_OBJ_HMGR_POWNED)
+ {
+ return GDIOBJ_SetOwnership((HGDIOBJ) hRgn, PsGetCurrentProcess() );
+ }
+ return FALSE;
}
-
BOOL
FASTCALL
-IntGdiSetBrushOwner(PGDIBRUSHOBJ pbr, DWORD OwnerMask)
+IntGdiSetBrushOwner(PBRUSH pbr, DWORD OwnerMask)
{
HBRUSH hBR;
PEPROCESS Owner = NULL;
return FALSE;
// Allow user access to User Data.
- pEntry->UserData = pbr->pBrushAttr;
+ pEntry->UserData = pbr->pBrushAttr;
}
return TRUE;
}
-
BOOL
FASTCALL
IntGdiSetDCOwnerEx( HDC hDC, DWORD OwnerMask, BOOL NoSetBrush)
if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
{
pDC = DC_LockDc ( hDC );
- MmCopyFromCaller(&pDC->Dc_Attr, pDC->pDc_Attr, sizeof(DC_ATTR));
+ MmCopyFromCaller(&pDC->dcattr, pDC->pdcattr, sizeof(DC_ATTR));
+ DC_vFreeDcAttr(pDC);
DC_UnlockDc( pDC );
- DC_FreeDcAttr( hDC ); // Free the dcattr!
-
if (!DC_SetOwnership( hDC, NULL )) // This hDC is inaccessible!
return Ret;
}
if (OwnerMask == GDI_OBJ_HMGR_POWNED)
{
pDC = DC_LockDc ( hDC );
- if ( !pDC->pDc_Attr ) Ret = TRUE; // Must be zero.
+ ASSERT(pDC->pdcattr == &pDC->dcattr);
DC_UnlockDc( pDC );
- if (!Ret) return Ret;
if (!DC_SetOwnership( hDC, PsGetCurrentProcess() )) return Ret;
if ((OwnerMask != GDI_OBJ_HMGR_NONE) && !NoSetBrush)
{
pDC = DC_LockDc ( hDC );
- if (IntGdiSetBrushOwner((PGDIBRUSHOBJ)pDC->DcLevel.pbrFill, OwnerMask))
- IntGdiSetBrushOwner((PGDIBRUSHOBJ)pDC->DcLevel.pbrLine, OwnerMask);
+ 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
{
case GDI_OBJECT_TYPE_PEN:
case GDI_OBJECT_TYPE_EXTPEN:
- Result = PEN_GetObject((PGDIBRUSHOBJ) pGdiObject, cbCount, (PLOGPEN) lpBuffer); // IntGdiCreatePenIndirect
+ Result = PEN_GetObject((PBRUSH) pGdiObject, cbCount, (PLOGPEN) lpBuffer); // IntGdiCreatePenIndirect
break;
case GDI_OBJECT_TYPE_BRUSH:
- Result = BRUSH_GetObject((PGDIBRUSHOBJ ) pGdiObject, cbCount, (LPLOGBRUSH)lpBuffer);
+ Result = BRUSH_GetObject((PBRUSH ) pGdiObject, cbCount, (LPLOGBRUSH)lpBuffer);
break;
case GDI_OBJECT_TYPE_BITMAP:
- Result = BITMAP_GetObject((BITMAPOBJ *) pGdiObject, cbCount, lpBuffer);
+ Result = BITMAP_GetObject((SURFACE *) pGdiObject, cbCount, lpBuffer);
break;
case GDI_OBJECT_TYPE_FONT:
Result = FontGetObject((PTEXTOBJ) pGdiObject, cbCount, lpBuffer);
break;
case GDI_OBJECT_TYPE_PALETTE:
- Result = PALETTE_GetObject((PPALGDI) pGdiObject, cbCount, lpBuffer);
+ Result = PALETTE_GetObject((PPALETTE) pGdiObject, cbCount, lpBuffer);
break;
default:
if ((cbCopyCount) && (lpBuffer))
{
// Enter SEH for buffer transfer
- _SEH_TRY
+ _SEH2_TRY
{
// Probe the buffer and copy it
ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD));
RtlCopyMemory(lpBuffer, &Object, cbCopyCount);
}
- _SEH_HANDLE
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
// Clear the return value.
// Do *NOT* set last error here!
iRetCount = 0;
}
- _SEH_END;
+ _SEH2_END;
}
// Return the count
return iRetCount;