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 GDI_ENTRY_TO_INDEX(ht, e) \
16 (((ULONG_PTR)(e) - (ULONG_PTR)&((ht)->Entries[0])) / sizeof(GDI_TABLE_ENTRY))
17 #define GDI_HANDLE_GET_ENTRY(HandleTable, h) \
18 (&(HandleTable)->Entries[GDI_HANDLE_GET_INDEX((h))])
20 #define BASE_OBJTYPE_COUNT 32
22 #define DelayExecution() \
23 DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
24 KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
27 BOOL INTERNAL_CALL
GDI_CleanupDummy(PVOID ObjectBody
);
29 /** GLOBALS *******************************************************************/
36 GDICLEANUPPROC CleanupProc
;
37 } OBJ_TYPE_INFO
, *POBJ_TYPE_INFO
;
40 OBJ_TYPE_INFO ObjTypeInfo
[BASE_OBJTYPE_COUNT
] =
42 {0, 0, 0, NULL
}, /* 00 reserved entry */
43 {1, sizeof(DC
), TAG_DC
, DC_Cleanup
}, /* 01 DC */
44 {1, 0, 0, NULL
}, /* 02 UNUSED1 */
45 {1, 0, 0, NULL
}, /* 03 UNUSED2 */
46 {1, sizeof(ROSRGNDATA
), TAG_REGION
, REGION_Cleanup
}, /* 04 RGN */
47 {1, sizeof(SURFACE
), TAG_SURFACE
, SURFACE_Cleanup
}, /* 05 SURFACE */
48 {1, sizeof(CLIENTOBJ
), TAG_CLIENTOBJ
, GDI_CleanupDummy
}, /* 06 CLIENTOBJ: METADC,... */
49 {1, sizeof(PATH
), TAG_PATH
, GDI_CleanupDummy
}, /* 07 PATH */
50 {1, sizeof(PALETTE
), TAG_PALETTE
, PALETTE_Cleanup
}, /* 08 PAL */
51 {1, sizeof(COLORSPACE
), TAG_ICMLCS
, GDI_CleanupDummy
}, /* 09 ICMLCS, */
52 {1, sizeof(TEXTOBJ
), TAG_LFONT
, GDI_CleanupDummy
}, /* 0a LFONT */
53 {0, 0, TAG_RFONT
, NULL
}, /* 0b RFONT, unused */
54 {0, 0, TAG_PFE
, NULL
}, /* 0c PFE, unused */
55 {0, 0, TAG_PFT
, NULL
}, /* 0d PFT, unused */
56 {0, sizeof(GDICLRXFORM
), TAG_ICMCXF
, GDI_CleanupDummy
}, /* 0e ICMCXF, */
57 {0, 0, TAG_SPRITE
, NULL
}, /* 0f SPRITE, unused */
58 {1, sizeof(BRUSH
), TAG_BRUSH
, BRUSH_Cleanup
}, /* 10 BRUSH, PEN, EXTPEN */
59 {0, 0, TAG_UMPD
, NULL
}, /* 11 UMPD, unused */
60 {0, 0, 0, NULL
}, /* 12 UNUSED4 */
61 {0, 0, TAG_SPACE
, NULL
}, /* 13 SPACE, unused */
62 {0, 0, 0, NULL
}, /* 14 UNUSED5 */
63 {0, 0, TAG_META
, NULL
}, /* 15 META, unused */
64 {0, 0, TAG_EFSTATE
, NULL
}, /* 16 EFSTATE, unused */
65 {0, 0, TAG_BMFD
, NULL
}, /* 17 BMFD, unused */
66 {0, 0, TAG_VTFD
, NULL
}, /* 18 VTFD, unused */
67 {0, 0, TAG_TTFD
, NULL
}, /* 19 TTFD, unused */
68 {0, 0, TAG_RC
, NULL
}, /* 1a RC, unused */
69 {0, 0, TAG_TEMP
, NULL
}, /* 1b TEMP, unused */
70 {0, sizeof(EDRIVEROBJ
), TAG_DRVOBJ
, DRIVEROBJ_Cleanup
},/* 1c DRVOBJ */
71 {0, 0, TAG_DCIOBJ
, NULL
}, /* 1d DCIOBJ, unused */
72 {0, 0, TAG_SPOOL
, NULL
}, /* 1e SPOOL, unused */
73 {0, 0, 0, NULL
}, /* 1f reserved entry */
76 static LARGE_INTEGER ShortDelay
;
77 PGDI_HANDLE_TABLE GdiHandleTable
= NULL
;
78 PSECTION_OBJECT GdiTableSection
= NULL
;
80 /** INTERNAL FUNCTIONS ********************************************************/
90 AllocTypeDataDump(INT TypeInfo
)
92 switch( TypeInfo
& GDI_HANDLE_TYPE_MASK
)
94 case GDILoObjType_LO_BRUSH_TYPE
:
97 case GDILoObjType_LO_DC_TYPE
:
100 case GDILoObjType_LO_BITMAP_TYPE
:
103 case GDILoObjType_LO_FONT_TYPE
:
106 case GDILoObjType_LO_REGION_TYPE
:
113 DeAllocTypeDataDump(INT TypeInfo
)
115 switch( TypeInfo
& GDI_HANDLE_TYPE_MASK
)
117 case GDILoObjType_LO_BRUSH_TYPE
:
120 case GDILoObjType_LO_DC_TYPE
:
123 case GDILoObjType_LO_BITMAP_TYPE
:
126 case GDILoObjType_LO_FONT_TYPE
:
129 case GDILoObjType_LO_REGION_TYPE
:
136 * Dummy GDI Cleanup Callback
140 GDI_CleanupDummy(PVOID ObjectBody
)
146 * Allocate GDI object table.
147 * \param Size - number of entries in the object table.
152 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT
*SectionObject
)
154 PGDI_HANDLE_TABLE HandleTable
= NULL
;
155 LARGE_INTEGER htSize
;
160 ASSERT(SectionObject
!= NULL
);
162 htSize
.QuadPart
= sizeof(GDI_HANDLE_TABLE
);
164 Status
= MmCreateSection((PVOID
*)SectionObject
,
172 if (!NT_SUCCESS(Status
))
175 /* FIXME - use MmMapViewInSessionSpace once available! */
176 Status
= MmMapViewInSystemSpace(*SectionObject
,
177 (PVOID
*)&HandleTable
,
179 if (!NT_SUCCESS(Status
))
181 ObDereferenceObject(*SectionObject
);
182 *SectionObject
= NULL
;
186 RtlZeroMemory(HandleTable
, sizeof(GDI_HANDLE_TABLE
));
188 HandleTable
->LookasideLists
= ExAllocatePoolWithTag(NonPagedPool
,
189 BASE_OBJTYPE_COUNT
* sizeof(PAGED_LOOKASIDE_LIST
),
191 if (HandleTable
->LookasideLists
== NULL
)
193 MmUnmapViewInSystemSpace(HandleTable
);
194 ObDereferenceObject(*SectionObject
);
195 *SectionObject
= NULL
;
199 for (ObjType
= 0; ObjType
< BASE_OBJTYPE_COUNT
; ObjType
++)
201 if (ObjTypeInfo
[ObjType
].bUseLookaside
)
203 ExInitializePagedLookasideList(HandleTable
->LookasideLists
+ ObjType
,
207 ObjTypeInfo
[ObjType
].ulBodySize
,
208 ObjTypeInfo
[ObjType
].Tag
,
213 ShortDelay
.QuadPart
= -5000LL; /* FIXME - 0.5 ms? */
215 HandleTable
->FirstFree
= 0;
216 HandleTable
->FirstUnused
= RESERVE_ENTRIES_COUNT
;
226 /* Create the GDI handle table */
227 GdiHandleTable
= GDIOBJ_iAllocHandleTable(&GdiTableSection
);
228 if (GdiHandleTable
== NULL
)
230 DPRINT1("Failed to initialize the GDI handle table.\n");
231 return STATUS_UNSUCCESSFUL
;
234 return STATUS_SUCCESS
;
239 LockErrorDebugOutput(HGDIOBJ hObj
, PGDI_TABLE_ENTRY Entry
, LPSTR Function
)
241 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
243 DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function
, hObj
);
244 GDIDBG_TRACEDELETER(hObj
);
246 else if (GDI_HANDLE_GET_REUSECNT(hObj
) != GDI_ENTRY_GET_REUSECNT(Entry
->Type
))
248 DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
249 Function
, hObj
, GDI_HANDLE_GET_REUSECNT(hObj
), GDI_ENTRY_GET_REUSECNT(Entry
->Type
));
251 else if (GDI_HANDLE_GET_TYPE(hObj
) != ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
))
253 DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
254 Function
, hObj
, GDI_HANDLE_GET_TYPE(hObj
), (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
);
258 DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
259 Function
, hObj
, Entry
->Type
);
261 GDIDBG_TRACECALLER();
266 InterlockedPopFreeEntry(VOID
)
268 ULONG iFirst
, iNext
, iPrev
;
269 PGDI_TABLE_ENTRY pEntry
;
271 DPRINT("Enter InterLockedPopFreeEntry\n");
275 /* Get the index and sequence number of the first free entry */
276 iFirst
= GdiHandleTable
->FirstFree
;
278 /* Check if we have a free entry */
279 if (!(iFirst
& GDI_HANDLE_INDEX_MASK
))
281 /* Increment FirstUnused and get the new index */
282 iFirst
= InterlockedIncrement((LONG
*)&GdiHandleTable
->FirstUnused
) - 1;
284 /* Check if we have unused entries left */
285 if (iFirst
>= GDI_HANDLE_COUNT
)
287 DPRINT1("No more gdi handles left!\n");
291 /* Return the old index */
295 /* Get a pointer to the first free entry */
296 pEntry
= GdiHandleTable
->Entries
+ (iFirst
& GDI_HANDLE_INDEX_MASK
);
298 /* Create a new value with an increased sequence number */
299 iNext
= (USHORT
)(ULONG_PTR
)pEntry
->KernelData
;
300 iNext
|= (iFirst
& ~GDI_HANDLE_INDEX_MASK
) + 0x10000;
302 /* Try to exchange the FirstFree value */
303 iPrev
= InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
,
307 while (iPrev
!= iFirst
);
309 /* Sanity check: is entry really free? */
310 ASSERT(((ULONG_PTR
)pEntry
->KernelData
& ~GDI_HANDLE_INDEX_MASK
) == 0);
312 return iFirst
& GDI_HANDLE_INDEX_MASK
;
315 /* Pushes an entry of the handle table to the free list,
316 The entry must be unlocked and the base type field must be 0 */
319 InterlockedPushFreeEntry(ULONG idxToFree
)
321 ULONG iToFree
, iFirst
, iPrev
;
322 PGDI_TABLE_ENTRY pFreeEntry
;
324 DPRINT("Enter InterlockedPushFreeEntry\n");
326 pFreeEntry
= GdiHandleTable
->Entries
+ idxToFree
;
327 ASSERT((pFreeEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0);
328 ASSERT(pFreeEntry
->ProcessId
== 0);
329 pFreeEntry
->UserData
= NULL
; // FIXME
330 ASSERT(pFreeEntry
->UserData
== NULL
);
334 /* Get the current first free index and sequence number */
335 iFirst
= GdiHandleTable
->FirstFree
;
337 /* Set the KernelData member to the index of the first free entry */
338 pFreeEntry
->KernelData
= UlongToPtr(iFirst
& GDI_HANDLE_INDEX_MASK
);
340 /* Combine new index and increased sequence number in iToFree */
341 iToFree
= idxToFree
| ((iFirst
& ~GDI_HANDLE_INDEX_MASK
) + 0x10000);
343 /* Try to atomically update the first free entry */
344 iPrev
= InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
,
348 while (iPrev
!= iFirst
);
354 GDIOBJ_ValidateHandle(HGDIOBJ hObj
, ULONG ObjectType
)
356 PGDI_TABLE_ENTRY Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
357 if ((((ULONG_PTR
)hObj
& GDI_HANDLE_TYPE_MASK
) == ObjectType
) &&
358 (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == GDI_HANDLE_GET_UPPER(hObj
))
360 HANDLE pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
361 if (pid
== NULL
|| pid
== PsGetCurrentProcessId())
370 GDIOBJ_AllocObj(UCHAR BaseType
)
374 ASSERT((BaseType
& ~GDIObjTypeTotal
) == 0);
375 // BaseType &= GDI_HANDLE_BASETYPE_MASK;
377 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
379 PPAGED_LOOKASIDE_LIST LookasideList
;
381 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
382 pObject
= ExAllocateFromPagedLookasideList(LookasideList
);
386 pObject
= ExAllocatePoolWithTag(PagedPool
,
387 ObjTypeInfo
[BaseType
].ulBodySize
,
388 ObjTypeInfo
[BaseType
].Tag
);
393 RtlZeroMemory(pObject
, ObjTypeInfo
[BaseType
].ulBodySize
);
401 * Allocate memory for GDI object and return handle to it.
403 * \param ObjectType - type of object \ref GDI object types
405 * \return Pointer to the allocated object, which is locked.
408 GDIOBJ_AllocObjWithHandle(ULONG ObjectType
)
410 PPROCESSINFO W32Process
;
411 POBJ newObject
= NULL
;
412 HANDLE CurrentProcessId
, LockedProcessId
;
415 PGDI_TABLE_ENTRY Entry
;
418 GDIDBG_INITLOOPTRACE();
420 W32Process
= PsGetCurrentProcessWin32Process();
421 /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
422 to take too many GDI objects, itself. */
423 if (W32Process
&& W32Process
->GDIHandleCount
>= 0x2710)
425 DPRINT1("Too many objects for process!!!\n");
426 DPRINT1("DC %d BRUSH %d BITMAP %d FONT %d RGN %d\n",tDC
,tBRUSH
,tBITMAP
,tFONT
,tRGN
);
427 GDIDBG_DUMPHANDLETABLE();
431 ASSERT(ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
);
433 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(ObjectType
);
435 newObject
= GDIOBJ_AllocObj(TypeIndex
);
438 DPRINT1("Not enough memory to allocate gdi object!\n");
442 CurrentProcessId
= PsGetCurrentProcessId();
443 LockedProcessId
= (HANDLE
)((ULONG_PTR
)CurrentProcessId
| 0x1);
445 // RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
447 /* On Windows the higher 16 bit of the type field don't contain the
448 full type from the handle, but the base type.
449 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
450 TypeInfo
= (ObjectType
& GDI_HANDLE_BASETYPE_MASK
) | (ObjectType
>> GDI_ENTRY_UPPER_SHIFT
);
452 Index
= InterlockedPopFreeEntry();
457 Entry
= &GdiHandleTable
->Entries
[Index
];
460 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, 0);
461 if (PrevProcId
== NULL
)
463 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
466 Entry
->KernelData
= newObject
;
468 /* copy the reuse-counter */
469 TypeInfo
|= Entry
->Type
& GDI_ENTRY_REUSE_MASK
;
471 /* we found a free entry, no need to exchange this field atomically
472 since we're holding the lock */
473 Entry
->Type
= TypeInfo
;
475 /* Create a handle */
476 Handle
= (HGDIOBJ
)((Index
& 0xFFFF) | (TypeInfo
<< GDI_ENTRY_UPPER_SHIFT
));
478 /* Initialize BaseObject fields */
479 newObject
->hHmgr
= Handle
;
480 newObject
->ulShareCount
= 0;
481 newObject
->cExclusiveLock
= 1;
482 newObject
->Tid
= Thread
;
484 if (Thread
) Thread
->cExclusiveLocks
++;
487 AllocTypeDataDump(TypeInfo
);
489 /* unlock the entry */
490 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, CurrentProcessId
);
492 GDIDBG_CAPTUREALLOCATOR(Index
);
494 if (W32Process
!= NULL
)
496 InterlockedIncrement(&W32Process
->GDIHandleCount
);
499 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle
, newObject
);
504 GDIDBG_TRACELOOP(Index
, PrevProcId
, CurrentProcessId
);
505 /* damn, someone is trying to lock the object even though it doesn't
506 even exist anymore, wait a little and try again!
507 FIXME - we shouldn't loop forever! Give up after some time! */
514 GDIOBJ_FreeObj(newObject
, TypeIndex
);
516 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
517 GDIDBG_DUMPHANDLETABLE();
524 GDIOBJ_FreeObj(POBJ pObject
, UCHAR BaseType
)
526 /* Object must not have a handle! */
527 ASSERT(pObject
->hHmgr
== NULL
);
529 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
531 PPAGED_LOOKASIDE_LIST LookasideList
;
533 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
534 ExFreeToPagedLookasideList(LookasideList
, pObject
);
543 * Free memory allocated for the GDI object. For each object type this function calls the
544 * appropriate cleanup routine.
546 * \param hObj - handle of the object to be deleted.
548 * \return Returns TRUE if succesful.
549 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
550 * to the calling process.
552 * \bug This function should return VOID and kill the object no matter what...
555 GDIOBJ_FreeObjByHandle(HGDIOBJ hObj
, DWORD ExpectedType
)
557 PGDI_TABLE_ENTRY Entry
;
558 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
559 ULONG HandleType
, HandleUpper
, TypeIndex
;
562 GDIDBG_INITLOOPTRACE();
564 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj
);
566 if (GDI_HANDLE_IS_STOCKOBJ(hObj
))
568 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj
);
569 GDIDBG_TRACECALLER();
573 ProcessId
= PsGetCurrentProcessId();
574 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
576 Silent
= (ExpectedType
& GDI_OBJECT_TYPE_SILENT
);
577 ExpectedType
&= ~GDI_OBJECT_TYPE_SILENT
;
579 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
580 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
582 /* Check if we have the requested type */
583 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
584 HandleType
!= ExpectedType
) ||
587 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
588 hObj
, HandleType
, ExpectedType
);
589 GDIDBG_TRACECALLER();
593 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
596 /* lock the object, we must not delete global objects, so don't exchange the locking
597 process ID to zero when attempting to lock a global object... */
598 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
599 if (PrevProcId
== ProcessId
)
601 if ( (Entry
->KernelData
!= NULL
) &&
602 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) &&
603 ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == (HandleUpper
& GDI_ENTRY_BASETYPE_MASK
)) )
606 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
608 Object
= Entry
->KernelData
;
610 if ((Object
->cExclusiveLock
== 0 || Object
->Tid
== Thread
) &&
611 Object
->ulShareCount
== 0)
614 PPROCESSINFO W32Process
= PsGetCurrentProcessWin32Process();
616 /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
617 Entry
->Type
= (Entry
->Type
+ GDI_ENTRY_REUSE_INC
) & ~GDI_ENTRY_BASETYPE_MASK
;
619 /* unlock the handle slot */
620 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
622 /* push this entry to the free list */
623 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable
, Entry
));
625 Object
->hHmgr
= NULL
;
629 if (Thread
->cExclusiveLocks
< Object
->cExclusiveLock
)
631 DPRINT1("cExclusiveLocks = %ld, object: %ld\n",
632 Thread
->cExclusiveLocks
, Object
->cExclusiveLock
);
635 Thread
->cExclusiveLocks
-= Object
->cExclusiveLock
;
639 if (W32Process
!= NULL
)
641 InterlockedDecrement(&W32Process
->GDIHandleCount
);
644 /* call the cleanup routine. */
645 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(HandleType
);
646 Ret
= ObjTypeInfo
[TypeIndex
].CleanupProc(Object
);
648 DeAllocTypeDataDump(HandleType
);
650 /* Now it's time to free the memory */
651 GDIOBJ_FreeObj(Object
, TypeIndex
);
653 GDIDBG_CAPTUREDELETER(hObj
);
656 else if (Object
->ulShareCount
!= 0)
659 PEPROCESS OldProcess
;
660 Object
->BaseFlags
|= BASEFLAG_READY_TO_DIE
;
661 DPRINT("Object %p, ulShareCount = %d\n", Object
->hHmgr
, Object
->ulShareCount
);
662 /* Set NULL owner. Do the work here to avoid race conditions */
663 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
664 if (NT_SUCCESS(Status
))
666 PPROCESSINFO W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
667 if (W32Process
!= NULL
)
669 InterlockedDecrement(&W32Process
->GDIHandleCount
);
671 ObDereferenceObject(OldProcess
);
673 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
674 /* Don't wait on shared locks */
680 * The object is currently locked by another thread, so freeing is forbidden!
682 DPRINT1("Object->cExclusiveLock = %d\n", Object
->cExclusiveLock
);
683 GDIDBG_TRACECALLER();
684 GDIDBG_TRACELOCKER(hObj
);
685 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
686 /* do not assert here for it will call again from dxg.sys it being call twice */
694 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
695 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
698 else if (PrevProcId
== LockedProcessId
)
700 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
702 /* the object is currently locked, wait some time and try again.
703 FIXME - we shouldn't loop forever! Give up after some time! */
712 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
714 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj
);
716 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
718 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
722 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);
724 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry
->Type
, Entry
->KernelData
, Entry
->ProcessId
);
725 GDIDBG_TRACECALLER();
726 GDIDBG_TRACEALLOCATOR(hObj
);
735 IsObjectDead(HGDIOBJ hObject
)
737 INT Index
= GDI_HANDLE_GET_INDEX(hObject
);
738 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
739 // We check to see if the objects are knocking on deaths door.
740 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
744 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject
);
745 return TRUE
; // return true and move on.
752 bPEBCacheHandle(HGDIOBJ Handle
, int oType
, PVOID pAttr
)
754 PGDIHANDLECACHE GdiHandleCache
;
757 int Offset
= 0, Number
;
760 GdiHandleCache
= (PGDIHANDLECACHE
)NtCurrentTeb()->ProcessEnvironmentBlock
->GdiHandleBuffer
;
769 Offset
= CACHE_BRUSH_ENTRIES
;
772 case hctRegionHandle
:
773 Offset
= CACHE_BRUSH_ENTRIES
+CACHE_PEN_ENTRIES
;
780 Lock
= InterlockedCompareExchangePointer( (PVOID
*)&GdiHandleCache
->ulLock
,
783 if (Lock
) return FALSE
;
787 Number
= GdiHandleCache
->ulNumHandles
[oType
];
789 hPtr
= GdiHandleCache
->Handle
+ Offset
;
791 if ( pAttr
&& oType
== hctRegionHandle
)
793 if ( Number
< CACHE_REGION_ENTRIES
)
795 ((PRGN_ATTR
)pAttr
)->AttrFlags
|= ATTR_CACHED
;
796 hPtr
[Number
] = Handle
;
797 GdiHandleCache
->ulNumHandles
[oType
]++;
798 DPRINT("Put Handle Count %d PEB 0x%x\n", GdiHandleCache
->ulNumHandles
[oType
], NtCurrentTeb()->ProcessEnvironmentBlock
);
803 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
809 (void)InterlockedExchangePointer((PVOID
*)&GdiHandleCache
->ulLock
, Lock
);
815 * \param hObject object handle
816 * \return if the function fails the returned value is FALSE.
820 GreDeleteObject(HGDIOBJ hObject
)
823 PGDI_TABLE_ENTRY Entry
;
827 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
828 if (!IsObjectDead(hObject
))
830 dwObjectType
= GDIOBJ_GetObjectType(hObject
);
832 Index
= GDI_HANDLE_GET_INDEX(hObject
);
833 Entry
= &GdiHandleTable
->Entries
[Index
];
834 pAttr
= Entry
->UserData
;
836 switch (dwObjectType
)
838 case GDI_OBJECT_TYPE_BRUSH
:
841 case GDI_OBJECT_TYPE_REGION
:
842 /* If pAttr NULL, the probability is high for System Region. */
844 bPEBCacheHandle(hObject
, hctRegionHandle
, pAttr
))
846 /* User space handle only! */
851 FreeObjectAttr(pAttr
);
852 Entry
->UserData
= NULL
;
856 case GDI_OBJECT_TYPE_DC
:
857 // DC_FreeDcAttr(hObject);
861 return NULL
!= hObject
862 ? GDIOBJ_FreeObjByHandle(hObject
, dwObjectType
) : FALSE
;
866 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject
);
867 return TRUE
; // return true and move on.
873 IntDeleteHandlesForProcess(struct _EPROCESS
*Process
, ULONG ObjectType
)
875 PGDI_TABLE_ENTRY Entry
, End
;
876 ULONG Index
= RESERVE_ENTRIES_COUNT
;
878 PPROCESSINFO W32Process
;
880 W32Process
= (PPROCESSINFO
)Process
->Win32Process
;
883 if (W32Process
->GDIHandleCount
> 0)
885 ProcId
= Process
->UniqueProcessId
;
887 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
888 we should delete it directly here! */
890 End
= &GdiHandleTable
->Entries
[GDI_HANDLE_COUNT
];
891 for (Entry
= &GdiHandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
895 /* ignore the lock bit */
896 if ( (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
)
898 if ( (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == ObjectType
||
899 ObjectType
== GDI_OBJECT_TYPE_DONTCARE
)
901 HGDIOBJ ObjectHandle
;
903 /* Create the object handle for the entry, the lower(!) 16 bit of the
904 Type field includes the type of the object including the stock
905 object flag - but since stock objects don't have a process id we can
906 simply ignore this fact here. */
907 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
909 if (!GDIOBJ_FreeObjByHandle(ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
))
911 DPRINT1("Failed to delete object %p!\n", ObjectHandle
);
914 if (W32Process
->GDIHandleCount
== 0)
916 /* there are no more gdi handles for this process, bail */
927 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
928 * \param Process - PID of the process that will be destroyed.
931 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
933 PEPROCESS CurrentProcess
;
934 PPROCESSINFO W32Process
;
936 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
937 CurrentProcess
= PsGetCurrentProcess();
938 if (CurrentProcess
!= Process
)
940 KeAttachProcess(&Process
->Pcb
);
943 W32Process
= (PPROCESSINFO
)CurrentProcess
->Win32Process
;
945 /* Delete objects. Begin with types that are not referenced by other types */
946 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_DC_TYPE
);
947 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BRUSH_TYPE
);
948 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BITMAP_TYPE
);
950 /* Finally finish with what's left */
951 IntDeleteHandlesForProcess(Process
, GDI_OBJECT_TYPE_DONTCARE
);
953 if (CurrentProcess
!= Process
)
959 GdiDbgHTIntegrityCheck();
962 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
963 if (W32Process
->GDIHandleCount
> 0)
965 DPRINT1("Leaking %d handles!\n", W32Process
->GDIHandleCount
);
972 * Return pointer to the object by handle.
974 * \param hObj Object handle
975 * \return Pointer to the object.
977 * \note Process can only get pointer to the objects it created or global objects.
979 * \todo Get rid of the ExpectedType parameter!
981 PGDIOBJ INTERNAL_CALL
982 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
985 PGDI_TABLE_ENTRY Entry
;
986 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
988 ULONG HandleType
, HandleUpper
;
990 /* Check for dummy call */
994 GDIDBG_INITLOOPTRACE();
996 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
997 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
998 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
1000 /* Check that the handle index is valid. */
1001 if (HandleIndex
>= GDI_HANDLE_COUNT
)
1004 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
1006 /* Check if we have the requested type */
1007 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
1008 HandleType
!= ExpectedType
) ||
1011 DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1012 hObj
, HandleType
, ExpectedType
);
1013 GDIDBG_TRACECALLER();
1014 GDIDBG_TRACEALLOCATOR(hObj
);
1015 GDIDBG_TRACEDELETER(hObj
);
1019 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
1022 * Prevent the thread from being terminated during the locking process.
1023 * It would result in undesired effects and inconsistency of the global
1027 KeEnterCriticalRegion();
1030 * Loop until we either successfully lock the handle entry & object or
1031 * fail some of the check.
1036 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
1038 /* Check for invalid owner. */
1039 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
1041 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj
, ProcessId
, HandleProcessId
);
1042 GDIDBG_TRACECALLER();
1043 GDIDBG_TRACEALLOCATOR(hObj
);
1047 /* Lock the handle table entry. */
1048 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
1049 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
1053 if (PrevProcId
== HandleProcessId
)
1056 * We're locking an object that belongs to our process or it's a
1057 * global object if HandleProcessId is 0 here.
1060 if ( (Entry
->KernelData
!= NULL
) &&
1061 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
1063 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1064 Object
= Entry
->KernelData
;
1066 if (Object
->cExclusiveLock
== 0)
1068 Object
->Tid
= Thread
;
1069 Object
->cExclusiveLock
= 1;
1070 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj
))
1072 if (Thread
) Thread
->cExclusiveLocks
++;
1077 if (Object
->Tid
!= Thread
)
1079 /* Unlock the handle table entry. */
1080 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1085 InterlockedIncrement((PLONG
)&Object
->cExclusiveLock
);
1087 if (Thread
) Thread
->cExclusiveLocks
++;
1094 * Debugging code. Report attempts to lock deleted handles and
1095 * locking type mismatches.
1097 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
1100 /* Unlock the handle table entry. */
1101 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1108 * The handle is currently locked, wait some time and try again.
1110 GDIDBG_TRACELOOP(hObj
, PrevProcId
, NULL
);
1117 KeLeaveCriticalRegion();
1124 * Return pointer to the object by handle (and allow sharing of the handle
1127 * \param hObj Object handle
1128 * \return Pointer to the object.
1130 * \note Process can only get pointer to the objects it created or global objects.
1132 * \todo Get rid of the ExpectedType parameter!
1134 PGDIOBJ INTERNAL_CALL
1135 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
1138 PGDI_TABLE_ENTRY Entry
;
1139 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
1141 ULONG_PTR HandleType
, HandleUpper
;
1143 /* Check for dummy call */
1147 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
1148 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
1149 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
1151 /* Check that the handle index is valid. */
1152 if (HandleIndex
>= GDI_HANDLE_COUNT
)
1155 /* Check if we have the requested type */
1156 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
1157 HandleType
!= ExpectedType
) ||
1160 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1161 hObj
, HandleType
, ExpectedType
);
1165 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
1167 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
1168 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
1170 /* Check for invalid owner. */
1171 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
1177 * Prevent the thread from being terminated during the locking process.
1178 * It would result in undesired effects and inconsistency of the global
1182 KeEnterCriticalRegion();
1185 * Loop until we either successfully lock the handle entry & object or
1186 * fail some of the check.
1191 /* Lock the handle table entry. */
1192 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
1193 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
1197 if (PrevProcId
== HandleProcessId
)
1200 * We're locking an object that belongs to our process or it's a
1201 * global object if HandleProcessId is 0 here.
1204 if ( (Entry
->KernelData
!= NULL
) &&
1205 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
1207 Object
= (POBJ
)Entry
->KernelData
;
1209 GDIDBG_CAPTURESHARELOCKER(HandleIndex
);
1211 if (InterlockedIncrement((PLONG
)&Object
->ulShareCount
) == 1)
1213 memset(GDIHandleLocker
[HandleIndex
], 0x00, GDI_STACK_LEVELS
* sizeof(ULONG
));
1214 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS
, (PVOID
*)GDIHandleShareLocker
[HandleIndex
], NULL
);
1217 InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
1223 * Debugging code. Report attempts to lock deleted handles and
1224 * locking type mismatches.
1226 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
1229 /* Unlock the handle table entry. */
1230 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1237 * The handle is currently locked, wait some time and try again.
1245 KeLeaveCriticalRegion();
1251 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
1253 PGDI_TABLE_ENTRY Entry
;
1257 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1259 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1261 ProcessId
= PsGetCurrentProcessId();
1263 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1264 Ret
= Entry
->KernelData
!= NULL
&&
1265 (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0 &&
1266 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1275 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1278 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1279 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1281 PGDI_TABLE_ENTRY Entry
;
1282 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1286 GDIDBG_INITLOOPTRACE();
1291 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj
);
1293 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1295 if (!GDI_HANDLE_IS_STOCKOBJ(hObj
))
1297 ProcessId
= PsGetCurrentProcessId();
1298 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1300 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
1303 /* lock the object, we must not convert stock objects, so don't check!!! */
1304 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1305 if (PrevProcId
== ProcessId
)
1307 LONG NewType
, PrevType
, OldType
;
1309 /* we're locking an object that belongs to our process. First calculate
1310 the new object type including the stock object flag and then try to
1312 /* On Windows the higher 16 bit of the type field don't contain the
1313 full type from the handle, but the base type.
1314 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1315 OldType
= ((ULONG
)hObj
& GDI_HANDLE_BASETYPE_MASK
) | ((ULONG
)hObj
>> GDI_ENTRY_UPPER_SHIFT
);
1316 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1317 we copy them as we can't get them from the handle */
1318 OldType
|= Entry
->Type
& GDI_ENTRY_FLAGS_MASK
;
1320 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1321 NewType
= OldType
| GDI_ENTRY_STOCK_MASK
;
1323 /* Try to exchange the type field - but only if the old (previous type) matches! */
1324 PrevType
= InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1325 if (PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1327 PTHREADINFO PrevThread
;
1330 /* We successfully set the stock object flag.
1331 KernelData should never be NULL here!!! */
1332 ASSERT(Entry
->KernelData
);
1334 Object
= Entry
->KernelData
;
1336 PrevThread
= Object
->Tid
;
1337 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1339 /* dereference the process' object counter */
1340 if (PrevProcId
!= GDI_GLOBAL_PROCESS
)
1342 PEPROCESS OldProcess
;
1343 PPROCESSINFO W32Process
;
1347 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1348 if (NT_SUCCESS(Status
))
1350 W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
1351 if (W32Process
!= NULL
)
1353 InterlockedDecrement(&W32Process
->GDIHandleCount
);
1355 ObDereferenceObject(OldProcess
);
1359 hObj
= (HGDIOBJ
)((ULONG
)(hObj
) | GDI_HANDLE_STOCK_MASK
);
1361 Object
->hHmgr
= hObj
;
1363 /* remove the process id lock and make it global */
1364 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1366 /* we're done, successfully converted the object */
1371 GDIDBG_TRACELOOP(hObj
, PrevThread
, Thread
);
1373 /* WTF?! The object is already locked by a different thread!
1374 Release the lock, wait a bit and try again!
1375 FIXME - we should give up after some time unless we want to wait forever! */
1376 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1384 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1385 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType
, Entry
->Type
, NewType
, Entry
->KernelData
);
1388 else if (PrevProcId
== LockedProcessId
)
1390 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
1392 /* the object is currently locked, wait some time and try again.
1393 FIXME - we shouldn't loop forever! Give up after some time! */
1400 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1408 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1410 PGDI_TABLE_ENTRY Entry
;
1411 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1415 GDIDBG_INITLOOPTRACE();
1417 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1419 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1421 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1423 ProcessId
= PsGetCurrentProcessId();
1424 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1426 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1429 /* lock the object, we must not convert stock objects, so don't check!!! */
1430 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1431 if (PrevProcId
== ProcessId
)
1433 PTHREADINFO PrevThread
;
1435 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1437 POBJ Object
= Entry
->KernelData
;
1439 PrevThread
= Object
->Tid
;
1440 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1442 PEPROCESS OldProcess
;
1443 PPROCESSINFO W32Process
;
1446 if (NewOwner
!= NULL
)
1448 ProcessId
= PsGetProcessId(NewOwner
);
1453 if((ULONG_PTR
)ProcessId
== ((ULONG_PTR
)PrevProcId
& ~0x1))
1455 DPRINT("Setting same process than previous one, nothing to do\n");
1459 /* dereference the process' object counter */
1461 if ((ULONG_PTR
)PrevProcId
& ~0x1)
1463 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1464 if (NT_SUCCESS(Status
))
1466 W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
1467 if (W32Process
!= NULL
)
1469 InterlockedDecrement(&W32Process
->GDIHandleCount
);
1471 ObDereferenceObject(OldProcess
);
1475 if (NewOwner
!= NULL
)
1477 /* Increase the new process' object counter */
1478 W32Process
= (PPROCESSINFO
)NewOwner
->Win32Process
;
1479 if (W32Process
!= NULL
)
1481 InterlockedIncrement(&W32Process
->GDIHandleCount
);
1486 /* remove the process id lock and change it to the new process id */
1487 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
);
1494 GDIDBG_TRACELOOP(ObjectHandle
, PrevThread
, Thread
);
1496 /* WTF?! The object is already locked by a different thread!
1497 Release the lock, wait a bit and try again! DO reset the pid lock
1498 so we make sure we don't access invalid memory in case the object is
1499 being deleted in the meantime (because we don't have aquired a reference
1501 FIXME - we should give up after some time unless we want to wait forever! */
1502 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1510 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1511 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry
->Type
, Entry
->KernelData
);
1515 else if (PrevProcId
== LockedProcessId
)
1517 GDIDBG_TRACELOOP(ObjectHandle
, PrevProcId
, ProcessId
);
1519 /* the object is currently locked, wait some time and try again.
1520 FIXME - we shouldn't loop forever! Give up after some time! */
1525 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1527 /* allow changing ownership of global objects */
1529 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1532 else if ((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1534 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1539 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1547 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1549 PGDI_TABLE_ENTRY FromEntry
;
1551 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1554 GDIDBG_INITLOOPTRACE();
1556 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1558 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1560 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1562 FromEntry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, CopyFrom
);
1564 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1565 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1568 /* lock the object, we must not convert stock objects, so don't check!!! */
1569 FromPrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1570 if (FromPrevProcId
== FromProcessId
)
1572 PTHREADINFO PrevThread
;
1575 if ((FromEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1577 Object
= FromEntry
->KernelData
;
1579 /* save the pointer to the calling thread so we know it was this thread
1580 that locked the object */
1581 PrevThread
= Object
->Tid
;
1582 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1584 /* now let's change the ownership of the target object */
1586 if (((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1588 PEPROCESS ProcessTo
;
1590 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1592 GDIOBJ_SetOwnership(CopyTo
, ProcessTo
);
1593 ObDereferenceObject(ProcessTo
);
1598 /* mark the object as global */
1599 GDIOBJ_SetOwnership(CopyTo
, NULL
);
1602 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1606 GDIDBG_TRACELOOP(CopyFrom
, PrevThread
, Thread
);
1608 /* WTF?! The object is already locked by a different thread!
1609 Release the lock, wait a bit and try again! DO reset the pid lock
1610 so we make sure we don't access invalid memory in case the object is
1611 being deleted in the meantime (because we don't have aquired a reference
1613 FIXME - we should give up after some time unless we want to wait forever! */
1614 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1617 goto LockHandleFrom
;
1622 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1626 else if (FromPrevProcId
== FromLockedProcessId
)
1628 GDIDBG_TRACELOOP(CopyFrom
, FromPrevProcId
, FromProcessId
);
1630 /* the object is currently locked, wait some time and try again.
1631 FIXME - we shouldn't loop forever! Give up after some time! */
1634 goto LockHandleFrom
;
1636 else if ((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1638 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1639 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1640 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1641 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1642 goto LockHandleFrom
;
1646 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1654 GDI_MapHandleTable(PSECTION_OBJECT SectionObject
, PEPROCESS Process
)
1656 PVOID MappedView
= NULL
;
1658 LARGE_INTEGER Offset
;
1659 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1661 Offset
.QuadPart
= 0;
1663 ASSERT(SectionObject
!= NULL
);
1664 ASSERT(Process
!= NULL
);
1666 Status
= MmMapViewOfSection(SectionObject
,
1677 if (!NT_SUCCESS(Status
))
1683 /* Locks 2 or 3 objects at a time */
1686 GDIOBJ_LockMultipleObjs(ULONG ulCount
,
1690 UINT auiIndices
[3] = {0,1,2};
1692 BOOL bUnsorted
= TRUE
;
1694 /* First is greatest */
1698 for(i
=1; i
<ulCount
; i
++)
1700 if((ULONG_PTR
)ahObj
[auiIndices
[i
-1]] < (ULONG_PTR
)ahObj
[auiIndices
[i
]])
1702 tmp
= auiIndices
[i
-1];
1703 auiIndices
[i
-1] = auiIndices
[i
];
1704 auiIndices
[i
] = tmp
;
1710 for(i
=0;i
<ulCount
;i
++)
1711 apObj
[auiIndices
[i
]] = GDIOBJ_LockObj(ahObj
[auiIndices
[i
]], GDI_OBJECT_TYPE_DONTCARE
);
1715 /** PUBLIC FUNCTIONS **********************************************************/
1719 IntGdiSetRegionOwner(HRGN hRgn
, DWORD OwnerMask
)
1722 PGDI_TABLE_ENTRY Entry
;
1725 These regions do not use attribute sections and when allocated, use gdiobj
1728 // FIXME! HAX!!! Remove this once we get everything right!
1729 Index
= GDI_HANDLE_GET_INDEX(hRgn
);
1730 Entry
= &GdiHandleTable
->Entries
[Index
];
1731 if (Entry
->UserData
) FreeObjectAttr(Entry
->UserData
);
1732 Entry
->UserData
= NULL
;
1734 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1736 return GDIOBJ_SetOwnership(hRgn
, NULL
);
1738 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1740 return GDIOBJ_SetOwnership((HGDIOBJ
) hRgn
, PsGetCurrentProcess() );
1747 IntGdiSetBrushOwner(PBRUSH pbr
, DWORD OwnerMask
)
1750 PEPROCESS Owner
= NULL
;
1751 PGDI_TABLE_ENTRY pEntry
= NULL
;
1753 if (!pbr
) return FALSE
;
1755 hBR
= pbr
->BaseObject
.hHmgr
;
1757 if (!hBR
|| (GDI_HANDLE_GET_TYPE(hBR
) != GDI_OBJECT_TYPE_BRUSH
))
1761 INT Index
= GDI_HANDLE_GET_INDEX((HGDIOBJ
)hBR
);
1762 pEntry
= &GdiHandleTable
->Entries
[Index
];
1765 if (pbr
->flAttrs
& GDIBRUSH_IS_GLOBAL
)
1767 GDIOBJ_ShareUnlockObjByPtr((POBJ
)pbr
);
1771 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1773 // Set this Brush to inaccessible mode and to an Owner of NONE.
1774 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1776 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, Owner
))
1779 // Deny user access to User Data.
1780 pEntry
->UserData
= NULL
; // This hBR is inaccessible!
1783 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1785 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, PsGetCurrentProcess() ))
1788 // Allow user access to User Data.
1789 pEntry
->UserData
= pbr
->pBrushAttr
;
1796 IntGdiSetDCOwnerEx( HDC hDC
, DWORD OwnerMask
, BOOL NoSetBrush
)
1801 if (!hDC
|| (GDI_HANDLE_GET_TYPE(hDC
) != GDI_OBJECT_TYPE_DC
)) return FALSE
;
1803 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1805 pDC
= DC_LockDc ( hDC
);
1806 MmCopyFromCaller(&pDC
->dcattr
, pDC
->pdcattr
, sizeof(DC_ATTR
));
1807 DC_vFreeDcAttr(pDC
);
1810 if (!DC_SetOwnership( hDC
, NULL
)) // This hDC is inaccessible!
1814 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1816 pDC
= DC_LockDc ( hDC
);
1817 ASSERT(pDC
->pdcattr
== &pDC
->dcattr
);
1820 if (!DC_SetOwnership( hDC
, PsGetCurrentProcess() )) return Ret
;
1822 DC_AllocateDcAttr( hDC
); // Allocate new dcattr
1824 DCU_SynchDcAttrtoUser( hDC
); // Copy data from dc to dcattr
1827 if ((OwnerMask
!= GDI_OBJ_HMGR_NONE
) && !NoSetBrush
)
1829 pDC
= DC_LockDc ( hDC
);
1830 if (IntGdiSetBrushOwner((PBRUSH
)pDC
->dclevel
.pbrFill
, OwnerMask
))
1831 IntGdiSetBrushOwner((PBRUSH
)pDC
->dclevel
.pbrLine
, OwnerMask
);
1839 GreGetObjectOwner(HGDIOBJ Handle
, GDIOBJTYPE ObjType
)
1841 INT Ret
= GDI_OBJ_HMGR_RESTRICTED
;
1843 if ( GDI_HANDLE_GET_INDEX(Handle
) < GDI_HANDLE_COUNT
)
1845 PGDI_TABLE_ENTRY pEntry
= &GdiHandleTable
->Entries
[GDI_HANDLE_GET_INDEX(Handle
)];
1847 if (pEntry
->ObjectType
== ObjType
)
1849 if (pEntry
->FullUnique
== (GDI_HANDLE_GET_UPPER(Handle
) >> GDI_ENTRY_UPPER_SHIFT
))
1850 Ret
= pEntry
->ProcessId
& ~1;
1859 NtGdiCreateClientObj(
1866 /* Mask out everything that would change the type in a wrong manner */
1867 ulType
&= (GDI_HANDLE_TYPE_MASK
& ~GDI_HANDLE_BASETYPE_MASK
);
1869 /* Allocate a new object */
1870 pObject
= GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ
| ulType
);
1876 /* get the handle */
1877 handle
= pObject
->hHmgr
;
1880 GDIOBJ_UnlockObjByPtr(pObject
);
1888 NtGdiDeleteClientObj(
1892 /* We first need to get the real type from the handle */
1893 ULONG type
= GDI_HANDLE_GET_TYPE(h
);
1895 /* Check if it's really a CLIENTOBJ */
1896 if ((type
& GDI_HANDLE_BASETYPE_MASK
) != GDILoObjType_LO_CLIENTOBJ_TYPE
)
1898 /* FIXME: SetLastError? */
1901 return GDIOBJ_FreeObjByHandle(h
, type
);
1906 IntGdiGetObject(IN HANDLE Handle
,
1914 pGdiObject
= GDIOBJ_LockObj(Handle
, GDI_OBJECT_TYPE_DONTCARE
);
1917 EngSetLastError(ERROR_INVALID_HANDLE
);
1921 dwObjectType
= GDIOBJ_GetObjectType(Handle
);
1922 switch (dwObjectType
)
1924 case GDI_OBJECT_TYPE_PEN
:
1925 case GDI_OBJECT_TYPE_EXTPEN
:
1926 Result
= PEN_GetObject((PBRUSH
) pGdiObject
, cbCount
, (PLOGPEN
) lpBuffer
); // IntGdiCreatePenIndirect
1929 case GDI_OBJECT_TYPE_BRUSH
:
1930 Result
= BRUSH_GetObject((PBRUSH
) pGdiObject
, cbCount
, (LPLOGBRUSH
)lpBuffer
);
1933 case GDI_OBJECT_TYPE_BITMAP
:
1934 Result
= BITMAP_GetObject((SURFACE
*) pGdiObject
, cbCount
, lpBuffer
);
1936 case GDI_OBJECT_TYPE_FONT
:
1937 Result
= FontGetObject((PTEXTOBJ
) pGdiObject
, cbCount
, lpBuffer
);
1939 // Fix the LOGFONT structure for the stock fonts
1940 if (FIRST_STOCK_HANDLE
<= Handle
&& Handle
<= LAST_STOCK_HANDLE
)
1942 FixStockFontSizeW(Handle
, cbCount
, lpBuffer
);
1947 case GDI_OBJECT_TYPE_PALETTE
:
1948 Result
= PALETTE_GetObject((PPALETTE
) pGdiObject
, cbCount
, lpBuffer
);
1952 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType
);
1956 GDIOBJ_UnlockObjByPtr(pGdiObject
);
1966 NtGdiExtGetObjectW(IN HANDLE hGdiObj
,
1968 OUT LPVOID lpBuffer
)
1975 DIBSECTION dibsection
;
1979 EXTLOGFONTW extlogfontw
;
1980 ENUMLOGFONTEXDVW enumlogfontexdvw
;
1983 // Normalize to the largest supported object size
1984 cbCount
= min((UINT
)cbCount
, sizeof(Object
));
1986 // Now do the actual call
1987 iRetCount
= IntGdiGetObject(hGdiObj
, cbCount
, lpBuffer
? &Object
: NULL
);
1988 cbCopyCount
= min((UINT
)cbCount
, (UINT
)iRetCount
);
1990 // Make sure we have a buffer and a copy size
1991 if ((cbCopyCount
) && (lpBuffer
))
1993 // Enter SEH for buffer transfer
1996 // Probe the buffer and copy it
1997 ProbeForWrite(lpBuffer
, cbCopyCount
, sizeof(WORD
));
1998 RtlCopyMemory(lpBuffer
, &Object
, cbCopyCount
);
2000 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2002 // Clear the return value.
2003 // Do *NOT* set last error here!