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 ******************************************************************/
15 #define BASE_OBJTYPE_COUNT 32
17 #define DelayExecution() \
18 DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
19 KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
22 BOOL INTERNAL_CALL
GDI_CleanupDummy(PVOID ObjectBody
);
24 /** GLOBALS *******************************************************************/
31 GDICLEANUPPROC CleanupProc
;
32 } OBJ_TYPE_INFO
, *POBJ_TYPE_INFO
;
35 OBJ_TYPE_INFO ObjTypeInfo
[BASE_OBJTYPE_COUNT
] =
37 {0, 0, 0, NULL
}, /* 00 reserved entry */
38 {1, sizeof(DC
), TAG_DC
, DC_Cleanup
}, /* 01 DC */
39 {1, 0, 0, NULL
}, /* 02 UNUSED1 */
40 {1, 0, 0, NULL
}, /* 03 UNUSED2 */
41 {1, sizeof(ROSRGNDATA
), TAG_REGION
, REGION_Cleanup
}, /* 04 RGN */
42 {1, sizeof(SURFACE
), TAG_SURFACE
, SURFACE_Cleanup
}, /* 05 SURFACE */
43 {1, sizeof(CLIENTOBJ
), TAG_CLIENTOBJ
, GDI_CleanupDummy
}, /* 06 CLIENTOBJ: METADC,... */
44 {1, sizeof(PATH
), TAG_PATH
, GDI_CleanupDummy
}, /* 07 PATH */
45 {1, sizeof(PALETTE
), TAG_PALETTE
, PALETTE_Cleanup
}, /* 08 PAL */
46 {1, sizeof(COLORSPACE
), TAG_ICMLCS
, GDI_CleanupDummy
}, /* 09 ICMLCS, */
47 {1, sizeof(TEXTOBJ
), TAG_LFONT
, GDI_CleanupDummy
}, /* 0a LFONT */
48 {0, 0, TAG_RFONT
, NULL
}, /* 0b RFONT, unused */
49 {0, 0, TAG_PFE
, NULL
}, /* 0c PFE, unused */
50 {0, 0, TAG_PFT
, NULL
}, /* 0d PFT, unused */
51 {0, sizeof(GDICLRXFORM
), TAG_ICMCXF
, GDI_CleanupDummy
}, /* 0e ICMCXF, */
52 {0, 0, TAG_SPRITE
, NULL
}, /* 0f SPRITE, unused */
53 {1, sizeof(BRUSH
), TAG_BRUSH
, BRUSH_Cleanup
}, /* 10 BRUSH, PEN, EXTPEN */
54 {0, 0, TAG_UMPD
, NULL
}, /* 11 UMPD, unused */
55 {0, 0, 0, NULL
}, /* 12 UNUSED4 */
56 {0, 0, TAG_SPACE
, NULL
}, /* 13 SPACE, unused */
57 {0, 0, 0, NULL
}, /* 14 UNUSED5 */
58 {0, 0, TAG_META
, NULL
}, /* 15 META, unused */
59 {0, 0, TAG_EFSTATE
, NULL
}, /* 16 EFSTATE, unused */
60 {0, 0, TAG_BMFD
, NULL
}, /* 17 BMFD, unused */
61 {0, 0, TAG_VTFD
, NULL
}, /* 18 VTFD, unused */
62 {0, 0, TAG_TTFD
, NULL
}, /* 19 TTFD, unused */
63 {0, 0, TAG_RC
, NULL
}, /* 1a RC, unused */
64 {0, 0, TAG_TEMP
, NULL
}, /* 1b TEMP, unused */
65 {0, sizeof(EDRIVEROBJ
), TAG_DRVOBJ
, DRIVEROBJ_Cleanup
},/* 1c DRVOBJ */
66 {0, 0, TAG_DCIOBJ
, NULL
}, /* 1d DCIOBJ, unused */
67 {0, 0, TAG_SPOOL
, NULL
}, /* 1e SPOOL, unused */
68 {0, 0, 0, NULL
}, /* 1f reserved entry */
71 static LARGE_INTEGER ShortDelay
;
72 PGDI_HANDLE_TABLE GdiHandleTable
= NULL
;
73 static PSECTION_OBJECT GdiTableSection
= NULL
;
75 /** INTERNAL FUNCTIONS ********************************************************/
85 AllocTypeDataDump(INT TypeInfo
)
87 switch( TypeInfo
& GDI_HANDLE_TYPE_MASK
)
89 case GDILoObjType_LO_BRUSH_TYPE
:
92 case GDILoObjType_LO_DC_TYPE
:
95 case GDILoObjType_LO_BITMAP_TYPE
:
98 case GDILoObjType_LO_FONT_TYPE
:
101 case GDILoObjType_LO_REGION_TYPE
:
108 DeAllocTypeDataDump(INT TypeInfo
)
110 switch( TypeInfo
& GDI_HANDLE_TYPE_MASK
)
112 case GDILoObjType_LO_BRUSH_TYPE
:
115 case GDILoObjType_LO_DC_TYPE
:
118 case GDILoObjType_LO_BITMAP_TYPE
:
121 case GDILoObjType_LO_FONT_TYPE
:
124 case GDILoObjType_LO_REGION_TYPE
:
131 * Dummy GDI Cleanup Callback
135 GDI_CleanupDummy(PVOID ObjectBody
)
141 * Allocate GDI object table.
142 * \param Size - number of entries in the object table.
147 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT
*SectionObject
)
149 PGDI_HANDLE_TABLE HandleTable
= NULL
;
150 LARGE_INTEGER htSize
;
155 ASSERT(SectionObject
!= NULL
);
157 htSize
.QuadPart
= sizeof(GDI_HANDLE_TABLE
);
159 Status
= MmCreateSection((PVOID
*)SectionObject
,
167 if (!NT_SUCCESS(Status
))
170 /* FIXME - use MmMapViewInSessionSpace once available! */
171 Status
= MmMapViewInSystemSpace(*SectionObject
,
172 (PVOID
*)&HandleTable
,
174 if (!NT_SUCCESS(Status
))
176 ObDereferenceObject(*SectionObject
);
177 *SectionObject
= NULL
;
181 RtlZeroMemory(HandleTable
, sizeof(GDI_HANDLE_TABLE
));
183 HandleTable
->LookasideLists
= ExAllocatePoolWithTag(NonPagedPool
,
184 BASE_OBJTYPE_COUNT
* sizeof(PAGED_LOOKASIDE_LIST
),
186 if (HandleTable
->LookasideLists
== NULL
)
188 MmUnmapViewInSystemSpace(HandleTable
);
189 ObDereferenceObject(*SectionObject
);
190 *SectionObject
= NULL
;
194 for (ObjType
= 0; ObjType
< BASE_OBJTYPE_COUNT
; ObjType
++)
196 if (ObjTypeInfo
[ObjType
].bUseLookaside
)
198 ExInitializePagedLookasideList(HandleTable
->LookasideLists
+ ObjType
,
202 ObjTypeInfo
[ObjType
].ulBodySize
,
203 ObjTypeInfo
[ObjType
].Tag
,
208 ShortDelay
.QuadPart
= -5000LL; /* FIXME - 0.5 ms? */
210 HandleTable
->FirstFree
= 0;
211 HandleTable
->FirstUnused
= RESERVE_ENTRIES_COUNT
;
221 /* Create the GDI handle table */
222 GdiHandleTable
= GDIOBJ_iAllocHandleTable(&GdiTableSection
);
223 if (GdiHandleTable
== NULL
)
225 DPRINT1("Failed to initialize the GDI handle table.\n");
226 return STATUS_UNSUCCESSFUL
;
229 return STATUS_SUCCESS
;
234 LockErrorDebugOutput(HGDIOBJ hObj
, PGDI_TABLE_ENTRY Entry
, LPSTR Function
)
236 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
238 DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function
, hObj
);
239 GDIDBG_TRACEDELETER(hObj
);
241 else if (GDI_HANDLE_GET_REUSECNT(hObj
) != GDI_ENTRY_GET_REUSECNT(Entry
->Type
))
243 DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
244 Function
, hObj
, GDI_HANDLE_GET_REUSECNT(hObj
), GDI_ENTRY_GET_REUSECNT(Entry
->Type
));
246 else if (GDI_HANDLE_GET_TYPE(hObj
) != ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
))
248 DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
249 Function
, hObj
, GDI_HANDLE_GET_TYPE(hObj
), (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
);
253 DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
254 Function
, hObj
, Entry
->Type
);
256 GDIDBG_TRACECALLER();
261 InterlockedPopFreeEntry(VOID
)
263 ULONG iFirst
, iNext
, iPrev
;
264 PGDI_TABLE_ENTRY pEntry
;
266 DPRINT("Enter InterLockedPopFreeEntry\n");
270 /* Get the index and sequence number of the first free entry */
271 iFirst
= GdiHandleTable
->FirstFree
;
273 /* Check if we have a free entry */
274 if (!(iFirst
& GDI_HANDLE_INDEX_MASK
))
276 /* Increment FirstUnused and get the new index */
277 iFirst
= InterlockedIncrement((LONG
*)&GdiHandleTable
->FirstUnused
) - 1;
279 /* Check if we have unused entries left */
280 if (iFirst
>= GDI_HANDLE_COUNT
)
282 DPRINT1("No more gdi handles left!\n");
286 /* Return the old index */
290 /* Get a pointer to the first free entry */
291 pEntry
= GdiHandleTable
->Entries
+ (iFirst
& GDI_HANDLE_INDEX_MASK
);
293 /* Create a new value with an increased sequence number */
294 iNext
= (USHORT
)(ULONG_PTR
)pEntry
->KernelData
;
295 iNext
|= (iFirst
& ~GDI_HANDLE_INDEX_MASK
) + 0x10000;
297 /* Try to exchange the FirstFree value */
298 iPrev
= InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
,
302 while (iPrev
!= iFirst
);
304 /* Sanity check: is entry really free? */
305 ASSERT(((ULONG_PTR
)pEntry
->KernelData
& ~GDI_HANDLE_INDEX_MASK
) == 0);
307 return iFirst
& GDI_HANDLE_INDEX_MASK
;
310 /* Pushes an entry of the handle table to the free list,
311 The entry must be unlocked and the base type field must be 0 */
314 InterlockedPushFreeEntry(ULONG idxToFree
)
316 ULONG iToFree
, iFirst
, iPrev
;
317 PGDI_TABLE_ENTRY pFreeEntry
;
319 DPRINT("Enter InterlockedPushFreeEntry\n");
321 pFreeEntry
= GdiHandleTable
->Entries
+ idxToFree
;
322 ASSERT((pFreeEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0);
323 ASSERT(pFreeEntry
->ProcessId
== 0);
324 pFreeEntry
->UserData
= NULL
; // FIXME
325 ASSERT(pFreeEntry
->UserData
== NULL
);
329 /* Get the current first free index and sequence number */
330 iFirst
= GdiHandleTable
->FirstFree
;
332 /* Set the KernelData member to the index of the first free entry */
333 pFreeEntry
->KernelData
= UlongToPtr(iFirst
& GDI_HANDLE_INDEX_MASK
);
335 /* Combine new index and increased sequence number in iToFree */
336 iToFree
= idxToFree
| ((iFirst
& ~GDI_HANDLE_INDEX_MASK
) + 0x10000);
338 /* Try to atomically update the first free entry */
339 iPrev
= InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
,
343 while (iPrev
!= iFirst
);
349 GDIOBJ_ValidateHandle(HGDIOBJ hObj
, ULONG ObjectType
)
351 PGDI_TABLE_ENTRY Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
352 if ((((ULONG_PTR
)hObj
& GDI_HANDLE_TYPE_MASK
) == ObjectType
) &&
353 (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == GDI_HANDLE_GET_UPPER(hObj
))
355 HANDLE pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
356 if (pid
== NULL
|| pid
== PsGetCurrentProcessId())
365 GDIOBJ_AllocObj(UCHAR BaseType
)
369 ASSERT((BaseType
& ~GDIObjTypeTotal
) == 0);
370 // BaseType &= GDI_HANDLE_BASETYPE_MASK;
372 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
374 PPAGED_LOOKASIDE_LIST LookasideList
;
376 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
377 pObject
= ExAllocateFromPagedLookasideList(LookasideList
);
381 pObject
= ExAllocatePoolWithTag(PagedPool
,
382 ObjTypeInfo
[BaseType
].ulBodySize
,
383 ObjTypeInfo
[BaseType
].Tag
);
388 RtlZeroMemory(pObject
, ObjTypeInfo
[BaseType
].ulBodySize
);
396 * Allocate memory for GDI object and return handle to it.
398 * \param ObjectType - type of object \ref GDI object types
400 * \return Pointer to the allocated object, which is locked.
403 GDIOBJ_AllocObjWithHandle(ULONG ObjectType
)
405 PPROCESSINFO W32Process
;
406 POBJ newObject
= NULL
;
407 HANDLE CurrentProcessId
, LockedProcessId
;
410 PGDI_TABLE_ENTRY Entry
;
413 GDIDBG_INITLOOPTRACE();
415 W32Process
= PsGetCurrentProcessWin32Process();
416 /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
417 to take too many GDI objects, itself. */
418 if (W32Process
&& W32Process
->GDIHandleCount
>= 0x2710)
420 DPRINT1("Too many objects for process!!!\n");
421 DPRINT1("DC %d BRUSH %d BITMAP %d FONT %d RGN %d\n",tDC
,tBRUSH
,tBITMAP
,tFONT
,tRGN
);
422 GDIDBG_DUMPHANDLETABLE();
426 ASSERT(ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
);
428 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(ObjectType
);
430 newObject
= GDIOBJ_AllocObj(TypeIndex
);
433 DPRINT1("Not enough memory to allocate gdi object!\n");
437 CurrentProcessId
= PsGetCurrentProcessId();
438 LockedProcessId
= (HANDLE
)((ULONG_PTR
)CurrentProcessId
| 0x1);
440 // RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
442 /* On Windows the higher 16 bit of the type field don't contain the
443 full type from the handle, but the base type.
444 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
445 TypeInfo
= (ObjectType
& GDI_HANDLE_BASETYPE_MASK
) | (ObjectType
>> GDI_ENTRY_UPPER_SHIFT
);
447 Index
= InterlockedPopFreeEntry();
452 Entry
= &GdiHandleTable
->Entries
[Index
];
455 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, 0);
456 if (PrevProcId
== NULL
)
458 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
461 Entry
->KernelData
= newObject
;
463 /* copy the reuse-counter */
464 TypeInfo
|= Entry
->Type
& GDI_ENTRY_REUSE_MASK
;
466 /* we found a free entry, no need to exchange this field atomically
467 since we're holding the lock */
468 Entry
->Type
= TypeInfo
;
470 /* Create a handle */
471 Handle
= (HGDIOBJ
)((Index
& 0xFFFF) | (TypeInfo
<< GDI_ENTRY_UPPER_SHIFT
));
473 /* Initialize BaseObject fields */
474 newObject
->hHmgr
= Handle
;
475 newObject
->ulShareCount
= 0;
476 newObject
->cExclusiveLock
= 1;
477 newObject
->Tid
= Thread
;
479 if (Thread
) Thread
->cExclusiveLocks
++;
482 AllocTypeDataDump(TypeInfo
);
484 /* unlock the entry */
485 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, CurrentProcessId
);
487 GDIDBG_CAPTUREALLOCATOR(Index
);
489 if (W32Process
!= NULL
)
491 InterlockedIncrement(&W32Process
->GDIHandleCount
);
494 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle
, newObject
);
499 GDIDBG_TRACELOOP(Index
, PrevProcId
, CurrentProcessId
);
500 /* damn, someone is trying to lock the object even though it doesn't
501 even exist anymore, wait a little and try again!
502 FIXME - we shouldn't loop forever! Give up after some time! */
509 GDIOBJ_FreeObj(newObject
, TypeIndex
);
511 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
512 GDIDBG_DUMPHANDLETABLE();
519 GDIOBJ_FreeObj(POBJ pObject
, UCHAR BaseType
)
521 /* Object must not have a handle! */
522 ASSERT(pObject
->hHmgr
== NULL
);
524 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
526 PPAGED_LOOKASIDE_LIST LookasideList
;
528 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
529 ExFreeToPagedLookasideList(LookasideList
, pObject
);
538 * Free memory allocated for the GDI object. For each object type this function calls the
539 * appropriate cleanup routine.
541 * \param hObj - handle of the object to be deleted.
543 * \return Returns TRUE if succesful.
544 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
545 * to the calling process.
547 * \bug This function should return VOID and kill the object no matter what...
550 GDIOBJ_FreeObjByHandle(HGDIOBJ hObj
, DWORD ExpectedType
)
552 PGDI_TABLE_ENTRY Entry
;
553 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
554 ULONG HandleType
, HandleUpper
, TypeIndex
;
557 GDIDBG_INITLOOPTRACE();
559 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj
);
561 if (GDI_HANDLE_IS_STOCKOBJ(hObj
))
563 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj
);
564 GDIDBG_TRACECALLER();
568 ProcessId
= PsGetCurrentProcessId();
569 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
571 Silent
= (ExpectedType
& GDI_OBJECT_TYPE_SILENT
);
572 ExpectedType
&= ~GDI_OBJECT_TYPE_SILENT
;
574 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
575 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
577 /* Check if we have the requested type */
578 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
579 HandleType
!= ExpectedType
) ||
582 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
583 hObj
, HandleType
, ExpectedType
);
584 GDIDBG_TRACECALLER();
588 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
591 /* lock the object, we must not delete global objects, so don't exchange the locking
592 process ID to zero when attempting to lock a global object... */
593 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
594 if (PrevProcId
== ProcessId
)
596 if ( (Entry
->KernelData
!= NULL
) &&
597 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) &&
598 ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == (HandleUpper
& GDI_ENTRY_BASETYPE_MASK
)) )
601 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
603 Object
= Entry
->KernelData
;
605 if ((Object
->cExclusiveLock
== 0 || Object
->Tid
== Thread
) &&
606 Object
->ulShareCount
== 0)
609 PPROCESSINFO W32Process
= PsGetCurrentProcessWin32Process();
611 /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
612 Entry
->Type
= (Entry
->Type
+ GDI_ENTRY_REUSE_INC
) & ~GDI_ENTRY_BASETYPE_MASK
;
614 /* unlock the handle slot */
615 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
617 /* push this entry to the free list */
618 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable
, Entry
));
620 Object
->hHmgr
= NULL
;
624 if (Thread
->cExclusiveLocks
< Object
->cExclusiveLock
)
626 DPRINT1("cExclusiveLocks = %ld, object: %ld\n",
627 Thread
->cExclusiveLocks
, Object
->cExclusiveLock
);
630 Thread
->cExclusiveLocks
-= Object
->cExclusiveLock
;
634 if (W32Process
!= NULL
)
636 InterlockedDecrement(&W32Process
->GDIHandleCount
);
639 /* call the cleanup routine. */
640 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(HandleType
);
641 Ret
= ObjTypeInfo
[TypeIndex
].CleanupProc(Object
);
643 DeAllocTypeDataDump(HandleType
);
645 /* Now it's time to free the memory */
646 GDIOBJ_FreeObj(Object
, TypeIndex
);
648 GDIDBG_CAPTUREDELETER(hObj
);
651 else if (Object
->ulShareCount
!= 0)
654 PEPROCESS OldProcess
;
655 Object
->BaseFlags
|= BASEFLAG_READY_TO_DIE
;
656 DPRINT("Object %p, ulShareCount = %d\n", Object
->hHmgr
, Object
->ulShareCount
);
657 /* Set NULL owner. Do the work here to avoid race conditions */
658 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
659 if (NT_SUCCESS(Status
))
661 PPROCESSINFO W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
662 if (W32Process
!= NULL
)
664 InterlockedDecrement(&W32Process
->GDIHandleCount
);
666 ObDereferenceObject(OldProcess
);
668 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
669 /* Don't wait on shared locks */
675 * The object is currently locked by another thread, so freeing is forbidden!
677 DPRINT1("Object->cExclusiveLock = %d\n", Object
->cExclusiveLock
);
678 GDIDBG_TRACECALLER();
679 GDIDBG_TRACELOCKER(hObj
);
680 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
681 /* do not assert here for it will call again from dxg.sys it being call twice */
689 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
690 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
693 else if (PrevProcId
== LockedProcessId
)
695 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
697 /* the object is currently locked, wait some time and try again.
698 FIXME - we shouldn't loop forever! Give up after some time! */
707 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
709 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj
);
711 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
713 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
717 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);
719 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry
->Type
, Entry
->KernelData
, Entry
->ProcessId
);
720 GDIDBG_TRACECALLER();
721 GDIDBG_TRACEALLOCATOR(hObj
);
730 IsObjectDead(HGDIOBJ hObject
)
732 INT Index
= GDI_HANDLE_GET_INDEX(hObject
);
733 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
734 // We check to see if the objects are knocking on deaths door.
735 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
739 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject
);
740 return TRUE
; // return true and move on.
745 * Process Environment Cached GDI Handles
747 * What types of GDI handle objects that are cached in the GDI handle buffer?
748 * Brushes set to BS_SOLID, Pens with widths of zero or set to PS_SOLID, and
749 * Regions that are set to NULLREGION or SIMPLEREGION.
753 bPEBCacheHandle(HGDIOBJ Handle
, int oType
, PVOID pAttr
)
755 PGDIHANDLECACHE GdiHandleCache
;
758 int Number
, Offset
, MaxNum
= CACHE_PEN_ENTRIES
;
761 GdiHandleCache
= (PGDIHANDLECACHE
)NtCurrentTeb()->ProcessEnvironmentBlock
->GdiHandleBuffer
;
767 MaxNum
= CACHE_BRUSH_ENTRIES
;
771 Offset
= CACHE_BRUSH_ENTRIES
;
774 case hctRegionHandle
:
775 Offset
= CACHE_BRUSH_ENTRIES
+CACHE_PEN_ENTRIES
;
782 Lock
= InterlockedCompareExchangePointer( (PVOID
*)&GdiHandleCache
->ulLock
,
785 if (Lock
) return FALSE
;
789 Number
= GdiHandleCache
->ulNumHandles
[oType
];
791 hPtr
= GdiHandleCache
->Handle
+ Offset
;
795 if ( Number
< MaxNum
)
796 { // This object is cached and waiting for it's resurrection by the users.
797 ((PRGN_ATTR
)pAttr
)->AttrFlags
|= ATTR_CACHED
;
798 hPtr
[Number
] = Handle
;
799 GdiHandleCache
->ulNumHandles
[oType
]++;
800 DPRINT("Put Handle Count %d PEB 0x%x\n", GdiHandleCache
->ulNumHandles
[oType
], NtCurrentTeb()->ProcessEnvironmentBlock
);
805 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
811 (void)InterlockedExchangePointer((PVOID
*)&GdiHandleCache
->ulLock
, Lock
);
817 * \param hObject object handle
818 * \return if the function fails the returned value is FALSE.
822 GreDeleteObject(HGDIOBJ hObject
)
825 PGDI_TABLE_ENTRY Entry
;
830 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
831 if (!IsObjectDead(hObject
))
833 dwObjectType
= GDIOBJ_GetObjectType(hObject
);
835 Index
= GDI_HANDLE_GET_INDEX(hObject
);
836 Entry
= &GdiHandleTable
->Entries
[Index
];
837 pAttr
= Entry
->UserData
;
839 switch (dwObjectType
)
841 case GDI_OBJECT_TYPE_BRUSH
:
842 ihct
= hctBrushHandle
;
845 case GDI_OBJECT_TYPE_PEN
:
849 case GDI_OBJECT_TYPE_REGION
:
850 ihct
= hctRegionHandle
;
854 switch (dwObjectType
)
856 // case GDI_OBJECT_TYPE_BRUSH:
857 // case GDI_OBJECT_TYPE_PEN:
858 case GDI_OBJECT_TYPE_REGION
:
859 /* If pAttr NULL, the probability is high for System GDI handle object. */
861 bPEBCacheHandle(hObject
, ihct
, pAttr
) )
862 { /* User space handle only! */
867 FreeObjectAttr(pAttr
);
868 Entry
->UserData
= NULL
;
872 case GDI_OBJECT_TYPE_DC
:
873 // DC_FreeDcAttr(hObject);
877 return NULL
!= hObject
878 ? GDIOBJ_FreeObjByHandle(hObject
, dwObjectType
) : FALSE
;
882 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject
);
883 return TRUE
; // return true and move on.
889 IntDeleteHandlesForProcess(struct _EPROCESS
*Process
, ULONG ObjectType
)
891 PGDI_TABLE_ENTRY Entry
, End
;
892 ULONG Index
= RESERVE_ENTRIES_COUNT
;
894 PPROCESSINFO W32Process
;
896 W32Process
= (PPROCESSINFO
)Process
->Win32Process
;
899 if (W32Process
->GDIHandleCount
> 0)
901 ProcId
= Process
->UniqueProcessId
;
903 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
904 we should delete it directly here! */
906 End
= &GdiHandleTable
->Entries
[GDI_HANDLE_COUNT
];
907 for (Entry
= &GdiHandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
911 /* ignore the lock bit */
912 if ( (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
)
914 if ( (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == ObjectType
||
915 ObjectType
== GDI_OBJECT_TYPE_DONTCARE
)
917 HGDIOBJ ObjectHandle
;
919 /* Create the object handle for the entry, the lower(!) 16 bit of the
920 Type field includes the type of the object including the stock
921 object flag - but since stock objects don't have a process id we can
922 simply ignore this fact here. */
923 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
925 if (!GDIOBJ_FreeObjByHandle(ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
))
927 DPRINT1("Failed to delete object %p!\n", ObjectHandle
);
930 if (W32Process
->GDIHandleCount
== 0)
932 /* there are no more gdi handles for this process, bail */
943 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
944 * \param Process - PID of the process that will be destroyed.
947 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
949 PEPROCESS CurrentProcess
;
950 PPROCESSINFO W32Process
;
952 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
953 CurrentProcess
= PsGetCurrentProcess();
954 if (CurrentProcess
!= Process
)
956 KeAttachProcess(&Process
->Pcb
);
959 W32Process
= (PPROCESSINFO
)CurrentProcess
->Win32Process
;
961 /* Delete objects. Begin with types that are not referenced by other types */
962 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_DC_TYPE
);
963 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BRUSH_TYPE
);
964 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BITMAP_TYPE
);
966 /* Finally finish with what's left */
967 IntDeleteHandlesForProcess(Process
, GDI_OBJECT_TYPE_DONTCARE
);
969 if (CurrentProcess
!= Process
)
975 GdiDbgHTIntegrityCheck();
978 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
979 if (W32Process
->GDIHandleCount
> 0)
981 DPRINT1("Leaking %d handles!\n", W32Process
->GDIHandleCount
);
988 * Return pointer to the object by handle.
990 * \param hObj Object handle
991 * \return Pointer to the object.
993 * \note Process can only get pointer to the objects it created or global objects.
995 * \todo Get rid of the ExpectedType parameter!
997 PGDIOBJ INTERNAL_CALL
998 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
1001 PGDI_TABLE_ENTRY Entry
;
1002 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
1004 ULONG HandleType
, HandleUpper
;
1006 /* Check for dummy call */
1010 GDIDBG_INITLOOPTRACE();
1012 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
1013 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
1014 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
1016 /* Check that the handle index is valid. */
1017 if (HandleIndex
>= GDI_HANDLE_COUNT
)
1020 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
1022 /* Check if we have the requested type */
1023 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
1024 HandleType
!= ExpectedType
) ||
1027 DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1028 hObj
, HandleType
, ExpectedType
);
1029 GDIDBG_TRACECALLER();
1030 GDIDBG_TRACEALLOCATOR(hObj
);
1031 GDIDBG_TRACEDELETER(hObj
);
1035 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
1038 * Prevent the thread from being terminated during the locking process.
1039 * It would result in undesired effects and inconsistency of the global
1043 KeEnterCriticalRegion();
1046 * Loop until we either successfully lock the handle entry & object or
1047 * fail some of the check.
1052 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
1054 /* Check for invalid owner. */
1055 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
1057 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj
, ProcessId
, HandleProcessId
);
1058 GDIDBG_TRACECALLER();
1059 GDIDBG_TRACEALLOCATOR(hObj
);
1063 /* Lock the handle table entry. */
1064 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
1065 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
1069 if (PrevProcId
== HandleProcessId
)
1072 * We're locking an object that belongs to our process or it's a
1073 * global object if HandleProcessId is 0 here.
1076 if ( (Entry
->KernelData
!= NULL
) &&
1077 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
1079 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1080 Object
= Entry
->KernelData
;
1082 if (Object
->cExclusiveLock
== 0)
1084 Object
->Tid
= Thread
;
1085 Object
->cExclusiveLock
= 1;
1086 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj
))
1088 if (Thread
) Thread
->cExclusiveLocks
++;
1093 if (Object
->Tid
!= Thread
)
1095 /* Unlock the handle table entry. */
1096 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1101 InterlockedIncrement((PLONG
)&Object
->cExclusiveLock
);
1103 if (Thread
) Thread
->cExclusiveLocks
++;
1110 * Debugging code. Report attempts to lock deleted handles and
1111 * locking type mismatches.
1113 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
1116 /* Unlock the handle table entry. */
1117 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1124 * The handle is currently locked, wait some time and try again.
1126 GDIDBG_TRACELOOP(hObj
, PrevProcId
, NULL
);
1133 KeLeaveCriticalRegion();
1140 * Return pointer to the object by handle (and allow sharing of the handle
1143 * \param hObj Object handle
1144 * \return Pointer to the object.
1146 * \note Process can only get pointer to the objects it created or global objects.
1148 * \todo Get rid of the ExpectedType parameter!
1150 PGDIOBJ INTERNAL_CALL
1151 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
1154 PGDI_TABLE_ENTRY Entry
;
1155 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
1157 ULONG_PTR HandleType
, HandleUpper
;
1159 /* Check for dummy call */
1163 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
1164 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
1165 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
1167 /* Check that the handle index is valid. */
1168 if (HandleIndex
>= GDI_HANDLE_COUNT
)
1171 /* Check if we have the requested type */
1172 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
1173 HandleType
!= ExpectedType
) ||
1176 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1177 hObj
, HandleType
, ExpectedType
);
1181 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
1183 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
1184 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
1186 /* Check for invalid owner. */
1187 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
1193 * Prevent the thread from being terminated during the locking process.
1194 * It would result in undesired effects and inconsistency of the global
1198 KeEnterCriticalRegion();
1201 * Loop until we either successfully lock the handle entry & object or
1202 * fail some of the check.
1207 /* Lock the handle table entry. */
1208 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
1209 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
1213 if (PrevProcId
== HandleProcessId
)
1216 * We're locking an object that belongs to our process or it's a
1217 * global object if HandleProcessId is 0 here.
1220 if ( (Entry
->KernelData
!= NULL
) &&
1221 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
1223 Object
= (POBJ
)Entry
->KernelData
;
1225 GDIDBG_CAPTURESHARELOCKER(HandleIndex
);
1227 if (InterlockedIncrement((PLONG
)&Object
->ulShareCount
) == 1)
1229 memset(GDIHandleLocker
[HandleIndex
], 0x00, GDI_STACK_LEVELS
* sizeof(ULONG
));
1230 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS
, (PVOID
*)GDIHandleShareLocker
[HandleIndex
], NULL
);
1233 InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
1239 * Debugging code. Report attempts to lock deleted handles and
1240 * locking type mismatches.
1242 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
1245 /* Unlock the handle table entry. */
1246 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1253 * The handle is currently locked, wait some time and try again.
1261 KeLeaveCriticalRegion();
1267 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
1269 PGDI_TABLE_ENTRY Entry
;
1273 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1275 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1277 ProcessId
= PsGetCurrentProcessId();
1279 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1280 Ret
= Entry
->KernelData
!= NULL
&&
1281 (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0 &&
1282 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1291 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1294 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1295 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1297 PGDI_TABLE_ENTRY Entry
;
1298 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1302 GDIDBG_INITLOOPTRACE();
1307 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj
);
1309 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1311 if (!GDI_HANDLE_IS_STOCKOBJ(hObj
))
1313 ProcessId
= PsGetCurrentProcessId();
1314 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1316 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
1319 /* lock the object, we must not convert stock objects, so don't check!!! */
1320 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1321 if (PrevProcId
== ProcessId
)
1323 LONG NewType
, PrevType
, OldType
;
1325 /* we're locking an object that belongs to our process. First calculate
1326 the new object type including the stock object flag and then try to
1328 /* On Windows the higher 16 bit of the type field don't contain the
1329 full type from the handle, but the base type.
1330 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1331 OldType
= ((ULONG
)hObj
& GDI_HANDLE_BASETYPE_MASK
) | ((ULONG
)hObj
>> GDI_ENTRY_UPPER_SHIFT
);
1332 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1333 we copy them as we can't get them from the handle */
1334 OldType
|= Entry
->Type
& GDI_ENTRY_FLAGS_MASK
;
1336 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1337 NewType
= OldType
| GDI_ENTRY_STOCK_MASK
;
1339 /* Try to exchange the type field - but only if the old (previous type) matches! */
1340 PrevType
= InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1341 if (PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1343 PTHREADINFO PrevThread
;
1346 /* We successfully set the stock object flag.
1347 KernelData should never be NULL here!!! */
1348 ASSERT(Entry
->KernelData
);
1350 Object
= Entry
->KernelData
;
1352 PrevThread
= Object
->Tid
;
1353 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1355 /* dereference the process' object counter */
1356 if (PrevProcId
!= GDI_GLOBAL_PROCESS
)
1358 PEPROCESS OldProcess
;
1359 PPROCESSINFO W32Process
;
1363 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1364 if (NT_SUCCESS(Status
))
1366 W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
1367 if (W32Process
!= NULL
)
1369 InterlockedDecrement(&W32Process
->GDIHandleCount
);
1371 ObDereferenceObject(OldProcess
);
1375 hObj
= (HGDIOBJ
)((ULONG
)(hObj
) | GDI_HANDLE_STOCK_MASK
);
1377 Object
->hHmgr
= hObj
;
1379 /* remove the process id lock and make it global */
1380 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1382 /* we're done, successfully converted the object */
1387 GDIDBG_TRACELOOP(hObj
, PrevThread
, Thread
);
1389 /* WTF?! The object is already locked by a different thread!
1390 Release the lock, wait a bit and try again!
1391 FIXME - we should give up after some time unless we want to wait forever! */
1392 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1400 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1401 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType
, Entry
->Type
, NewType
, Entry
->KernelData
);
1404 else if (PrevProcId
== LockedProcessId
)
1406 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
1408 /* the object is currently locked, wait some time and try again.
1409 FIXME - we shouldn't loop forever! Give up after some time! */
1416 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1424 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1426 PGDI_TABLE_ENTRY Entry
;
1427 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1431 GDIDBG_INITLOOPTRACE();
1433 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1435 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1437 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1439 ProcessId
= PsGetCurrentProcessId();
1440 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1442 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1445 /* lock the object, we must not convert stock objects, so don't check!!! */
1446 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1447 if (PrevProcId
== ProcessId
)
1449 PTHREADINFO PrevThread
;
1451 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1453 POBJ Object
= Entry
->KernelData
;
1455 PrevThread
= Object
->Tid
;
1456 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1458 PEPROCESS OldProcess
;
1459 PPROCESSINFO W32Process
;
1462 if (NewOwner
!= NULL
)
1464 ProcessId
= PsGetProcessId(NewOwner
);
1469 if((ULONG_PTR
)ProcessId
== ((ULONG_PTR
)PrevProcId
& ~0x1))
1471 DPRINT("Setting same process than previous one, nothing to do\n");
1475 /* dereference the process' object counter */
1477 if ((ULONG_PTR
)PrevProcId
& ~0x1)
1479 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1480 if (NT_SUCCESS(Status
))
1482 W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
1483 if (W32Process
!= NULL
)
1485 InterlockedDecrement(&W32Process
->GDIHandleCount
);
1487 ObDereferenceObject(OldProcess
);
1491 if (NewOwner
!= NULL
)
1493 /* Increase the new process' object counter */
1494 W32Process
= (PPROCESSINFO
)NewOwner
->Win32Process
;
1495 if (W32Process
!= NULL
)
1497 InterlockedIncrement(&W32Process
->GDIHandleCount
);
1502 /* remove the process id lock and change it to the new process id */
1503 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
);
1510 GDIDBG_TRACELOOP(ObjectHandle
, PrevThread
, Thread
);
1512 /* WTF?! The object is already locked by a different thread!
1513 Release the lock, wait a bit and try again! DO reset the pid lock
1514 so we make sure we don't access invalid memory in case the object is
1515 being deleted in the meantime (because we don't have aquired a reference
1517 FIXME - we should give up after some time unless we want to wait forever! */
1518 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1526 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1527 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry
->Type
, Entry
->KernelData
);
1531 else if (PrevProcId
== LockedProcessId
)
1533 GDIDBG_TRACELOOP(ObjectHandle
, PrevProcId
, ProcessId
);
1535 /* the object is currently locked, wait some time and try again.
1536 FIXME - we shouldn't loop forever! Give up after some time! */
1541 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1543 /* allow changing ownership of global objects */
1545 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1548 else if ((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1550 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1555 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1563 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1565 PGDI_TABLE_ENTRY FromEntry
;
1567 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1570 GDIDBG_INITLOOPTRACE();
1572 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1574 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1576 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1578 FromEntry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, CopyFrom
);
1580 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1581 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1584 /* lock the object, we must not convert stock objects, so don't check!!! */
1585 FromPrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1586 if (FromPrevProcId
== FromProcessId
)
1588 PTHREADINFO PrevThread
;
1591 if ((FromEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1593 Object
= FromEntry
->KernelData
;
1595 /* save the pointer to the calling thread so we know it was this thread
1596 that locked the object */
1597 PrevThread
= Object
->Tid
;
1598 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1600 /* now let's change the ownership of the target object */
1602 if (((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1604 PEPROCESS ProcessTo
;
1606 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1608 GDIOBJ_SetOwnership(CopyTo
, ProcessTo
);
1609 ObDereferenceObject(ProcessTo
);
1614 /* mark the object as global */
1615 GDIOBJ_SetOwnership(CopyTo
, NULL
);
1618 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1622 GDIDBG_TRACELOOP(CopyFrom
, PrevThread
, Thread
);
1624 /* WTF?! The object is already locked by a different thread!
1625 Release the lock, wait a bit and try again! DO reset the pid lock
1626 so we make sure we don't access invalid memory in case the object is
1627 being deleted in the meantime (because we don't have aquired a reference
1629 FIXME - we should give up after some time unless we want to wait forever! */
1630 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1633 goto LockHandleFrom
;
1638 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1642 else if (FromPrevProcId
== FromLockedProcessId
)
1644 GDIDBG_TRACELOOP(CopyFrom
, FromPrevProcId
, FromProcessId
);
1646 /* the object is currently locked, wait some time and try again.
1647 FIXME - we shouldn't loop forever! Give up after some time! */
1650 goto LockHandleFrom
;
1652 else if ((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1654 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1655 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1656 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1657 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1658 goto LockHandleFrom
;
1662 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1670 GDI_MapHandleTable(PEPROCESS Process
)
1672 PVOID MappedView
= NULL
;
1674 LARGE_INTEGER Offset
;
1675 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1677 Offset
.QuadPart
= 0;
1679 ASSERT(GdiTableSection
!= NULL
);
1680 ASSERT(Process
!= NULL
);
1682 Status
= MmMapViewOfSection(GdiTableSection
,
1693 if (!NT_SUCCESS(Status
))
1699 /* Locks 2 or 3 objects at a time */
1702 GDIOBJ_LockMultipleObjs(ULONG ulCount
,
1706 UINT auiIndices
[3] = {0,1,2};
1708 BOOL bUnsorted
= TRUE
;
1710 /* First is greatest */
1714 for(i
=1; i
<ulCount
; i
++)
1716 if((ULONG_PTR
)ahObj
[auiIndices
[i
-1]] < (ULONG_PTR
)ahObj
[auiIndices
[i
]])
1718 tmp
= auiIndices
[i
-1];
1719 auiIndices
[i
-1] = auiIndices
[i
];
1720 auiIndices
[i
] = tmp
;
1726 for(i
=0;i
<ulCount
;i
++)
1727 apObj
[auiIndices
[i
]] = GDIOBJ_LockObj(ahObj
[auiIndices
[i
]], GDI_OBJECT_TYPE_DONTCARE
);
1731 /** PUBLIC FUNCTIONS **********************************************************/
1735 GreGetObjectOwner(HGDIOBJ Handle
, GDIOBJTYPE ObjType
)
1737 INT Ret
= GDI_OBJ_HMGR_RESTRICTED
;
1739 if ( GDI_HANDLE_GET_INDEX(Handle
) < GDI_HANDLE_COUNT
)
1741 PGDI_TABLE_ENTRY pEntry
= &GdiHandleTable
->Entries
[GDI_HANDLE_GET_INDEX(Handle
)];
1743 if (pEntry
->ObjectType
== ObjType
)
1745 if (pEntry
->FullUnique
== (GDI_HANDLE_GET_UPPER(Handle
) >> GDI_ENTRY_UPPER_SHIFT
))
1746 Ret
= pEntry
->ProcessId
& ~1;
1755 NtGdiCreateClientObj(
1762 /* Mask out everything that would change the type in a wrong manner */
1763 ulType
&= (GDI_HANDLE_TYPE_MASK
& ~GDI_HANDLE_BASETYPE_MASK
);
1765 /* Allocate a new object */
1766 pObject
= GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ
| ulType
);
1772 /* get the handle */
1773 handle
= pObject
->hHmgr
;
1776 GDIOBJ_UnlockObjByPtr(pObject
);
1784 NtGdiDeleteClientObj(
1788 /* We first need to get the real type from the handle */
1789 ULONG type
= GDI_HANDLE_GET_TYPE(h
);
1791 /* Check if it's really a CLIENTOBJ */
1792 if ((type
& GDI_HANDLE_BASETYPE_MASK
) != GDILoObjType_LO_CLIENTOBJ_TYPE
)
1794 /* FIXME: SetLastError? */
1797 return GDIOBJ_FreeObjByHandle(h
, type
);
1802 IntGdiGetObject(IN HANDLE Handle
,
1810 pGdiObject
= GDIOBJ_LockObj(Handle
, GDI_OBJECT_TYPE_DONTCARE
);
1813 EngSetLastError(ERROR_INVALID_HANDLE
);
1817 dwObjectType
= GDIOBJ_GetObjectType(Handle
);
1818 switch (dwObjectType
)
1820 case GDI_OBJECT_TYPE_PEN
:
1821 case GDI_OBJECT_TYPE_EXTPEN
:
1822 Result
= PEN_GetObject((PBRUSH
) pGdiObject
, cbCount
, (PLOGPEN
) lpBuffer
); // IntGdiCreatePenIndirect
1825 case GDI_OBJECT_TYPE_BRUSH
:
1826 Result
= BRUSH_GetObject((PBRUSH
) pGdiObject
, cbCount
, (LPLOGBRUSH
)lpBuffer
);
1829 case GDI_OBJECT_TYPE_BITMAP
:
1830 Result
= BITMAP_GetObject((SURFACE
*) pGdiObject
, cbCount
, lpBuffer
);
1832 case GDI_OBJECT_TYPE_FONT
:
1833 Result
= FontGetObject((PTEXTOBJ
) pGdiObject
, cbCount
, lpBuffer
);
1835 // Fix the LOGFONT structure for the stock fonts
1836 if (FIRST_STOCK_HANDLE
<= Handle
&& Handle
<= LAST_STOCK_HANDLE
)
1838 FixStockFontSizeW(Handle
, cbCount
, lpBuffer
);
1843 case GDI_OBJECT_TYPE_PALETTE
:
1844 Result
= PALETTE_GetObject((PPALETTE
) pGdiObject
, cbCount
, lpBuffer
);
1848 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType
);
1852 GDIOBJ_UnlockObjByPtr(pGdiObject
);
1862 NtGdiExtGetObjectW(IN HANDLE hGdiObj
,
1864 OUT LPVOID lpBuffer
)
1871 DIBSECTION dibsection
;
1875 EXTLOGFONTW extlogfontw
;
1876 ENUMLOGFONTEXDVW enumlogfontexdvw
;
1879 // Normalize to the largest supported object size
1880 cbCount
= min((UINT
)cbCount
, sizeof(Object
));
1882 // Now do the actual call
1883 iRetCount
= IntGdiGetObject(hGdiObj
, cbCount
, lpBuffer
? &Object
: NULL
);
1884 cbCopyCount
= min((UINT
)cbCount
, (UINT
)iRetCount
);
1886 // Make sure we have a buffer and a copy size
1887 if ((cbCopyCount
) && (lpBuffer
))
1889 // Enter SEH for buffer transfer
1892 // Probe the buffer and copy it
1893 ProbeForWrite(lpBuffer
, cbCopyCount
, sizeof(WORD
));
1894 RtlCopyMemory(lpBuffer
, &Object
, cbCopyCount
);
1896 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1898 // Clear the return value.
1899 // Do *NOT* set last error here!