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)
634 Object
->BaseFlags
|= BASEFLAG_READY_TO_DIE
;
635 DPRINT("Object %p, ulShareCount = %d\n", Object
->hHmgr
, Object
->ulShareCount
);
636 //GDIDBG_TRACECALLER();
637 //GDIDBG_TRACESHARELOCKER(GDI_HANDLE_GET_INDEX(hObj));
638 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
639 /* Don't wait on shared locks */
645 * The object is currently locked by another thread, so freeing is forbidden!
647 DPRINT1("Object->cExclusiveLock = %d\n", Object
->cExclusiveLock
);
648 GDIDBG_TRACECALLER();
649 GDIDBG_TRACELOCKER(hObj
);
650 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
651 /* do not assert here for it will call again from dxg.sys it being call twice */
659 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
660 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
663 else if (PrevProcId
== LockedProcessId
)
665 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
667 /* the object is currently locked, wait some time and try again.
668 FIXME - we shouldn't loop forever! Give up after some time! */
677 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
679 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj
);
681 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
683 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
687 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);
689 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry
->Type
, Entry
->KernelData
, Entry
->ProcessId
);
690 GDIDBG_TRACECALLER();
691 GDIDBG_TRACEALLOCATOR(hObj
);
700 IsObjectDead(HGDIOBJ hObject
)
702 INT Index
= GDI_HANDLE_GET_INDEX(hObject
);
703 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
704 // We check to see if the objects are knocking on deaths door.
705 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
709 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject
);
710 return TRUE
; // return true and move on.
717 bPEBCacheHandle(HGDIOBJ Handle
, int oType
, PVOID pAttr
)
719 PGDIHANDLECACHE GdiHandleCache
;
722 int Offset
= 0, Number
;
725 GdiHandleCache
= (PGDIHANDLECACHE
)NtCurrentTeb()->ProcessEnvironmentBlock
->GdiHandleBuffer
;
734 Offset
= CACHE_BRUSH_ENTRIES
;
737 case hctRegionHandle
:
738 Offset
= CACHE_BRUSH_ENTRIES
+CACHE_PEN_ENTRIES
;
745 Lock
= InterlockedCompareExchangePointer( (PVOID
*)&GdiHandleCache
->ulLock
,
748 if (Lock
) return FALSE
;
752 Number
= GdiHandleCache
->ulNumHandles
[oType
];
754 hPtr
= GdiHandleCache
->Handle
+ Offset
;
756 if ( pAttr
&& oType
== hctRegionHandle
)
758 if ( Number
< CACHE_REGION_ENTRIES
)
760 ((PRGN_ATTR
)pAttr
)->AttrFlags
|= ATTR_CACHED
;
761 hPtr
[Number
] = Handle
;
762 GdiHandleCache
->ulNumHandles
[oType
]++;
763 DPRINT("Put Handle Count %d PEB 0x%x\n", GdiHandleCache
->ulNumHandles
[oType
], NtCurrentTeb()->ProcessEnvironmentBlock
);
768 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
774 (void)InterlockedExchangePointer((PVOID
*)&GdiHandleCache
->ulLock
, Lock
);
780 * \param hObject object handle
781 * \return if the function fails the returned value is FALSE.
785 GreDeleteObject(HGDIOBJ hObject
)
788 PGDI_TABLE_ENTRY Entry
;
792 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
793 if (!IsObjectDead(hObject
))
795 dwObjectType
= GDIOBJ_GetObjectType(hObject
);
797 Index
= GDI_HANDLE_GET_INDEX(hObject
);
798 Entry
= &GdiHandleTable
->Entries
[Index
];
799 pAttr
= Entry
->UserData
;
801 switch (dwObjectType
)
803 case GDI_OBJECT_TYPE_BRUSH
:
806 case GDI_OBJECT_TYPE_REGION
:
807 /* If pAttr NULL, the probability is high for System Region. */
809 bPEBCacheHandle(hObject
, hctRegionHandle
, pAttr
))
811 /* User space handle only! */
816 FreeObjectAttr(pAttr
);
817 Entry
->UserData
= NULL
;
821 case GDI_OBJECT_TYPE_DC
:
822 // DC_FreeDcAttr(hObject);
826 return NULL
!= hObject
827 ? GDIOBJ_FreeObjByHandle(hObject
, dwObjectType
) : FALSE
;
831 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject
);
832 return TRUE
; // return true and move on.
838 IntDeleteHandlesForProcess(struct _EPROCESS
*Process
, ULONG ObjectType
)
840 PGDI_TABLE_ENTRY Entry
, End
;
841 ULONG Index
= RESERVE_ENTRIES_COUNT
;
843 PPROCESSINFO W32Process
;
845 W32Process
= (PPROCESSINFO
)Process
->Win32Process
;
848 if (W32Process
->GDIHandleCount
> 0)
850 ProcId
= Process
->UniqueProcessId
;
852 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
853 we should delete it directly here! */
855 End
= &GdiHandleTable
->Entries
[GDI_HANDLE_COUNT
];
856 for (Entry
= &GdiHandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
860 /* ignore the lock bit */
861 if ( (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
)
863 if ( (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == ObjectType
||
864 ObjectType
== GDI_OBJECT_TYPE_DONTCARE
)
866 HGDIOBJ ObjectHandle
;
868 /* Create the object handle for the entry, the lower(!) 16 bit of the
869 Type field includes the type of the object including the stock
870 object flag - but since stock objects don't have a process id we can
871 simply ignore this fact here. */
872 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
874 if (!GDIOBJ_FreeObjByHandle(ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
))
876 DPRINT1("Failed to delete object %p!\n", ObjectHandle
);
879 if (W32Process
->GDIHandleCount
== 0)
881 /* there are no more gdi handles for this process, bail */
892 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
893 * \param Process - PID of the process that will be destroyed.
896 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
898 PEPROCESS CurrentProcess
;
899 PPROCESSINFO W32Process
;
901 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
902 CurrentProcess
= PsGetCurrentProcess();
903 if (CurrentProcess
!= Process
)
905 KeAttachProcess(&Process
->Pcb
);
908 W32Process
= (PPROCESSINFO
)CurrentProcess
->Win32Process
;
910 /* Delete objects. Begin with types that are not referenced by other types */
911 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_DC_TYPE
);
912 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BRUSH_TYPE
);
913 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BITMAP_TYPE
);
915 /* Finally finish with what's left */
916 IntDeleteHandlesForProcess(Process
, GDI_OBJECT_TYPE_DONTCARE
);
918 if (CurrentProcess
!= Process
)
924 GdiDbgHTIntegrityCheck();
927 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
928 if (W32Process
->GDIHandleCount
> 0)
930 DPRINT1("Leaking %d handles!\n", W32Process
->GDIHandleCount
);
937 * Return pointer to the object by handle.
939 * \param hObj Object handle
940 * \return Pointer to the object.
942 * \note Process can only get pointer to the objects it created or global objects.
944 * \todo Get rid of the ExpectedType parameter!
946 PGDIOBJ INTERNAL_CALL
947 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
950 PGDI_TABLE_ENTRY Entry
;
951 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
953 ULONG HandleType
, HandleUpper
;
955 /* Check for dummy call */
959 GDIDBG_INITLOOPTRACE();
961 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
962 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
963 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
965 /* Check that the handle index is valid. */
966 if (HandleIndex
>= GDI_HANDLE_COUNT
)
969 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
971 /* Check if we have the requested type */
972 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
973 HandleType
!= ExpectedType
) ||
976 DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
977 hObj
, HandleType
, ExpectedType
);
978 GDIDBG_TRACECALLER();
979 GDIDBG_TRACEALLOCATOR(hObj
);
980 GDIDBG_TRACEDELETER(hObj
);
984 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
985 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
987 /* Check for invalid owner. */
988 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
990 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj
, ProcessId
, HandleProcessId
);
991 GDIDBG_TRACECALLER();
992 GDIDBG_TRACEALLOCATOR(hObj
);
997 * Prevent the thread from being terminated during the locking process.
998 * It would result in undesired effects and inconsistency of the global
1002 KeEnterCriticalRegion();
1005 * Loop until we either successfully lock the handle entry & object or
1006 * fail some of the check.
1011 /* Lock the handle table entry. */
1012 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
1013 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
1017 if (PrevProcId
== HandleProcessId
)
1020 * We're locking an object that belongs to our process or it's a
1021 * global object if HandleProcessId is 0 here.
1024 if ( (Entry
->KernelData
!= NULL
) &&
1025 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
1027 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1028 Object
= Entry
->KernelData
;
1030 if (Object
->cExclusiveLock
== 0)
1032 Object
->Tid
= Thread
;
1033 Object
->cExclusiveLock
= 1;
1034 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj
))
1038 if (Object
->Tid
!= Thread
)
1040 GDIDBG_TRACELOOP(hObj
, Object
->Tid
, Thread
);
1041 GDIDBG_TRACECALLER();
1042 GDIDBG_TRACELOCKER(hObj
);
1043 GDIDBG_TRACEALLOCATOR(hObj
);
1045 /* Unlock the handle table entry. */
1046 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1051 InterlockedIncrement((PLONG
)&Object
->cExclusiveLock
);
1057 * Debugging code. Report attempts to lock deleted handles and
1058 * locking type mismatches.
1060 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
1063 /* Unlock the handle table entry. */
1064 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1071 * The handle is currently locked, wait some time and try again.
1073 GDIDBG_TRACELOOP(hObj
, PrevProcId
, NULL
);
1080 KeLeaveCriticalRegion();
1087 * Return pointer to the object by handle (and allow sharing of the handle
1090 * \param hObj Object handle
1091 * \return Pointer to the object.
1093 * \note Process can only get pointer to the objects it created or global objects.
1095 * \todo Get rid of the ExpectedType parameter!
1097 PGDIOBJ INTERNAL_CALL
1098 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
1101 PGDI_TABLE_ENTRY Entry
;
1102 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
1104 ULONG_PTR HandleType
, HandleUpper
;
1106 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
1107 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
1108 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
1110 /* Check that the handle index is valid. */
1111 if (HandleIndex
>= GDI_HANDLE_COUNT
)
1114 /* Check if we have the requested type */
1115 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
1116 HandleType
!= ExpectedType
) ||
1119 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1120 hObj
, HandleType
, ExpectedType
);
1124 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
1126 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
1127 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
1129 /* Check for invalid owner. */
1130 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
1136 * Prevent the thread from being terminated during the locking process.
1137 * It would result in undesired effects and inconsistency of the global
1141 KeEnterCriticalRegion();
1144 * Loop until we either successfully lock the handle entry & object or
1145 * fail some of the check.
1150 /* Lock the handle table entry. */
1151 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
1152 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
1156 if (PrevProcId
== HandleProcessId
)
1159 * We're locking an object that belongs to our process or it's a
1160 * global object if HandleProcessId is 0 here.
1163 if ( (Entry
->KernelData
!= NULL
) &&
1164 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
1166 Object
= (POBJ
)Entry
->KernelData
;
1168 GDIDBG_CAPTURESHARELOCKER(HandleIndex
);
1170 if (InterlockedIncrement((PLONG
)&Object
->ulShareCount
) == 1)
1172 memset(GDIHandleLocker
[HandleIndex
], 0x00, GDI_STACK_LEVELS
* sizeof(ULONG
));
1173 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS
, (PVOID
*)GDIHandleShareLocker
[HandleIndex
], NULL
);
1176 InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
1182 * Debugging code. Report attempts to lock deleted handles and
1183 * locking type mismatches.
1185 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
1188 /* Unlock the handle table entry. */
1189 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1196 * The handle is currently locked, wait some time and try again.
1204 KeLeaveCriticalRegion();
1210 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
1212 PGDI_TABLE_ENTRY Entry
;
1216 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1218 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1220 ProcessId
= PsGetCurrentProcessId();
1222 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1223 Ret
= Entry
->KernelData
!= NULL
&&
1224 (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0 &&
1225 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1234 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1237 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1238 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1240 PGDI_TABLE_ENTRY Entry
;
1241 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1245 GDIDBG_INITLOOPTRACE();
1250 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj
);
1252 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1254 if (!GDI_HANDLE_IS_STOCKOBJ(hObj
))
1256 ProcessId
= PsGetCurrentProcessId();
1257 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1259 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
1262 /* lock the object, we must not convert stock objects, so don't check!!! */
1263 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1264 if (PrevProcId
== ProcessId
)
1266 LONG NewType
, PrevType
, OldType
;
1268 /* we're locking an object that belongs to our process. First calculate
1269 the new object type including the stock object flag and then try to
1271 /* On Windows the higher 16 bit of the type field don't contain the
1272 full type from the handle, but the base type.
1273 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1274 OldType
= ((ULONG
)hObj
& GDI_HANDLE_BASETYPE_MASK
) | ((ULONG
)hObj
>> GDI_ENTRY_UPPER_SHIFT
);
1275 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1276 we copy them as we can't get them from the handle */
1277 OldType
|= Entry
->Type
& GDI_ENTRY_FLAGS_MASK
;
1279 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1280 NewType
= OldType
| GDI_ENTRY_STOCK_MASK
;
1282 /* Try to exchange the type field - but only if the old (previous type) matches! */
1283 PrevType
= InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1284 if (PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1286 PTHREADINFO PrevThread
;
1289 /* We successfully set the stock object flag.
1290 KernelData should never be NULL here!!! */
1291 ASSERT(Entry
->KernelData
);
1293 Object
= Entry
->KernelData
;
1295 PrevThread
= Object
->Tid
;
1296 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1298 /* dereference the process' object counter */
1299 if (PrevProcId
!= GDI_GLOBAL_PROCESS
)
1301 PEPROCESS OldProcess
;
1302 PPROCESSINFO W32Process
;
1306 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1307 if (NT_SUCCESS(Status
))
1309 W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
1310 if (W32Process
!= NULL
)
1312 InterlockedDecrement(&W32Process
->GDIHandleCount
);
1314 ObDereferenceObject(OldProcess
);
1318 hObj
= (HGDIOBJ
)((ULONG
)(hObj
) | GDI_HANDLE_STOCK_MASK
);
1320 Object
->hHmgr
= hObj
;
1322 /* remove the process id lock and make it global */
1323 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1325 /* we're done, successfully converted the object */
1330 GDIDBG_TRACELOOP(hObj
, PrevThread
, Thread
);
1332 /* WTF?! The object is already locked by a different thread!
1333 Release the lock, wait a bit and try again!
1334 FIXME - we should give up after some time unless we want to wait forever! */
1335 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1343 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1344 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType
, Entry
->Type
, NewType
, Entry
->KernelData
);
1347 else if (PrevProcId
== LockedProcessId
)
1349 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
1351 /* the object is currently locked, wait some time and try again.
1352 FIXME - we shouldn't loop forever! Give up after some time! */
1359 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1367 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1369 PGDI_TABLE_ENTRY Entry
;
1370 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1374 GDIDBG_INITLOOPTRACE();
1376 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1378 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1380 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1382 ProcessId
= PsGetCurrentProcessId();
1383 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1385 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1388 /* lock the object, we must not convert stock objects, so don't check!!! */
1389 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1390 if (PrevProcId
== ProcessId
)
1392 PTHREADINFO PrevThread
;
1394 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1396 POBJ Object
= Entry
->KernelData
;
1398 PrevThread
= Object
->Tid
;
1399 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1401 PEPROCESS OldProcess
;
1402 PPROCESSINFO W32Process
;
1405 /* dereference the process' object counter */
1407 if ((ULONG_PTR
)PrevProcId
& ~0x1)
1409 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1410 if (NT_SUCCESS(Status
))
1412 W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
1413 if (W32Process
!= NULL
)
1415 InterlockedDecrement(&W32Process
->GDIHandleCount
);
1417 ObDereferenceObject(OldProcess
);
1421 if (NewOwner
!= NULL
)
1423 ProcessId
= PsGetProcessId(NewOwner
);
1425 /* Increase the new process' object counter */
1426 W32Process
= (PPROCESSINFO
)NewOwner
->Win32Process
;
1427 if (W32Process
!= NULL
)
1429 InterlockedIncrement(&W32Process
->GDIHandleCount
);
1435 /* remove the process id lock and change it to the new process id */
1436 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
);
1443 GDIDBG_TRACELOOP(ObjectHandle
, PrevThread
, Thread
);
1445 /* WTF?! The object is already locked by a different thread!
1446 Release the lock, wait a bit and try again! DO reset the pid lock
1447 so we make sure we don't access invalid memory in case the object is
1448 being deleted in the meantime (because we don't have aquired a reference
1450 FIXME - we should give up after some time unless we want to wait forever! */
1451 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1459 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1460 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry
->Type
, Entry
->KernelData
);
1464 else if (PrevProcId
== LockedProcessId
)
1466 GDIDBG_TRACELOOP(ObjectHandle
, PrevProcId
, ProcessId
);
1468 /* the object is currently locked, wait some time and try again.
1469 FIXME - we shouldn't loop forever! Give up after some time! */
1474 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1476 /* allow changing ownership of global objects */
1478 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1481 else if ((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1483 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1488 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1496 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1498 PGDI_TABLE_ENTRY FromEntry
;
1500 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1503 GDIDBG_INITLOOPTRACE();
1505 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1507 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1509 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1511 FromEntry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, CopyFrom
);
1513 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1514 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1517 /* lock the object, we must not convert stock objects, so don't check!!! */
1518 FromPrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1519 if (FromPrevProcId
== FromProcessId
)
1521 PTHREADINFO PrevThread
;
1524 if ((FromEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1526 Object
= FromEntry
->KernelData
;
1528 /* save the pointer to the calling thread so we know it was this thread
1529 that locked the object */
1530 PrevThread
= Object
->Tid
;
1531 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1533 /* now let's change the ownership of the target object */
1535 if (((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1537 PEPROCESS ProcessTo
;
1539 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1541 GDIOBJ_SetOwnership(CopyTo
, ProcessTo
);
1542 ObDereferenceObject(ProcessTo
);
1547 /* mark the object as global */
1548 GDIOBJ_SetOwnership(CopyTo
, NULL
);
1551 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1555 GDIDBG_TRACELOOP(CopyFrom
, PrevThread
, Thread
);
1557 /* WTF?! The object is already locked by a different thread!
1558 Release the lock, wait a bit and try again! DO reset the pid lock
1559 so we make sure we don't access invalid memory in case the object is
1560 being deleted in the meantime (because we don't have aquired a reference
1562 FIXME - we should give up after some time unless we want to wait forever! */
1563 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1566 goto LockHandleFrom
;
1571 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1575 else if (FromPrevProcId
== FromLockedProcessId
)
1577 GDIDBG_TRACELOOP(CopyFrom
, FromPrevProcId
, FromProcessId
);
1579 /* the object is currently locked, wait some time and try again.
1580 FIXME - we shouldn't loop forever! Give up after some time! */
1583 goto LockHandleFrom
;
1585 else if ((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1587 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1588 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1589 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1590 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1591 goto LockHandleFrom
;
1595 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1603 GDI_MapHandleTable(PSECTION_OBJECT SectionObject
, PEPROCESS Process
)
1605 PVOID MappedView
= NULL
;
1607 LARGE_INTEGER Offset
;
1608 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1610 Offset
.QuadPart
= 0;
1612 ASSERT(SectionObject
!= NULL
);
1613 ASSERT(Process
!= NULL
);
1615 Status
= MmMapViewOfSection(SectionObject
,
1626 if (!NT_SUCCESS(Status
))
1632 /* Locks 2 or 3 objects at a time */
1635 GDIOBJ_LockMultipleObjs(ULONG ulCount
,
1639 UINT auiIndices
[3] = {0,1,2};
1641 BOOL bUnsorted
= TRUE
;
1643 /* First is greatest */
1647 for(i
=1; i
<ulCount
; i
++)
1649 if((ULONG_PTR
)ahObj
[auiIndices
[i
-1]] < (ULONG_PTR
)ahObj
[auiIndices
[i
]])
1651 tmp
= auiIndices
[i
-1];
1652 auiIndices
[i
-1] = auiIndices
[i
];
1653 auiIndices
[i
] = tmp
;
1659 for(i
=0;i
<ulCount
;i
++)
1660 apObj
[auiIndices
[i
]] = GDIOBJ_LockObj(ahObj
[auiIndices
[i
]], GDI_OBJECT_TYPE_DONTCARE
);
1664 /** PUBLIC FUNCTIONS **********************************************************/
1668 IntGdiSetRegionOwner(HRGN hRgn
, DWORD OwnerMask
)
1671 PGDI_TABLE_ENTRY Entry
;
1674 These regions do not use attribute sections and when allocated, use gdiobj
1677 // FIXME! HAX!!! Remove this once we get everything right!
1678 Index
= GDI_HANDLE_GET_INDEX(hRgn
);
1679 Entry
= &GdiHandleTable
->Entries
[Index
];
1680 if (Entry
->UserData
) FreeObjectAttr(Entry
->UserData
);
1681 Entry
->UserData
= NULL
;
1683 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1685 return GDIOBJ_SetOwnership(hRgn
, NULL
);
1687 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1689 return GDIOBJ_SetOwnership((HGDIOBJ
) hRgn
, PsGetCurrentProcess() );
1696 IntGdiSetBrushOwner(PBRUSH pbr
, DWORD OwnerMask
)
1699 PEPROCESS Owner
= NULL
;
1700 PGDI_TABLE_ENTRY pEntry
= NULL
;
1702 if (!pbr
) return FALSE
;
1704 hBR
= pbr
->BaseObject
.hHmgr
;
1706 if (!hBR
|| (GDI_HANDLE_GET_TYPE(hBR
) != GDI_OBJECT_TYPE_BRUSH
))
1710 INT Index
= GDI_HANDLE_GET_INDEX((HGDIOBJ
)hBR
);
1711 pEntry
= &GdiHandleTable
->Entries
[Index
];
1714 if (pbr
->flAttrs
& GDIBRUSH_IS_GLOBAL
)
1716 GDIOBJ_ShareUnlockObjByPtr((POBJ
)pbr
);
1720 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1722 // Set this Brush to inaccessible mode and to an Owner of NONE.
1723 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1725 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, Owner
))
1728 // Deny user access to User Data.
1729 pEntry
->UserData
= NULL
; // This hBR is inaccessible!
1732 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1734 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, PsGetCurrentProcess() ))
1737 // Allow user access to User Data.
1738 pEntry
->UserData
= pbr
->pBrushAttr
;
1745 IntGdiSetDCOwnerEx( HDC hDC
, DWORD OwnerMask
, BOOL NoSetBrush
)
1750 if (!hDC
|| (GDI_HANDLE_GET_TYPE(hDC
) != GDI_OBJECT_TYPE_DC
)) return FALSE
;
1752 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1754 pDC
= DC_LockDc ( hDC
);
1755 MmCopyFromCaller(&pDC
->dcattr
, pDC
->pdcattr
, sizeof(DC_ATTR
));
1756 DC_vFreeDcAttr(pDC
);
1759 if (!DC_SetOwnership( hDC
, NULL
)) // This hDC is inaccessible!
1763 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1765 pDC
= DC_LockDc ( hDC
);
1766 ASSERT(pDC
->pdcattr
== &pDC
->dcattr
);
1769 if (!DC_SetOwnership( hDC
, PsGetCurrentProcess() )) return Ret
;
1771 DC_AllocateDcAttr( hDC
); // Allocate new dcattr
1773 DCU_SynchDcAttrtoUser( hDC
); // Copy data from dc to dcattr
1776 if ((OwnerMask
!= GDI_OBJ_HMGR_NONE
) && !NoSetBrush
)
1778 pDC
= DC_LockDc ( hDC
);
1779 if (IntGdiSetBrushOwner((PBRUSH
)pDC
->dclevel
.pbrFill
, OwnerMask
))
1780 IntGdiSetBrushOwner((PBRUSH
)pDC
->dclevel
.pbrLine
, OwnerMask
);
1788 GreGetObjectOwner(HGDIOBJ Handle
, GDIOBJTYPE ObjType
)
1790 INT Ret
= GDI_OBJ_HMGR_RESTRICTED
;
1792 if ( GDI_HANDLE_GET_INDEX(Handle
) < GDI_HANDLE_COUNT
)
1794 PGDI_TABLE_ENTRY pEntry
= &GdiHandleTable
->Entries
[GDI_HANDLE_GET_INDEX(Handle
)];
1796 if (pEntry
->ObjectType
== ObjType
)
1798 if (pEntry
->FullUnique
== (GDI_HANDLE_GET_UPPER(Handle
) >> GDI_ENTRY_UPPER_SHIFT
))
1799 Ret
= pEntry
->ProcessId
& ~1;
1808 NtGdiCreateClientObj(
1815 /* Mask out everything that would change the type in a wrong manner */
1816 ulType
&= (GDI_HANDLE_TYPE_MASK
& ~GDI_HANDLE_BASETYPE_MASK
);
1818 /* Allocate a new object */
1819 pObject
= GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ
| ulType
);
1825 /* get the handle */
1826 handle
= pObject
->hHmgr
;
1829 GDIOBJ_UnlockObjByPtr(pObject
);
1837 NtGdiDeleteClientObj(
1841 /* We first need to get the real type from the handle */
1842 ULONG type
= GDI_HANDLE_GET_TYPE(h
);
1844 /* Check if it's really a CLIENTOBJ */
1845 if ((type
& GDI_HANDLE_BASETYPE_MASK
) != GDILoObjType_LO_CLIENTOBJ_TYPE
)
1847 /* FIXME: SetLastError? */
1850 return GDIOBJ_FreeObjByHandle(h
, type
);
1855 IntGdiGetObject(IN HANDLE Handle
,
1863 pGdiObject
= GDIOBJ_LockObj(Handle
, GDI_OBJECT_TYPE_DONTCARE
);
1866 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1870 dwObjectType
= GDIOBJ_GetObjectType(Handle
);
1871 switch (dwObjectType
)
1873 case GDI_OBJECT_TYPE_PEN
:
1874 case GDI_OBJECT_TYPE_EXTPEN
:
1875 Result
= PEN_GetObject((PBRUSH
) pGdiObject
, cbCount
, (PLOGPEN
) lpBuffer
); // IntGdiCreatePenIndirect
1878 case GDI_OBJECT_TYPE_BRUSH
:
1879 Result
= BRUSH_GetObject((PBRUSH
) pGdiObject
, cbCount
, (LPLOGBRUSH
)lpBuffer
);
1882 case GDI_OBJECT_TYPE_BITMAP
:
1883 Result
= BITMAP_GetObject((SURFACE
*) pGdiObject
, cbCount
, lpBuffer
);
1885 case GDI_OBJECT_TYPE_FONT
:
1886 Result
= FontGetObject((PTEXTOBJ
) pGdiObject
, cbCount
, lpBuffer
);
1888 // Fix the LOGFONT structure for the stock fonts
1889 if (FIRST_STOCK_HANDLE
<= Handle
&& Handle
<= LAST_STOCK_HANDLE
)
1891 FixStockFontSizeW(Handle
, cbCount
, lpBuffer
);
1896 case GDI_OBJECT_TYPE_PALETTE
:
1897 Result
= PALETTE_GetObject((PPALETTE
) pGdiObject
, cbCount
, lpBuffer
);
1901 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType
);
1905 GDIOBJ_UnlockObjByPtr(pGdiObject
);
1915 NtGdiExtGetObjectW(IN HANDLE hGdiObj
,
1917 OUT LPVOID lpBuffer
)
1924 DIBSECTION dibsection
;
1928 EXTLOGFONTW extlogfontw
;
1929 ENUMLOGFONTEXDVW enumlogfontexdvw
;
1932 // Normalize to the largest supported object size
1933 cbCount
= min((UINT
)cbCount
, sizeof(Object
));
1935 // Now do the actual call
1936 iRetCount
= IntGdiGetObject(hGdiObj
, cbCount
, lpBuffer
? &Object
: NULL
);
1937 cbCopyCount
= min((UINT
)cbCount
, (UINT
)iRetCount
);
1939 // Make sure we have a buffer and a copy size
1940 if ((cbCopyCount
) && (lpBuffer
))
1942 // Enter SEH for buffer transfer
1945 // Probe the buffer and copy it
1946 ProbeForWrite(lpBuffer
, cbCopyCount
, sizeof(WORD
));
1947 RtlCopyMemory(lpBuffer
, &Object
, cbCopyCount
);
1949 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1951 // Clear the return value.
1952 // Do *NOT* set last error here!