2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/objects/gdiobj.c
5 * PURPOSE: General GDI object manipulation routines
9 /** INCLUDES ******************************************************************/
17 #define GDI_ENTRY_TO_INDEX(ht, e) \
18 (((ULONG_PTR)(e) - (ULONG_PTR)&((ht)->Entries[0])) / sizeof(GDI_TABLE_ENTRY))
19 #define GDI_HANDLE_GET_ENTRY(HandleTable, h) \
20 (&(HandleTable)->Entries[GDI_HANDLE_GET_INDEX((h))])
22 /* apparently the first 10 entries are never used in windows as they are empty */
23 #define RESERVE_ENTRIES_COUNT 10
25 #define BASE_OBJTYPE_COUNT 32
27 #define DelayExecution() \
28 DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
29 KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
34 BOOL INTERNAL_CALL
GDI_CleanupDummy(PVOID ObjectBody
);
36 /** GLOBALS *******************************************************************/
43 GDICLEANUPPROC CleanupProc
;
44 } OBJ_TYPE_INFO
, *POBJ_TYPE_INFO
;
47 OBJ_TYPE_INFO ObjTypeInfo
[BASE_OBJTYPE_COUNT
] =
49 {0, 0, 0, NULL
}, /* 00 reserved entry */
50 {1, sizeof(DC
), TAG_DC
, DC_Cleanup
}, /* 01 DC */
51 {1, 0, 0, NULL
}, /* 02 UNUSED1 */
52 {1, 0, 0, NULL
}, /* 03 UNUSED2 */
53 {1, sizeof(ROSRGNDATA
), TAG_REGION
, REGION_Cleanup
}, /* 04 RGN */
54 {1, sizeof(SURFACE
), TAG_SURFACE
, SURFACE_Cleanup
}, /* 05 SURFACE */
55 {1, sizeof(CLIENTOBJ
), TAG_CLIENTOBJ
, GDI_CleanupDummy
}, /* 06 CLIENTOBJ: METADC,... */
56 {1, sizeof(PATH
), TAG_PATH
, GDI_CleanupDummy
}, /* 07 PATH */
57 {1, sizeof(PALETTE
), TAG_PALETTE
, PALETTE_Cleanup
}, /* 08 PAL */
58 {1, sizeof(COLORSPACE
), TAG_ICMLCS
, GDI_CleanupDummy
}, /* 09 ICMLCS, */
59 {1, sizeof(TEXTOBJ
), TAG_LFONT
, GDI_CleanupDummy
}, /* 0a LFONT */
60 {0, 0, TAG_RFONT
, NULL
}, /* 0b RFONT, unused */
61 {0, 0, TAG_PFE
, NULL
}, /* 0c PFE, unused */
62 {0, 0, TAG_PFT
, NULL
}, /* 0d PFT, unused */
63 {0, sizeof(GDICLRXFORM
), TAG_ICMCXF
, GDI_CleanupDummy
}, /* 0e ICMCXF, */
64 {0, 0, TAG_SPRITE
, NULL
}, /* 0f SPRITE, unused */
65 {1, sizeof(BRUSH
), TAG_BRUSH
, BRUSH_Cleanup
}, /* 10 BRUSH, PEN, EXTPEN */
66 {0, 0, TAG_UMPD
, NULL
}, /* 11 UMPD, unused */
67 {0, 0, 0, NULL
}, /* 12 UNUSED4 */
68 {0, 0, TAG_SPACE
, NULL
}, /* 13 SPACE, unused */
69 {0, 0, 0, NULL
}, /* 14 UNUSED5 */
70 {0, 0, TAG_META
, NULL
}, /* 15 META, unused */
71 {0, 0, TAG_EFSTATE
, NULL
}, /* 16 EFSTATE, unused */
72 {0, 0, TAG_BMFD
, NULL
}, /* 17 BMFD, unused */
73 {0, 0, TAG_VTFD
, NULL
}, /* 18 VTFD, unused */
74 {0, 0, TAG_TTFD
, NULL
}, /* 19 TTFD, unused */
75 {0, 0, TAG_RC
, NULL
}, /* 1a RC, unused */
76 {0, 0, TAG_TEMP
, NULL
}, /* 1b TEMP, unused */
77 {0, sizeof(EDRIVEROBJ
), TAG_DRVOBJ
, DRIVEROBJ_Cleanup
},/* 1c DRVOBJ */
78 {0, 0, TAG_DCIOBJ
, NULL
}, /* 1d DCIOBJ, unused */
79 {0, 0, TAG_SPOOL
, NULL
}, /* 1e SPOOL, unused */
80 {0, 0, 0, NULL
}, /* 1f reserved entry */
83 static LARGE_INTEGER ShortDelay
;
85 /** INTERNAL FUNCTIONS ********************************************************/
95 AllocTypeDataDump(INT TypeInfo
)
97 switch( TypeInfo
& GDI_HANDLE_TYPE_MASK
)
99 case GDILoObjType_LO_BRUSH_TYPE
:
102 case GDILoObjType_LO_DC_TYPE
:
105 case GDILoObjType_LO_BITMAP_TYPE
:
108 case GDILoObjType_LO_FONT_TYPE
:
111 case GDILoObjType_LO_REGION_TYPE
:
118 DeAllocTypeDataDump(INT TypeInfo
)
120 switch( TypeInfo
& GDI_HANDLE_TYPE_MASK
)
122 case GDILoObjType_LO_BRUSH_TYPE
:
125 case GDILoObjType_LO_DC_TYPE
:
128 case GDILoObjType_LO_BITMAP_TYPE
:
131 case GDILoObjType_LO_FONT_TYPE
:
134 case GDILoObjType_LO_REGION_TYPE
:
141 * Dummy GDI Cleanup Callback
145 GDI_CleanupDummy(PVOID ObjectBody
)
151 * Allocate GDI object table.
152 * \param Size - number of entries in the object table.
154 PGDI_HANDLE_TABLE INTERNAL_CALL
155 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT
*SectionObject
)
157 PGDI_HANDLE_TABLE HandleTable
= NULL
;
158 LARGE_INTEGER htSize
;
163 ASSERT(SectionObject
!= NULL
);
165 htSize
.QuadPart
= sizeof(GDI_HANDLE_TABLE
);
167 Status
= MmCreateSection((PVOID
*)SectionObject
,
175 if (!NT_SUCCESS(Status
))
178 /* FIXME - use MmMapViewInSessionSpace once available! */
179 Status
= MmMapViewInSystemSpace(*SectionObject
,
180 (PVOID
*)&HandleTable
,
182 if (!NT_SUCCESS(Status
))
184 ObDereferenceObject(*SectionObject
);
185 *SectionObject
= NULL
;
189 RtlZeroMemory(HandleTable
, sizeof(GDI_HANDLE_TABLE
));
191 HandleTable
->LookasideLists
= ExAllocatePoolWithTag(NonPagedPool
,
192 BASE_OBJTYPE_COUNT
* sizeof(PAGED_LOOKASIDE_LIST
),
194 if (HandleTable
->LookasideLists
== NULL
)
196 MmUnmapViewInSystemSpace(HandleTable
);
197 ObDereferenceObject(*SectionObject
);
198 *SectionObject
= NULL
;
202 for (ObjType
= 0; ObjType
< BASE_OBJTYPE_COUNT
; ObjType
++)
204 if (ObjTypeInfo
[ObjType
].bUseLookaside
)
206 ExInitializePagedLookasideList(HandleTable
->LookasideLists
+ ObjType
,
210 ObjTypeInfo
[ObjType
].ulBodySize
,
211 ObjTypeInfo
[ObjType
].Tag
,
216 ShortDelay
.QuadPart
= -5000LL; /* FIXME - 0.5 ms? */
218 HandleTable
->FirstFree
= 0;
219 HandleTable
->FirstUnused
= RESERVE_ENTRIES_COUNT
;
225 LockErrorDebugOutput(HGDIOBJ hObj
, PGDI_TABLE_ENTRY Entry
, LPSTR Function
)
227 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
229 DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function
, hObj
);
230 GDIDBG_TRACEDELETER(hObj
);
232 else if (GDI_HANDLE_GET_REUSECNT(hObj
) != GDI_ENTRY_GET_REUSECNT(Entry
->Type
))
234 DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
235 Function
, hObj
, GDI_HANDLE_GET_REUSECNT(hObj
), GDI_ENTRY_GET_REUSECNT(Entry
->Type
));
237 else if (GDI_HANDLE_GET_TYPE(hObj
) != ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
))
239 DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
240 Function
, hObj
, GDI_HANDLE_GET_TYPE(hObj
), (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
);
244 DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
245 Function
, hObj
, Entry
->Type
);
247 GDIDBG_TRACECALLER();
252 InterlockedPopFreeEntry(VOID
)
254 ULONG idxFirst
, idxNext
, idxPrev
;
255 PGDI_TABLE_ENTRY pEntry
;
258 DPRINT("Enter InterLockedPopFreeEntry\n");
262 idxFirst
= GdiHandleTable
->FirstFree
;
266 /* Increment FirstUnused and get the new index */
267 idxFirst
= InterlockedIncrement((LONG
*)&GdiHandleTable
->FirstUnused
) - 1;
269 /* Check if we have entries left */
270 if (idxFirst
>= GDI_HANDLE_COUNT
)
272 DPRINT1("No more gdi handles left!\n");
276 /* Return the old index */
280 /* Get a pointer to the first free entry */
281 pEntry
= GdiHandleTable
->Entries
+ idxFirst
;
283 /* Try to lock the entry */
284 PrevProcId
= InterlockedCompareExchange((LONG
*)&pEntry
->ProcessId
, 1, 0);
287 /* The entry was locked or not free, wait and start over */
292 /* Sanity check: is entry really free? */
293 ASSERT(((ULONG_PTR
)pEntry
->KernelData
& ~GDI_HANDLE_INDEX_MASK
) == 0);
295 /* Try to exchange the FirstFree value */
296 idxNext
= (ULONG_PTR
)pEntry
->KernelData
;
297 idxPrev
= InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
,
301 /* Unlock the free entry */
302 (void)InterlockedExchange((LONG
*)&pEntry
->ProcessId
, 0);
304 /* If we succeeded, break out of the loop */
305 if (idxPrev
== idxFirst
)
314 /* Pushes an entry of the handle table to the free list,
315 The entry must be unlocked and the base type field must be 0 */
318 InterlockedPushFreeEntry(ULONG idxToFree
)
320 ULONG idxFirstFree
, idxPrev
;
321 PGDI_TABLE_ENTRY pFreeEntry
;
323 DPRINT("Enter InterlockedPushFreeEntry\n");
325 pFreeEntry
= GdiHandleTable
->Entries
+ idxToFree
;
326 ASSERT((pFreeEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0);
327 ASSERT(pFreeEntry
->ProcessId
== 0);
328 pFreeEntry
->UserData
= NULL
;
332 idxFirstFree
= GdiHandleTable
->FirstFree
;
333 pFreeEntry
->KernelData
= (PVOID
)(ULONG_PTR
)idxFirstFree
;
335 idxPrev
= InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
,
339 while (idxPrev
!= idxFirstFree
);
345 GDIOBJ_ValidateHandle(HGDIOBJ hObj
, ULONG ObjectType
)
347 PGDI_TABLE_ENTRY Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
348 if ((((ULONG_PTR
)hObj
& GDI_HANDLE_TYPE_MASK
) == ObjectType
) &&
349 (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == GDI_HANDLE_GET_UPPER(hObj
))
351 HANDLE pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
352 if (pid
== NULL
|| pid
== PsGetCurrentProcessId())
361 GDIOBJ_AllocObj(UCHAR BaseType
)
365 ASSERT((BaseType
& ~GDIObjTypeTotal
) == 0);
366 // BaseType &= GDI_HANDLE_BASETYPE_MASK;
368 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
370 PPAGED_LOOKASIDE_LIST LookasideList
;
372 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
373 pObject
= ExAllocateFromPagedLookasideList(LookasideList
);
377 pObject
= ExAllocatePoolWithTag(PagedPool
,
378 ObjTypeInfo
[BaseType
].ulBodySize
,
379 ObjTypeInfo
[BaseType
].Tag
);
384 RtlZeroMemory(pObject
, ObjTypeInfo
[BaseType
].ulBodySize
);
392 * Allocate memory for GDI object and return handle to it.
394 * \param ObjectType - type of object \ref GDI object types
396 * \return Pointer to the allocated object, which is locked.
399 GDIOBJ_AllocObjWithHandle(ULONG ObjectType
)
401 PPROCESSINFO W32Process
;
402 POBJ newObject
= NULL
;
403 HANDLE CurrentProcessId
, LockedProcessId
;
406 PGDI_TABLE_ENTRY Entry
;
409 GDIDBG_INITLOOPTRACE();
411 W32Process
= PsGetCurrentProcessWin32Process();
412 /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
413 to take too many GDI objects, itself. */
414 if (W32Process
&& W32Process
->GDIHandleCount
>= 0x2710)
416 DPRINT1("Too many objects for process!!!\n");
417 DPRINT1("DC %d BRUSH %d BITMAP %d FONT %d RGN %d\n",tDC
,tBRUSH
,tBITMAP
,tFONT
,tRGN
);
418 GDIDBG_DUMPHANDLETABLE();
422 ASSERT(ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
);
424 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(ObjectType
);
426 newObject
= GDIOBJ_AllocObj(TypeIndex
);
429 DPRINT1("Not enough memory to allocate gdi object!\n");
433 CurrentProcessId
= PsGetCurrentProcessId();
434 LockedProcessId
= (HANDLE
)((ULONG_PTR
)CurrentProcessId
| 0x1);
436 // RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
438 /* On Windows the higher 16 bit of the type field don't contain the
439 full type from the handle, but the base type.
440 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
441 TypeInfo
= (ObjectType
& GDI_HANDLE_BASETYPE_MASK
) | (ObjectType
>> GDI_ENTRY_UPPER_SHIFT
);
443 Index
= InterlockedPopFreeEntry();
448 Entry
= &GdiHandleTable
->Entries
[Index
];
451 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, 0);
452 if (PrevProcId
== NULL
)
454 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
457 Entry
->KernelData
= newObject
;
459 /* copy the reuse-counter */
460 TypeInfo
|= Entry
->Type
& GDI_ENTRY_REUSE_MASK
;
462 /* we found a free entry, no need to exchange this field atomically
463 since we're holding the lock */
464 Entry
->Type
= TypeInfo
;
466 /* Create a handle */
467 Handle
= (HGDIOBJ
)((Index
& 0xFFFF) | (TypeInfo
<< GDI_ENTRY_UPPER_SHIFT
));
469 /* Initialize BaseObject fields */
470 newObject
->hHmgr
= Handle
;
471 newObject
->ulShareCount
= 0;
472 newObject
->cExclusiveLock
= 1;
473 newObject
->Tid
= Thread
;
475 AllocTypeDataDump(TypeInfo
);
477 /* unlock the entry */
478 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, CurrentProcessId
);
480 GDIDBG_CAPTUREALLOCATOR(Index
);
482 if (W32Process
!= NULL
)
484 InterlockedIncrement(&W32Process
->GDIHandleCount
);
487 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle
, newObject
);
492 GDIDBG_TRACELOOP(Index
, PrevProcId
, CurrentProcessId
);
493 /* damn, someone is trying to lock the object even though it doesn't
494 even exist anymore, wait a little and try again!
495 FIXME - we shouldn't loop forever! Give up after some time! */
502 GDIOBJ_FreeObj(newObject
, TypeIndex
);
504 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
505 GDIDBG_DUMPHANDLETABLE();
512 GDIOBJ_FreeObj(POBJ pObject
, UCHAR BaseType
)
514 /* Object must not have a handle! */
515 ASSERT(pObject
->hHmgr
== NULL
);
517 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
519 PPAGED_LOOKASIDE_LIST LookasideList
;
521 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
522 ExFreeToPagedLookasideList(LookasideList
, pObject
);
531 * Free memory allocated for the GDI object. For each object type this function calls the
532 * appropriate cleanup routine.
534 * \param hObj - handle of the object to be deleted.
536 * \return Returns TRUE if succesful.
537 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
538 * to the calling process.
540 * \bug This function should return VOID and kill the object no matter what...
543 GDIOBJ_FreeObjByHandle(HGDIOBJ hObj
, DWORD ExpectedType
)
545 PGDI_TABLE_ENTRY Entry
;
546 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
547 ULONG HandleType
, HandleUpper
, TypeIndex
;
550 GDIDBG_INITLOOPTRACE();
552 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj
);
554 if (GDI_HANDLE_IS_STOCKOBJ(hObj
))
556 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj
);
557 GDIDBG_TRACECALLER();
561 ProcessId
= PsGetCurrentProcessId();
562 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
564 Silent
= (ExpectedType
& GDI_OBJECT_TYPE_SILENT
);
565 ExpectedType
&= ~GDI_OBJECT_TYPE_SILENT
;
567 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
568 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
570 /* Check if we have the requested type */
571 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
572 HandleType
!= ExpectedType
) ||
575 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
576 hObj
, HandleType
, ExpectedType
);
577 GDIDBG_TRACECALLER();
581 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
584 /* lock the object, we must not delete global objects, so don't exchange the locking
585 process ID to zero when attempting to lock a global object... */
586 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
587 if (PrevProcId
== ProcessId
)
589 if ( (Entry
->KernelData
!= NULL
) &&
590 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) &&
591 ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == (HandleUpper
& GDI_ENTRY_BASETYPE_MASK
)) )
595 Object
= Entry
->KernelData
;
597 if ((Object
->cExclusiveLock
== 0 ||
598 Object
->Tid
== (PTHREADINFO
)PsGetCurrentThreadWin32Thread()) &&
599 Object
->ulShareCount
== 0)
602 PPROCESSINFO W32Process
= PsGetCurrentProcessWin32Process();
604 /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
605 Entry
->Type
= (Entry
->Type
+ GDI_ENTRY_REUSE_INC
) & ~GDI_ENTRY_BASETYPE_MASK
;
607 /* unlock the handle slot */
608 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
610 /* push this entry to the free list */
611 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable
, Entry
));
613 Object
->hHmgr
= NULL
;
615 if (W32Process
!= NULL
)
617 InterlockedDecrement(&W32Process
->GDIHandleCount
);
620 /* call the cleanup routine. */
621 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(HandleType
);
622 Ret
= ObjTypeInfo
[TypeIndex
].CleanupProc(Object
);
624 DeAllocTypeDataDump(HandleType
);
626 /* Now it's time to free the memory */
627 GDIOBJ_FreeObj(Object
, TypeIndex
);
629 GDIDBG_CAPTUREDELETER(hObj
);
632 else if (Object
->ulShareCount
!= 0)
635 PEPROCESS OldProcess
;
636 Object
->BaseFlags
|= BASEFLAG_READY_TO_DIE
;
637 DPRINT("Object %p, ulShareCount = %d\n", Object
->hHmgr
, Object
->ulShareCount
);
638 /* Set NULL owner. Do the work here to avoid race conditions */
639 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
640 if (NT_SUCCESS(Status
))
642 PPROCESSINFO W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
643 if (W32Process
!= NULL
)
645 InterlockedDecrement(&W32Process
->GDIHandleCount
);
647 ObDereferenceObject(OldProcess
);
649 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
650 /* Don't wait on shared locks */
656 * The object is currently locked by another thread, so freeing is forbidden!
658 DPRINT1("Object->cExclusiveLock = %d\n", Object
->cExclusiveLock
);
659 GDIDBG_TRACECALLER();
660 GDIDBG_TRACELOCKER(hObj
);
661 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
662 /* do not assert here for it will call again from dxg.sys it being call twice */
670 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
671 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
674 else if (PrevProcId
== LockedProcessId
)
676 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
678 /* the object is currently locked, wait some time and try again.
679 FIXME - we shouldn't loop forever! Give up after some time! */
688 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
690 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj
);
692 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
694 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
698 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);
700 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry
->Type
, Entry
->KernelData
, Entry
->ProcessId
);
701 GDIDBG_TRACECALLER();
702 GDIDBG_TRACEALLOCATOR(hObj
);
711 IsObjectDead(HGDIOBJ hObject
)
713 INT Index
= GDI_HANDLE_GET_INDEX(hObject
);
714 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
715 // We check to see if the objects are knocking on deaths door.
716 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
720 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject
);
721 return TRUE
; // return true and move on.
728 bPEBCacheHandle(HGDIOBJ Handle
, int oType
, PVOID pAttr
)
730 PGDIHANDLECACHE GdiHandleCache
;
733 int Offset
= 0, Number
;
736 GdiHandleCache
= (PGDIHANDLECACHE
)NtCurrentTeb()->ProcessEnvironmentBlock
->GdiHandleBuffer
;
745 Offset
= CACHE_BRUSH_ENTRIES
;
748 case hctRegionHandle
:
749 Offset
= CACHE_BRUSH_ENTRIES
+CACHE_PEN_ENTRIES
;
756 Lock
= InterlockedCompareExchangePointer( (PVOID
*)&GdiHandleCache
->ulLock
,
759 if (Lock
) return FALSE
;
763 Number
= GdiHandleCache
->ulNumHandles
[oType
];
765 hPtr
= GdiHandleCache
->Handle
+ Offset
;
767 if ( pAttr
&& oType
== hctRegionHandle
)
769 if ( Number
< CACHE_REGION_ENTRIES
)
771 ((PRGN_ATTR
)pAttr
)->AttrFlags
|= ATTR_CACHED
;
772 hPtr
[Number
] = Handle
;
773 GdiHandleCache
->ulNumHandles
[oType
]++;
774 DPRINT("Put Handle Count %d PEB 0x%x\n", GdiHandleCache
->ulNumHandles
[oType
], NtCurrentTeb()->ProcessEnvironmentBlock
);
779 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
785 (void)InterlockedExchangePointer((PVOID
*)&GdiHandleCache
->ulLock
, Lock
);
791 * \param hObject object handle
792 * \return if the function fails the returned value is FALSE.
796 GreDeleteObject(HGDIOBJ hObject
)
799 PGDI_TABLE_ENTRY Entry
;
803 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
804 if (!IsObjectDead(hObject
))
806 dwObjectType
= GDIOBJ_GetObjectType(hObject
);
808 Index
= GDI_HANDLE_GET_INDEX(hObject
);
809 Entry
= &GdiHandleTable
->Entries
[Index
];
810 pAttr
= Entry
->UserData
;
812 switch (dwObjectType
)
814 case GDI_OBJECT_TYPE_BRUSH
:
817 case GDI_OBJECT_TYPE_REGION
:
818 /* If pAttr NULL, the probability is high for System Region. */
820 bPEBCacheHandle(hObject
, hctRegionHandle
, pAttr
))
822 /* User space handle only! */
827 FreeObjectAttr(pAttr
);
828 Entry
->UserData
= NULL
;
832 case GDI_OBJECT_TYPE_DC
:
833 // DC_FreeDcAttr(hObject);
837 return NULL
!= hObject
838 ? GDIOBJ_FreeObjByHandle(hObject
, dwObjectType
) : FALSE
;
842 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject
);
843 return TRUE
; // return true and move on.
849 IntDeleteHandlesForProcess(struct _EPROCESS
*Process
, ULONG ObjectType
)
851 PGDI_TABLE_ENTRY Entry
, End
;
852 ULONG Index
= RESERVE_ENTRIES_COUNT
;
854 PPROCESSINFO W32Process
;
856 W32Process
= (PPROCESSINFO
)Process
->Win32Process
;
859 if (W32Process
->GDIHandleCount
> 0)
861 ProcId
= Process
->UniqueProcessId
;
863 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
864 we should delete it directly here! */
866 End
= &GdiHandleTable
->Entries
[GDI_HANDLE_COUNT
];
867 for (Entry
= &GdiHandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
871 /* ignore the lock bit */
872 if ( (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
)
874 if ( (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == ObjectType
||
875 ObjectType
== GDI_OBJECT_TYPE_DONTCARE
)
877 HGDIOBJ ObjectHandle
;
879 /* Create the object handle for the entry, the lower(!) 16 bit of the
880 Type field includes the type of the object including the stock
881 object flag - but since stock objects don't have a process id we can
882 simply ignore this fact here. */
883 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
885 if (!GDIOBJ_FreeObjByHandle(ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
))
887 DPRINT1("Failed to delete object %p!\n", ObjectHandle
);
890 if (W32Process
->GDIHandleCount
== 0)
892 /* there are no more gdi handles for this process, bail */
903 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
904 * \param Process - PID of the process that will be destroyed.
907 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
909 PEPROCESS CurrentProcess
;
910 PPROCESSINFO W32Process
;
912 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
913 CurrentProcess
= PsGetCurrentProcess();
914 if (CurrentProcess
!= Process
)
916 KeAttachProcess(&Process
->Pcb
);
919 W32Process
= (PPROCESSINFO
)CurrentProcess
->Win32Process
;
921 /* Delete objects. Begin with types that are not referenced by other types */
922 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_DC_TYPE
);
923 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BRUSH_TYPE
);
924 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BITMAP_TYPE
);
926 /* Finally finish with what's left */
927 IntDeleteHandlesForProcess(Process
, GDI_OBJECT_TYPE_DONTCARE
);
929 if (CurrentProcess
!= Process
)
935 GdiDbgHTIntegrityCheck();
938 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
939 if (W32Process
->GDIHandleCount
> 0)
941 DPRINT1("Leaking %d handles!\n", W32Process
->GDIHandleCount
);
948 * Return pointer to the object by handle.
950 * \param hObj Object handle
951 * \return Pointer to the object.
953 * \note Process can only get pointer to the objects it created or global objects.
955 * \todo Get rid of the ExpectedType parameter!
957 PGDIOBJ INTERNAL_CALL
958 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
961 PGDI_TABLE_ENTRY Entry
;
962 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
964 ULONG HandleType
, HandleUpper
;
966 /* Check for dummy call */
970 GDIDBG_INITLOOPTRACE();
972 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
973 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
974 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
976 /* Check that the handle index is valid. */
977 if (HandleIndex
>= GDI_HANDLE_COUNT
)
980 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
982 /* Check if we have the requested type */
983 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
984 HandleType
!= ExpectedType
) ||
987 DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
988 hObj
, HandleType
, ExpectedType
);
989 GDIDBG_TRACECALLER();
990 GDIDBG_TRACEALLOCATOR(hObj
);
991 GDIDBG_TRACEDELETER(hObj
);
995 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
996 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
998 /* Check for invalid owner. */
999 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
1001 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj
, ProcessId
, HandleProcessId
);
1002 GDIDBG_TRACECALLER();
1003 GDIDBG_TRACEALLOCATOR(hObj
);
1008 * Prevent the thread from being terminated during the locking process.
1009 * It would result in undesired effects and inconsistency of the global
1013 KeEnterCriticalRegion();
1016 * Loop until we either successfully lock the handle entry & object or
1017 * fail some of the check.
1022 /* Lock the handle table entry. */
1023 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
1024 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
1028 if (PrevProcId
== HandleProcessId
)
1031 * We're locking an object that belongs to our process or it's a
1032 * global object if HandleProcessId is 0 here.
1035 if ( (Entry
->KernelData
!= NULL
) &&
1036 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
1038 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1039 Object
= Entry
->KernelData
;
1041 if (Object
->cExclusiveLock
== 0)
1043 Object
->Tid
= Thread
;
1044 Object
->cExclusiveLock
= 1;
1045 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj
))
1049 if (Object
->Tid
!= Thread
)
1051 /* Unlock the handle table entry. */
1052 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1057 InterlockedIncrement((PLONG
)&Object
->cExclusiveLock
);
1063 * Debugging code. Report attempts to lock deleted handles and
1064 * locking type mismatches.
1066 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
1069 /* Unlock the handle table entry. */
1070 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1077 * The handle is currently locked, wait some time and try again.
1079 GDIDBG_TRACELOOP(hObj
, PrevProcId
, NULL
);
1086 KeLeaveCriticalRegion();
1093 * Return pointer to the object by handle (and allow sharing of the handle
1096 * \param hObj Object handle
1097 * \return Pointer to the object.
1099 * \note Process can only get pointer to the objects it created or global objects.
1101 * \todo Get rid of the ExpectedType parameter!
1103 PGDIOBJ INTERNAL_CALL
1104 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
1107 PGDI_TABLE_ENTRY Entry
;
1108 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
1110 ULONG_PTR HandleType
, HandleUpper
;
1112 /* Check for dummy call */
1116 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
1117 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
1118 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
1120 /* Check that the handle index is valid. */
1121 if (HandleIndex
>= GDI_HANDLE_COUNT
)
1124 /* Check if we have the requested type */
1125 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
1126 HandleType
!= ExpectedType
) ||
1129 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1130 hObj
, HandleType
, ExpectedType
);
1134 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
1136 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
1137 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
1139 /* Check for invalid owner. */
1140 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
1146 * Prevent the thread from being terminated during the locking process.
1147 * It would result in undesired effects and inconsistency of the global
1151 KeEnterCriticalRegion();
1154 * Loop until we either successfully lock the handle entry & object or
1155 * fail some of the check.
1160 /* Lock the handle table entry. */
1161 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
1162 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
1166 if (PrevProcId
== HandleProcessId
)
1169 * We're locking an object that belongs to our process or it's a
1170 * global object if HandleProcessId is 0 here.
1173 if ( (Entry
->KernelData
!= NULL
) &&
1174 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
1176 Object
= (POBJ
)Entry
->KernelData
;
1178 GDIDBG_CAPTURESHARELOCKER(HandleIndex
);
1180 if (InterlockedIncrement((PLONG
)&Object
->ulShareCount
) == 1)
1182 memset(GDIHandleLocker
[HandleIndex
], 0x00, GDI_STACK_LEVELS
* sizeof(ULONG
));
1183 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS
, (PVOID
*)GDIHandleShareLocker
[HandleIndex
], NULL
);
1186 InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
1192 * Debugging code. Report attempts to lock deleted handles and
1193 * locking type mismatches.
1195 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
1198 /* Unlock the handle table entry. */
1199 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1206 * The handle is currently locked, wait some time and try again.
1214 KeLeaveCriticalRegion();
1220 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
1222 PGDI_TABLE_ENTRY Entry
;
1226 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1228 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1230 ProcessId
= PsGetCurrentProcessId();
1232 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1233 Ret
= Entry
->KernelData
!= NULL
&&
1234 (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0 &&
1235 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1244 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1247 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1248 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1250 PGDI_TABLE_ENTRY Entry
;
1251 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1255 GDIDBG_INITLOOPTRACE();
1260 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj
);
1262 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1264 if (!GDI_HANDLE_IS_STOCKOBJ(hObj
))
1266 ProcessId
= PsGetCurrentProcessId();
1267 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1269 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
1272 /* lock the object, we must not convert stock objects, so don't check!!! */
1273 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1274 if (PrevProcId
== ProcessId
)
1276 LONG NewType
, PrevType
, OldType
;
1278 /* we're locking an object that belongs to our process. First calculate
1279 the new object type including the stock object flag and then try to
1281 /* On Windows the higher 16 bit of the type field don't contain the
1282 full type from the handle, but the base type.
1283 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1284 OldType
= ((ULONG
)hObj
& GDI_HANDLE_BASETYPE_MASK
) | ((ULONG
)hObj
>> GDI_ENTRY_UPPER_SHIFT
);
1285 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1286 we copy them as we can't get them from the handle */
1287 OldType
|= Entry
->Type
& GDI_ENTRY_FLAGS_MASK
;
1289 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1290 NewType
= OldType
| GDI_ENTRY_STOCK_MASK
;
1292 /* Try to exchange the type field - but only if the old (previous type) matches! */
1293 PrevType
= InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1294 if (PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1296 PTHREADINFO PrevThread
;
1299 /* We successfully set the stock object flag.
1300 KernelData should never be NULL here!!! */
1301 ASSERT(Entry
->KernelData
);
1303 Object
= Entry
->KernelData
;
1305 PrevThread
= Object
->Tid
;
1306 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1308 /* dereference the process' object counter */
1309 if (PrevProcId
!= GDI_GLOBAL_PROCESS
)
1311 PEPROCESS OldProcess
;
1312 PPROCESSINFO W32Process
;
1316 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1317 if (NT_SUCCESS(Status
))
1319 W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
1320 if (W32Process
!= NULL
)
1322 InterlockedDecrement(&W32Process
->GDIHandleCount
);
1324 ObDereferenceObject(OldProcess
);
1328 hObj
= (HGDIOBJ
)((ULONG
)(hObj
) | GDI_HANDLE_STOCK_MASK
);
1330 Object
->hHmgr
= hObj
;
1332 /* remove the process id lock and make it global */
1333 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1335 /* we're done, successfully converted the object */
1340 GDIDBG_TRACELOOP(hObj
, PrevThread
, Thread
);
1342 /* WTF?! The object is already locked by a different thread!
1343 Release the lock, wait a bit and try again!
1344 FIXME - we should give up after some time unless we want to wait forever! */
1345 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1353 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1354 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType
, Entry
->Type
, NewType
, Entry
->KernelData
);
1357 else if (PrevProcId
== LockedProcessId
)
1359 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
1361 /* the object is currently locked, wait some time and try again.
1362 FIXME - we shouldn't loop forever! Give up after some time! */
1369 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1377 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1379 PGDI_TABLE_ENTRY Entry
;
1380 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1384 GDIDBG_INITLOOPTRACE();
1386 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1388 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1390 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1392 ProcessId
= PsGetCurrentProcessId();
1393 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1395 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1398 /* lock the object, we must not convert stock objects, so don't check!!! */
1399 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1400 if (PrevProcId
== ProcessId
)
1402 PTHREADINFO PrevThread
;
1404 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1406 POBJ Object
= Entry
->KernelData
;
1408 PrevThread
= Object
->Tid
;
1409 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1411 PEPROCESS OldProcess
;
1412 PPROCESSINFO W32Process
;
1415 if (NewOwner
!= NULL
)
1417 ProcessId
= PsGetProcessId(NewOwner
);
1422 if((ULONG_PTR
)ProcessId
== ((ULONG_PTR
)PrevProcId
& ~0x1))
1424 DPRINT("Setting same process than previous one, nothing to do\n");
1428 /* dereference the process' object counter */
1430 if ((ULONG_PTR
)PrevProcId
& ~0x1)
1432 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1433 if (NT_SUCCESS(Status
))
1435 W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
1436 if (W32Process
!= NULL
)
1438 InterlockedDecrement(&W32Process
->GDIHandleCount
);
1440 ObDereferenceObject(OldProcess
);
1444 if (NewOwner
!= NULL
)
1446 /* Increase the new process' object counter */
1447 W32Process
= (PPROCESSINFO
)NewOwner
->Win32Process
;
1448 if (W32Process
!= NULL
)
1450 InterlockedIncrement(&W32Process
->GDIHandleCount
);
1455 /* remove the process id lock and change it to the new process id */
1456 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
);
1463 GDIDBG_TRACELOOP(ObjectHandle
, PrevThread
, Thread
);
1465 /* WTF?! The object is already locked by a different thread!
1466 Release the lock, wait a bit and try again! DO reset the pid lock
1467 so we make sure we don't access invalid memory in case the object is
1468 being deleted in the meantime (because we don't have aquired a reference
1470 FIXME - we should give up after some time unless we want to wait forever! */
1471 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1479 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1480 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry
->Type
, Entry
->KernelData
);
1484 else if (PrevProcId
== LockedProcessId
)
1486 GDIDBG_TRACELOOP(ObjectHandle
, PrevProcId
, ProcessId
);
1488 /* the object is currently locked, wait some time and try again.
1489 FIXME - we shouldn't loop forever! Give up after some time! */
1494 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1496 /* allow changing ownership of global objects */
1498 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1501 else if ((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1503 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1508 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1516 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1518 PGDI_TABLE_ENTRY FromEntry
;
1520 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1523 GDIDBG_INITLOOPTRACE();
1525 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1527 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1529 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1531 FromEntry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, CopyFrom
);
1533 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1534 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1537 /* lock the object, we must not convert stock objects, so don't check!!! */
1538 FromPrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1539 if (FromPrevProcId
== FromProcessId
)
1541 PTHREADINFO PrevThread
;
1544 if ((FromEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1546 Object
= FromEntry
->KernelData
;
1548 /* save the pointer to the calling thread so we know it was this thread
1549 that locked the object */
1550 PrevThread
= Object
->Tid
;
1551 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1553 /* now let's change the ownership of the target object */
1555 if (((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1557 PEPROCESS ProcessTo
;
1559 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1561 GDIOBJ_SetOwnership(CopyTo
, ProcessTo
);
1562 ObDereferenceObject(ProcessTo
);
1567 /* mark the object as global */
1568 GDIOBJ_SetOwnership(CopyTo
, NULL
);
1571 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1575 GDIDBG_TRACELOOP(CopyFrom
, PrevThread
, Thread
);
1577 /* WTF?! The object is already locked by a different thread!
1578 Release the lock, wait a bit and try again! DO reset the pid lock
1579 so we make sure we don't access invalid memory in case the object is
1580 being deleted in the meantime (because we don't have aquired a reference
1582 FIXME - we should give up after some time unless we want to wait forever! */
1583 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1586 goto LockHandleFrom
;
1591 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1595 else if (FromPrevProcId
== FromLockedProcessId
)
1597 GDIDBG_TRACELOOP(CopyFrom
, FromPrevProcId
, FromProcessId
);
1599 /* the object is currently locked, wait some time and try again.
1600 FIXME - we shouldn't loop forever! Give up after some time! */
1603 goto LockHandleFrom
;
1605 else if ((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1607 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1608 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1609 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1610 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1611 goto LockHandleFrom
;
1615 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1623 GDI_MapHandleTable(PSECTION_OBJECT SectionObject
, PEPROCESS Process
)
1625 PVOID MappedView
= NULL
;
1627 LARGE_INTEGER Offset
;
1628 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1630 Offset
.QuadPart
= 0;
1632 ASSERT(SectionObject
!= NULL
);
1633 ASSERT(Process
!= NULL
);
1635 Status
= MmMapViewOfSection(SectionObject
,
1646 if (!NT_SUCCESS(Status
))
1652 /* Locks 2 or 3 objects at a time */
1655 GDIOBJ_LockMultipleObjs(ULONG ulCount
,
1659 UINT auiIndices
[3] = {0,1,2};
1661 BOOL bUnsorted
= TRUE
;
1663 /* First is greatest */
1667 for(i
=1; i
<ulCount
; i
++)
1669 if((ULONG_PTR
)ahObj
[auiIndices
[i
-1]] < (ULONG_PTR
)ahObj
[auiIndices
[i
]])
1671 tmp
= auiIndices
[i
-1];
1672 auiIndices
[i
-1] = auiIndices
[i
];
1673 auiIndices
[i
] = tmp
;
1679 for(i
=0;i
<ulCount
;i
++)
1680 apObj
[auiIndices
[i
]] = GDIOBJ_LockObj(ahObj
[auiIndices
[i
]], GDI_OBJECT_TYPE_DONTCARE
);
1684 /** PUBLIC FUNCTIONS **********************************************************/
1688 IntGdiSetRegionOwner(HRGN hRgn
, DWORD OwnerMask
)
1691 PGDI_TABLE_ENTRY Entry
;
1694 These regions do not use attribute sections and when allocated, use gdiobj
1697 // FIXME! HAX!!! Remove this once we get everything right!
1698 Index
= GDI_HANDLE_GET_INDEX(hRgn
);
1699 Entry
= &GdiHandleTable
->Entries
[Index
];
1700 if (Entry
->UserData
) FreeObjectAttr(Entry
->UserData
);
1701 Entry
->UserData
= NULL
;
1703 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1705 return GDIOBJ_SetOwnership(hRgn
, NULL
);
1707 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1709 return GDIOBJ_SetOwnership((HGDIOBJ
) hRgn
, PsGetCurrentProcess() );
1716 IntGdiSetBrushOwner(PBRUSH pbr
, DWORD OwnerMask
)
1719 PEPROCESS Owner
= NULL
;
1720 PGDI_TABLE_ENTRY pEntry
= NULL
;
1722 if (!pbr
) return FALSE
;
1724 hBR
= pbr
->BaseObject
.hHmgr
;
1726 if (!hBR
|| (GDI_HANDLE_GET_TYPE(hBR
) != GDI_OBJECT_TYPE_BRUSH
))
1730 INT Index
= GDI_HANDLE_GET_INDEX((HGDIOBJ
)hBR
);
1731 pEntry
= &GdiHandleTable
->Entries
[Index
];
1734 if (pbr
->flAttrs
& GDIBRUSH_IS_GLOBAL
)
1736 GDIOBJ_ShareUnlockObjByPtr((POBJ
)pbr
);
1740 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1742 // Set this Brush to inaccessible mode and to an Owner of NONE.
1743 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1745 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, Owner
))
1748 // Deny user access to User Data.
1749 pEntry
->UserData
= NULL
; // This hBR is inaccessible!
1752 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1754 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, PsGetCurrentProcess() ))
1757 // Allow user access to User Data.
1758 pEntry
->UserData
= pbr
->pBrushAttr
;
1765 IntGdiSetDCOwnerEx( HDC hDC
, DWORD OwnerMask
, BOOL NoSetBrush
)
1770 if (!hDC
|| (GDI_HANDLE_GET_TYPE(hDC
) != GDI_OBJECT_TYPE_DC
)) return FALSE
;
1772 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1774 pDC
= DC_LockDc ( hDC
);
1775 MmCopyFromCaller(&pDC
->dcattr
, pDC
->pdcattr
, sizeof(DC_ATTR
));
1776 DC_vFreeDcAttr(pDC
);
1779 if (!DC_SetOwnership( hDC
, NULL
)) // This hDC is inaccessible!
1783 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1785 pDC
= DC_LockDc ( hDC
);
1786 ASSERT(pDC
->pdcattr
== &pDC
->dcattr
);
1789 if (!DC_SetOwnership( hDC
, PsGetCurrentProcess() )) return Ret
;
1791 DC_AllocateDcAttr( hDC
); // Allocate new dcattr
1793 DCU_SynchDcAttrtoUser( hDC
); // Copy data from dc to dcattr
1796 if ((OwnerMask
!= GDI_OBJ_HMGR_NONE
) && !NoSetBrush
)
1798 pDC
= DC_LockDc ( hDC
);
1799 if (IntGdiSetBrushOwner((PBRUSH
)pDC
->dclevel
.pbrFill
, OwnerMask
))
1800 IntGdiSetBrushOwner((PBRUSH
)pDC
->dclevel
.pbrLine
, OwnerMask
);
1808 GreGetObjectOwner(HGDIOBJ Handle
, GDIOBJTYPE ObjType
)
1810 INT Ret
= GDI_OBJ_HMGR_RESTRICTED
;
1812 if ( GDI_HANDLE_GET_INDEX(Handle
) < GDI_HANDLE_COUNT
)
1814 PGDI_TABLE_ENTRY pEntry
= &GdiHandleTable
->Entries
[GDI_HANDLE_GET_INDEX(Handle
)];
1816 if (pEntry
->ObjectType
== ObjType
)
1818 if (pEntry
->FullUnique
== (GDI_HANDLE_GET_UPPER(Handle
) >> GDI_ENTRY_UPPER_SHIFT
))
1819 Ret
= pEntry
->ProcessId
& ~1;
1828 NtGdiCreateClientObj(
1835 /* Mask out everything that would change the type in a wrong manner */
1836 ulType
&= (GDI_HANDLE_TYPE_MASK
& ~GDI_HANDLE_BASETYPE_MASK
);
1838 /* Allocate a new object */
1839 pObject
= GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ
| ulType
);
1845 /* get the handle */
1846 handle
= pObject
->hHmgr
;
1849 GDIOBJ_UnlockObjByPtr(pObject
);
1857 NtGdiDeleteClientObj(
1861 /* We first need to get the real type from the handle */
1862 ULONG type
= GDI_HANDLE_GET_TYPE(h
);
1864 /* Check if it's really a CLIENTOBJ */
1865 if ((type
& GDI_HANDLE_BASETYPE_MASK
) != GDILoObjType_LO_CLIENTOBJ_TYPE
)
1867 /* FIXME: SetLastError? */
1870 return GDIOBJ_FreeObjByHandle(h
, type
);
1875 IntGdiGetObject(IN HANDLE Handle
,
1883 pGdiObject
= GDIOBJ_LockObj(Handle
, GDI_OBJECT_TYPE_DONTCARE
);
1886 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1890 dwObjectType
= GDIOBJ_GetObjectType(Handle
);
1891 switch (dwObjectType
)
1893 case GDI_OBJECT_TYPE_PEN
:
1894 case GDI_OBJECT_TYPE_EXTPEN
:
1895 Result
= PEN_GetObject((PBRUSH
) pGdiObject
, cbCount
, (PLOGPEN
) lpBuffer
); // IntGdiCreatePenIndirect
1898 case GDI_OBJECT_TYPE_BRUSH
:
1899 Result
= BRUSH_GetObject((PBRUSH
) pGdiObject
, cbCount
, (LPLOGBRUSH
)lpBuffer
);
1902 case GDI_OBJECT_TYPE_BITMAP
:
1903 Result
= BITMAP_GetObject((SURFACE
*) pGdiObject
, cbCount
, lpBuffer
);
1905 case GDI_OBJECT_TYPE_FONT
:
1906 Result
= FontGetObject((PTEXTOBJ
) pGdiObject
, cbCount
, lpBuffer
);
1908 // Fix the LOGFONT structure for the stock fonts
1909 if (FIRST_STOCK_HANDLE
<= Handle
&& Handle
<= LAST_STOCK_HANDLE
)
1911 FixStockFontSizeW(Handle
, cbCount
, lpBuffer
);
1916 case GDI_OBJECT_TYPE_PALETTE
:
1917 Result
= PALETTE_GetObject((PPALETTE
) pGdiObject
, cbCount
, lpBuffer
);
1921 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType
);
1925 GDIOBJ_UnlockObjByPtr(pGdiObject
);
1935 NtGdiExtGetObjectW(IN HANDLE hGdiObj
,
1937 OUT LPVOID lpBuffer
)
1944 DIBSECTION dibsection
;
1948 EXTLOGFONTW extlogfontw
;
1949 ENUMLOGFONTEXDVW enumlogfontexdvw
;
1952 // Normalize to the largest supported object size
1953 cbCount
= min((UINT
)cbCount
, sizeof(Object
));
1955 // Now do the actual call
1956 iRetCount
= IntGdiGetObject(hGdiObj
, cbCount
, lpBuffer
? &Object
: NULL
);
1957 cbCopyCount
= min((UINT
)cbCount
, (UINT
)iRetCount
);
1959 // Make sure we have a buffer and a copy size
1960 if ((cbCopyCount
) && (lpBuffer
))
1962 // Enter SEH for buffer transfer
1965 // Probe the buffer and copy it
1966 ProbeForWrite(lpBuffer
, cbCopyCount
, sizeof(WORD
));
1967 RtlCopyMemory(lpBuffer
, &Object
, cbCopyCount
);
1969 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1971 // Clear the return value.
1972 // Do *NOT* set last error here!