2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/objects/gdiobj.c
5 * PURPOSE: General GDI object manipulation routines
9 /** INCLUDES ******************************************************************/
17 #define GDI_ENTRY_TO_INDEX(ht, e) \
18 (((ULONG_PTR)(e) - (ULONG_PTR)&((ht)->Entries[0])) / sizeof(GDI_TABLE_ENTRY))
19 #define GDI_HANDLE_GET_ENTRY(HandleTable, h) \
20 (&(HandleTable)->Entries[GDI_HANDLE_GET_INDEX((h))])
22 /* apparently the first 10 entries are never used in windows as they are empty */
23 #define RESERVE_ENTRIES_COUNT 10
25 #define BASE_OBJTYPE_COUNT 32
27 #define DelayExecution() \
28 DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
29 KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
34 BOOL INTERNAL_CALL
GDI_CleanupDummy(PVOID ObjectBody
);
36 /** GLOBALS *******************************************************************/
43 GDICLEANUPPROC CleanupProc
;
44 } OBJ_TYPE_INFO
, *POBJ_TYPE_INFO
;
47 OBJ_TYPE_INFO ObjTypeInfo
[BASE_OBJTYPE_COUNT
] =
49 {0, 0, 0, NULL
}, /* 00 reserved entry */
50 {1, sizeof(DC
), TAG_DC
, DC_Cleanup
}, /* 01 DC */
51 {1, 0, 0, NULL
}, /* 02 UNUSED1 */
52 {1, 0, 0, NULL
}, /* 03 UNUSED2 */
53 {1, sizeof(ROSRGNDATA
), TAG_REGION
, REGION_Cleanup
}, /* 04 RGN */
54 {1, sizeof(SURFACE
), TAG_SURFACE
, SURFACE_Cleanup
}, /* 05 SURFACE */
55 {1, sizeof(CLIENTOBJ
), TAG_CLIENTOBJ
, GDI_CleanupDummy
}, /* 06 CLIENTOBJ: METADC,... */
56 {1, sizeof(PATH
), TAG_PATH
, GDI_CleanupDummy
}, /* 07 PATH */
57 {1, sizeof(PALETTE
), TAG_PALETTE
, PALETTE_Cleanup
}, /* 08 PAL */
58 {1, sizeof(COLORSPACE
), TAG_ICMLCS
, GDI_CleanupDummy
}, /* 09 ICMLCS, */
59 {1, sizeof(TEXTOBJ
), TAG_LFONT
, GDI_CleanupDummy
}, /* 0a LFONT */
60 {0, 0, TAG_RFONT
, NULL
}, /* 0b RFONT, unused */
61 {0, 0, TAG_PFE
, NULL
}, /* 0c PFE, unused */
62 {0, 0, TAG_PFT
, NULL
}, /* 0d PFT, unused */
63 {0, sizeof(GDICLRXFORM
), TAG_ICMCXF
, GDI_CleanupDummy
}, /* 0e ICMCXF, */
64 {0, 0, TAG_SPRITE
, NULL
}, /* 0f SPRITE, unused */
65 {1, sizeof(BRUSH
), TAG_BRUSH
, BRUSH_Cleanup
}, /* 10 BRUSH, PEN, EXTPEN */
66 {0, 0, TAG_UMPD
, NULL
}, /* 11 UMPD, unused */
67 {0, 0, 0, NULL
}, /* 12 UNUSED4 */
68 {0, 0, TAG_SPACE
, NULL
}, /* 13 SPACE, unused */
69 {0, 0, 0, NULL
}, /* 14 UNUSED5 */
70 {0, 0, TAG_META
, NULL
}, /* 15 META, unused */
71 {0, 0, TAG_EFSTATE
, NULL
}, /* 16 EFSTATE, unused */
72 {0, 0, TAG_BMFD
, NULL
}, /* 17 BMFD, unused */
73 {0, 0, TAG_VTFD
, NULL
}, /* 18 VTFD, unused */
74 {0, 0, TAG_TTFD
, NULL
}, /* 19 TTFD, unused */
75 {0, 0, TAG_RC
, NULL
}, /* 1a RC, unused */
76 {0, 0, TAG_TEMP
, NULL
}, /* 1b TEMP, unused */
77 {0, sizeof(EDRIVEROBJ
), TAG_DRVOBJ
, DRIVEROBJ_Cleanup
},/* 1c DRVOBJ */
78 {0, 0, TAG_DCIOBJ
, NULL
}, /* 1d DCIOBJ, unused */
79 {0, 0, TAG_SPOOL
, NULL
}, /* 1e SPOOL, unused */
80 {0, 0, 0, NULL
}, /* 1f reserved entry */
83 static LARGE_INTEGER ShortDelay
;
84 PGDI_HANDLE_TABLE GdiHandleTable
= NULL
;
85 PSECTION_OBJECT GdiTableSection
= NULL
;
87 /** INTERNAL FUNCTIONS ********************************************************/
97 AllocTypeDataDump(INT TypeInfo
)
99 switch( TypeInfo
& GDI_HANDLE_TYPE_MASK
)
101 case GDILoObjType_LO_BRUSH_TYPE
:
104 case GDILoObjType_LO_DC_TYPE
:
107 case GDILoObjType_LO_BITMAP_TYPE
:
110 case GDILoObjType_LO_FONT_TYPE
:
113 case GDILoObjType_LO_REGION_TYPE
:
120 DeAllocTypeDataDump(INT TypeInfo
)
122 switch( TypeInfo
& GDI_HANDLE_TYPE_MASK
)
124 case GDILoObjType_LO_BRUSH_TYPE
:
127 case GDILoObjType_LO_DC_TYPE
:
130 case GDILoObjType_LO_BITMAP_TYPE
:
133 case GDILoObjType_LO_FONT_TYPE
:
136 case GDILoObjType_LO_REGION_TYPE
:
143 * Dummy GDI Cleanup Callback
147 GDI_CleanupDummy(PVOID ObjectBody
)
153 * Allocate GDI object table.
154 * \param Size - number of entries in the object table.
159 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT
*SectionObject
)
161 PGDI_HANDLE_TABLE HandleTable
= NULL
;
162 LARGE_INTEGER htSize
;
167 ASSERT(SectionObject
!= NULL
);
169 htSize
.QuadPart
= sizeof(GDI_HANDLE_TABLE
);
171 Status
= MmCreateSection((PVOID
*)SectionObject
,
179 if (!NT_SUCCESS(Status
))
182 /* FIXME - use MmMapViewInSessionSpace once available! */
183 Status
= MmMapViewInSystemSpace(*SectionObject
,
184 (PVOID
*)&HandleTable
,
186 if (!NT_SUCCESS(Status
))
188 ObDereferenceObject(*SectionObject
);
189 *SectionObject
= NULL
;
193 RtlZeroMemory(HandleTable
, sizeof(GDI_HANDLE_TABLE
));
195 HandleTable
->LookasideLists
= ExAllocatePoolWithTag(NonPagedPool
,
196 BASE_OBJTYPE_COUNT
* sizeof(PAGED_LOOKASIDE_LIST
),
198 if (HandleTable
->LookasideLists
== NULL
)
200 MmUnmapViewInSystemSpace(HandleTable
);
201 ObDereferenceObject(*SectionObject
);
202 *SectionObject
= NULL
;
206 for (ObjType
= 0; ObjType
< BASE_OBJTYPE_COUNT
; ObjType
++)
208 if (ObjTypeInfo
[ObjType
].bUseLookaside
)
210 ExInitializePagedLookasideList(HandleTable
->LookasideLists
+ ObjType
,
214 ObjTypeInfo
[ObjType
].ulBodySize
,
215 ObjTypeInfo
[ObjType
].Tag
,
220 ShortDelay
.QuadPart
= -5000LL; /* FIXME - 0.5 ms? */
222 HandleTable
->FirstFree
= 0;
223 HandleTable
->FirstUnused
= RESERVE_ENTRIES_COUNT
;
233 /* Create the GDI handle table */
234 GdiHandleTable
= GDIOBJ_iAllocHandleTable(&GdiTableSection
);
235 if (GdiHandleTable
== NULL
)
237 DPRINT1("Failed to initialize the GDI handle table.\n");
238 return STATUS_UNSUCCESSFUL
;
241 return STATUS_SUCCESS
;
246 LockErrorDebugOutput(HGDIOBJ hObj
, PGDI_TABLE_ENTRY Entry
, LPSTR Function
)
248 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
250 DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function
, hObj
);
251 GDIDBG_TRACEDELETER(hObj
);
253 else if (GDI_HANDLE_GET_REUSECNT(hObj
) != GDI_ENTRY_GET_REUSECNT(Entry
->Type
))
255 DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
256 Function
, hObj
, GDI_HANDLE_GET_REUSECNT(hObj
), GDI_ENTRY_GET_REUSECNT(Entry
->Type
));
258 else if (GDI_HANDLE_GET_TYPE(hObj
) != ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
))
260 DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
261 Function
, hObj
, GDI_HANDLE_GET_TYPE(hObj
), (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
);
265 DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
266 Function
, hObj
, Entry
->Type
);
268 GDIDBG_TRACECALLER();
273 InterlockedPopFreeEntry(VOID
)
275 ULONG idxFirst
, idxNext
, idxPrev
;
276 PGDI_TABLE_ENTRY pEntry
;
279 DPRINT("Enter InterLockedPopFreeEntry\n");
283 idxFirst
= GdiHandleTable
->FirstFree
;
287 /* Increment FirstUnused and get the new index */
288 idxFirst
= InterlockedIncrement((LONG
*)&GdiHandleTable
->FirstUnused
) - 1;
290 /* Check if we have entries left */
291 if (idxFirst
>= GDI_HANDLE_COUNT
)
293 DPRINT1("No more gdi handles left!\n");
297 /* Return the old index */
301 /* Get a pointer to the first free entry */
302 pEntry
= GdiHandleTable
->Entries
+ idxFirst
;
304 /* Try to lock the entry */
305 PrevProcId
= InterlockedCompareExchange((LONG
*)&pEntry
->ProcessId
, 1, 0);
308 /* The entry was locked or not free, wait and start over */
313 /* Sanity check: is entry really free? */
314 ASSERT(((ULONG_PTR
)pEntry
->KernelData
& ~GDI_HANDLE_INDEX_MASK
) == 0);
316 /* Try to exchange the FirstFree value */
317 idxNext
= (ULONG_PTR
)pEntry
->KernelData
;
318 idxPrev
= InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
,
322 /* Unlock the free entry */
323 (void)InterlockedExchange((LONG
*)&pEntry
->ProcessId
, 0);
325 /* If we succeeded, break out of the loop */
326 if (idxPrev
== idxFirst
)
335 /* Pushes an entry of the handle table to the free list,
336 The entry must be unlocked and the base type field must be 0 */
339 InterlockedPushFreeEntry(ULONG idxToFree
)
341 ULONG idxFirstFree
, idxPrev
;
342 PGDI_TABLE_ENTRY pFreeEntry
;
344 DPRINT("Enter InterlockedPushFreeEntry\n");
346 pFreeEntry
= GdiHandleTable
->Entries
+ idxToFree
;
347 ASSERT((pFreeEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0);
348 ASSERT(pFreeEntry
->ProcessId
== 0);
349 pFreeEntry
->UserData
= NULL
;
353 idxFirstFree
= GdiHandleTable
->FirstFree
;
354 pFreeEntry
->KernelData
= (PVOID
)(ULONG_PTR
)idxFirstFree
;
356 idxPrev
= InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
,
360 while (idxPrev
!= idxFirstFree
);
366 GDIOBJ_ValidateHandle(HGDIOBJ hObj
, ULONG ObjectType
)
368 PGDI_TABLE_ENTRY Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
369 if ((((ULONG_PTR
)hObj
& GDI_HANDLE_TYPE_MASK
) == ObjectType
) &&
370 (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == GDI_HANDLE_GET_UPPER(hObj
))
372 HANDLE pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
373 if (pid
== NULL
|| pid
== PsGetCurrentProcessId())
382 GDIOBJ_AllocObj(UCHAR BaseType
)
386 ASSERT((BaseType
& ~GDIObjTypeTotal
) == 0);
387 // BaseType &= GDI_HANDLE_BASETYPE_MASK;
389 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
391 PPAGED_LOOKASIDE_LIST LookasideList
;
393 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
394 pObject
= ExAllocateFromPagedLookasideList(LookasideList
);
398 pObject
= ExAllocatePoolWithTag(PagedPool
,
399 ObjTypeInfo
[BaseType
].ulBodySize
,
400 ObjTypeInfo
[BaseType
].Tag
);
405 RtlZeroMemory(pObject
, ObjTypeInfo
[BaseType
].ulBodySize
);
413 * Allocate memory for GDI object and return handle to it.
415 * \param ObjectType - type of object \ref GDI object types
417 * \return Pointer to the allocated object, which is locked.
420 GDIOBJ_AllocObjWithHandle(ULONG ObjectType
)
422 PPROCESSINFO W32Process
;
423 POBJ newObject
= NULL
;
424 HANDLE CurrentProcessId
, LockedProcessId
;
427 PGDI_TABLE_ENTRY Entry
;
430 GDIDBG_INITLOOPTRACE();
432 W32Process
= PsGetCurrentProcessWin32Process();
433 /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
434 to take too many GDI objects, itself. */
435 if (W32Process
&& W32Process
->GDIHandleCount
>= 0x2710)
437 DPRINT1("Too many objects for process!!!\n");
438 DPRINT1("DC %d BRUSH %d BITMAP %d FONT %d RGN %d\n",tDC
,tBRUSH
,tBITMAP
,tFONT
,tRGN
);
439 GDIDBG_DUMPHANDLETABLE();
443 ASSERT(ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
);
445 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(ObjectType
);
447 newObject
= GDIOBJ_AllocObj(TypeIndex
);
450 DPRINT1("Not enough memory to allocate gdi object!\n");
454 CurrentProcessId
= PsGetCurrentProcessId();
455 LockedProcessId
= (HANDLE
)((ULONG_PTR
)CurrentProcessId
| 0x1);
457 // RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
459 /* On Windows the higher 16 bit of the type field don't contain the
460 full type from the handle, but the base type.
461 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
462 TypeInfo
= (ObjectType
& GDI_HANDLE_BASETYPE_MASK
) | (ObjectType
>> GDI_ENTRY_UPPER_SHIFT
);
464 Index
= InterlockedPopFreeEntry();
469 Entry
= &GdiHandleTable
->Entries
[Index
];
472 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, 0);
473 if (PrevProcId
== NULL
)
475 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
478 Entry
->KernelData
= newObject
;
480 /* copy the reuse-counter */
481 TypeInfo
|= Entry
->Type
& GDI_ENTRY_REUSE_MASK
;
483 /* we found a free entry, no need to exchange this field atomically
484 since we're holding the lock */
485 Entry
->Type
= TypeInfo
;
487 /* Create a handle */
488 Handle
= (HGDIOBJ
)((Index
& 0xFFFF) | (TypeInfo
<< GDI_ENTRY_UPPER_SHIFT
));
490 /* Initialize BaseObject fields */
491 newObject
->hHmgr
= Handle
;
492 newObject
->ulShareCount
= 0;
493 newObject
->cExclusiveLock
= 1;
494 newObject
->Tid
= Thread
;
496 AllocTypeDataDump(TypeInfo
);
498 /* unlock the entry */
499 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, CurrentProcessId
);
501 GDIDBG_CAPTUREALLOCATOR(Index
);
503 if (W32Process
!= NULL
)
505 InterlockedIncrement(&W32Process
->GDIHandleCount
);
508 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle
, newObject
);
513 GDIDBG_TRACELOOP(Index
, PrevProcId
, CurrentProcessId
);
514 /* damn, someone is trying to lock the object even though it doesn't
515 even exist anymore, wait a little and try again!
516 FIXME - we shouldn't loop forever! Give up after some time! */
523 GDIOBJ_FreeObj(newObject
, TypeIndex
);
525 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
526 GDIDBG_DUMPHANDLETABLE();
533 GDIOBJ_FreeObj(POBJ pObject
, UCHAR BaseType
)
535 /* Object must not have a handle! */
536 ASSERT(pObject
->hHmgr
== NULL
);
538 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
540 PPAGED_LOOKASIDE_LIST LookasideList
;
542 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
543 ExFreeToPagedLookasideList(LookasideList
, pObject
);
552 * Free memory allocated for the GDI object. For each object type this function calls the
553 * appropriate cleanup routine.
555 * \param hObj - handle of the object to be deleted.
557 * \return Returns TRUE if succesful.
558 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
559 * to the calling process.
561 * \bug This function should return VOID and kill the object no matter what...
564 GDIOBJ_FreeObjByHandle(HGDIOBJ hObj
, DWORD ExpectedType
)
566 PGDI_TABLE_ENTRY Entry
;
567 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
568 ULONG HandleType
, HandleUpper
, TypeIndex
;
571 GDIDBG_INITLOOPTRACE();
573 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj
);
575 if (GDI_HANDLE_IS_STOCKOBJ(hObj
))
577 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj
);
578 GDIDBG_TRACECALLER();
582 ProcessId
= PsGetCurrentProcessId();
583 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
585 Silent
= (ExpectedType
& GDI_OBJECT_TYPE_SILENT
);
586 ExpectedType
&= ~GDI_OBJECT_TYPE_SILENT
;
588 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
589 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
591 /* Check if we have the requested type */
592 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
593 HandleType
!= ExpectedType
) ||
596 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
597 hObj
, HandleType
, ExpectedType
);
598 GDIDBG_TRACECALLER();
602 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
605 /* lock the object, we must not delete global objects, so don't exchange the locking
606 process ID to zero when attempting to lock a global object... */
607 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
608 if (PrevProcId
== ProcessId
)
610 if ( (Entry
->KernelData
!= NULL
) &&
611 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) &&
612 ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == (HandleUpper
& GDI_ENTRY_BASETYPE_MASK
)) )
616 Object
= Entry
->KernelData
;
618 if ((Object
->cExclusiveLock
== 0 ||
619 Object
->Tid
== (PTHREADINFO
)PsGetCurrentThreadWin32Thread()) &&
620 Object
->ulShareCount
== 0)
623 PPROCESSINFO W32Process
= PsGetCurrentProcessWin32Process();
625 /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
626 Entry
->Type
= (Entry
->Type
+ GDI_ENTRY_REUSE_INC
) & ~GDI_ENTRY_BASETYPE_MASK
;
628 /* unlock the handle slot */
629 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
631 /* push this entry to the free list */
632 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable
, Entry
));
634 Object
->hHmgr
= NULL
;
636 if (W32Process
!= NULL
)
638 InterlockedDecrement(&W32Process
->GDIHandleCount
);
641 /* call the cleanup routine. */
642 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(HandleType
);
643 Ret
= ObjTypeInfo
[TypeIndex
].CleanupProc(Object
);
645 DeAllocTypeDataDump(HandleType
);
647 /* Now it's time to free the memory */
648 GDIOBJ_FreeObj(Object
, TypeIndex
);
650 GDIDBG_CAPTUREDELETER(hObj
);
653 else if (Object
->ulShareCount
!= 0)
656 PEPROCESS OldProcess
;
657 Object
->BaseFlags
|= BASEFLAG_READY_TO_DIE
;
658 DPRINT("Object %p, ulShareCount = %d\n", Object
->hHmgr
, Object
->ulShareCount
);
659 /* Set NULL owner. Do the work here to avoid race conditions */
660 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
661 if (NT_SUCCESS(Status
))
663 PPROCESSINFO W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
664 if (W32Process
!= NULL
)
666 InterlockedDecrement(&W32Process
->GDIHandleCount
);
668 ObDereferenceObject(OldProcess
);
670 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
671 /* Don't wait on shared locks */
677 * The object is currently locked by another thread, so freeing is forbidden!
679 DPRINT1("Object->cExclusiveLock = %d\n", Object
->cExclusiveLock
);
680 GDIDBG_TRACECALLER();
681 GDIDBG_TRACELOCKER(hObj
);
682 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
683 /* do not assert here for it will call again from dxg.sys it being call twice */
691 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
692 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
695 else if (PrevProcId
== LockedProcessId
)
697 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
699 /* the object is currently locked, wait some time and try again.
700 FIXME - we shouldn't loop forever! Give up after some time! */
709 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
711 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj
);
713 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
715 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
719 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);
721 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry
->Type
, Entry
->KernelData
, Entry
->ProcessId
);
722 GDIDBG_TRACECALLER();
723 GDIDBG_TRACEALLOCATOR(hObj
);
732 IsObjectDead(HGDIOBJ hObject
)
734 INT Index
= GDI_HANDLE_GET_INDEX(hObject
);
735 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
736 // We check to see if the objects are knocking on deaths door.
737 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
741 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject
);
742 return TRUE
; // return true and move on.
749 bPEBCacheHandle(HGDIOBJ Handle
, int oType
, PVOID pAttr
)
751 PGDIHANDLECACHE GdiHandleCache
;
754 int Offset
= 0, Number
;
757 GdiHandleCache
= (PGDIHANDLECACHE
)NtCurrentTeb()->ProcessEnvironmentBlock
->GdiHandleBuffer
;
766 Offset
= CACHE_BRUSH_ENTRIES
;
769 case hctRegionHandle
:
770 Offset
= CACHE_BRUSH_ENTRIES
+CACHE_PEN_ENTRIES
;
777 Lock
= InterlockedCompareExchangePointer( (PVOID
*)&GdiHandleCache
->ulLock
,
780 if (Lock
) return FALSE
;
784 Number
= GdiHandleCache
->ulNumHandles
[oType
];
786 hPtr
= GdiHandleCache
->Handle
+ Offset
;
788 if ( pAttr
&& oType
== hctRegionHandle
)
790 if ( Number
< CACHE_REGION_ENTRIES
)
792 ((PRGN_ATTR
)pAttr
)->AttrFlags
|= ATTR_CACHED
;
793 hPtr
[Number
] = Handle
;
794 GdiHandleCache
->ulNumHandles
[oType
]++;
795 DPRINT("Put Handle Count %d PEB 0x%x\n", GdiHandleCache
->ulNumHandles
[oType
], NtCurrentTeb()->ProcessEnvironmentBlock
);
800 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
806 (void)InterlockedExchangePointer((PVOID
*)&GdiHandleCache
->ulLock
, Lock
);
812 * \param hObject object handle
813 * \return if the function fails the returned value is FALSE.
817 GreDeleteObject(HGDIOBJ hObject
)
820 PGDI_TABLE_ENTRY Entry
;
824 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
825 if (!IsObjectDead(hObject
))
827 dwObjectType
= GDIOBJ_GetObjectType(hObject
);
829 Index
= GDI_HANDLE_GET_INDEX(hObject
);
830 Entry
= &GdiHandleTable
->Entries
[Index
];
831 pAttr
= Entry
->UserData
;
833 switch (dwObjectType
)
835 case GDI_OBJECT_TYPE_BRUSH
:
838 case GDI_OBJECT_TYPE_REGION
:
839 /* If pAttr NULL, the probability is high for System Region. */
841 bPEBCacheHandle(hObject
, hctRegionHandle
, pAttr
))
843 /* User space handle only! */
848 FreeObjectAttr(pAttr
);
849 Entry
->UserData
= NULL
;
853 case GDI_OBJECT_TYPE_DC
:
854 // DC_FreeDcAttr(hObject);
858 return NULL
!= hObject
859 ? GDIOBJ_FreeObjByHandle(hObject
, dwObjectType
) : FALSE
;
863 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject
);
864 return TRUE
; // return true and move on.
870 IntDeleteHandlesForProcess(struct _EPROCESS
*Process
, ULONG ObjectType
)
872 PGDI_TABLE_ENTRY Entry
, End
;
873 ULONG Index
= RESERVE_ENTRIES_COUNT
;
875 PPROCESSINFO W32Process
;
877 W32Process
= (PPROCESSINFO
)Process
->Win32Process
;
880 if (W32Process
->GDIHandleCount
> 0)
882 ProcId
= Process
->UniqueProcessId
;
884 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
885 we should delete it directly here! */
887 End
= &GdiHandleTable
->Entries
[GDI_HANDLE_COUNT
];
888 for (Entry
= &GdiHandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
892 /* ignore the lock bit */
893 if ( (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
)
895 if ( (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == ObjectType
||
896 ObjectType
== GDI_OBJECT_TYPE_DONTCARE
)
898 HGDIOBJ ObjectHandle
;
900 /* Create the object handle for the entry, the lower(!) 16 bit of the
901 Type field includes the type of the object including the stock
902 object flag - but since stock objects don't have a process id we can
903 simply ignore this fact here. */
904 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
906 if (!GDIOBJ_FreeObjByHandle(ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
))
908 DPRINT1("Failed to delete object %p!\n", ObjectHandle
);
911 if (W32Process
->GDIHandleCount
== 0)
913 /* there are no more gdi handles for this process, bail */
924 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
925 * \param Process - PID of the process that will be destroyed.
928 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
930 PEPROCESS CurrentProcess
;
931 PPROCESSINFO W32Process
;
933 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
934 CurrentProcess
= PsGetCurrentProcess();
935 if (CurrentProcess
!= Process
)
937 KeAttachProcess(&Process
->Pcb
);
940 W32Process
= (PPROCESSINFO
)CurrentProcess
->Win32Process
;
942 /* Delete objects. Begin with types that are not referenced by other types */
943 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_DC_TYPE
);
944 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BRUSH_TYPE
);
945 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BITMAP_TYPE
);
947 /* Finally finish with what's left */
948 IntDeleteHandlesForProcess(Process
, GDI_OBJECT_TYPE_DONTCARE
);
950 if (CurrentProcess
!= Process
)
956 GdiDbgHTIntegrityCheck();
959 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
960 if (W32Process
->GDIHandleCount
> 0)
962 DPRINT1("Leaking %d handles!\n", W32Process
->GDIHandleCount
);
969 * Return pointer to the object by handle.
971 * \param hObj Object handle
972 * \return Pointer to the object.
974 * \note Process can only get pointer to the objects it created or global objects.
976 * \todo Get rid of the ExpectedType parameter!
978 PGDIOBJ INTERNAL_CALL
979 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
982 PGDI_TABLE_ENTRY Entry
;
983 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
985 ULONG HandleType
, HandleUpper
;
987 /* Check for dummy call */
991 GDIDBG_INITLOOPTRACE();
993 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
994 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
995 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
997 /* Check that the handle index is valid. */
998 if (HandleIndex
>= GDI_HANDLE_COUNT
)
1001 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
1003 /* Check if we have the requested type */
1004 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
1005 HandleType
!= ExpectedType
) ||
1008 DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1009 hObj
, HandleType
, ExpectedType
);
1010 GDIDBG_TRACECALLER();
1011 GDIDBG_TRACEALLOCATOR(hObj
);
1012 GDIDBG_TRACEDELETER(hObj
);
1016 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
1017 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
1019 /* Check for invalid owner. */
1020 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
1022 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj
, ProcessId
, HandleProcessId
);
1023 GDIDBG_TRACECALLER();
1024 GDIDBG_TRACEALLOCATOR(hObj
);
1029 * Prevent the thread from being terminated during the locking process.
1030 * It would result in undesired effects and inconsistency of the global
1034 KeEnterCriticalRegion();
1037 * Loop until we either successfully lock the handle entry & object or
1038 * fail some of the check.
1043 /* Lock the handle table entry. */
1044 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
1045 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
1049 if (PrevProcId
== HandleProcessId
)
1052 * We're locking an object that belongs to our process or it's a
1053 * global object if HandleProcessId is 0 here.
1056 if ( (Entry
->KernelData
!= NULL
) &&
1057 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
1059 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1060 Object
= Entry
->KernelData
;
1062 if (Object
->cExclusiveLock
== 0)
1064 Object
->Tid
= Thread
;
1065 Object
->cExclusiveLock
= 1;
1066 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj
))
1070 if (Object
->Tid
!= Thread
)
1072 /* Unlock the handle table entry. */
1073 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1078 InterlockedIncrement((PLONG
)&Object
->cExclusiveLock
);
1084 * Debugging code. Report attempts to lock deleted handles and
1085 * locking type mismatches.
1087 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
1090 /* Unlock the handle table entry. */
1091 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1098 * The handle is currently locked, wait some time and try again.
1100 GDIDBG_TRACELOOP(hObj
, PrevProcId
, NULL
);
1107 KeLeaveCriticalRegion();
1114 * Return pointer to the object by handle (and allow sharing of the handle
1117 * \param hObj Object handle
1118 * \return Pointer to the object.
1120 * \note Process can only get pointer to the objects it created or global objects.
1122 * \todo Get rid of the ExpectedType parameter!
1124 PGDIOBJ INTERNAL_CALL
1125 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
1128 PGDI_TABLE_ENTRY Entry
;
1129 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
1131 ULONG_PTR HandleType
, HandleUpper
;
1133 /* Check for dummy call */
1137 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
1138 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
1139 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
1141 /* Check that the handle index is valid. */
1142 if (HandleIndex
>= GDI_HANDLE_COUNT
)
1145 /* Check if we have the requested type */
1146 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
1147 HandleType
!= ExpectedType
) ||
1150 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1151 hObj
, HandleType
, ExpectedType
);
1155 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
1157 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
1158 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
1160 /* Check for invalid owner. */
1161 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
1167 * Prevent the thread from being terminated during the locking process.
1168 * It would result in undesired effects and inconsistency of the global
1172 KeEnterCriticalRegion();
1175 * Loop until we either successfully lock the handle entry & object or
1176 * fail some of the check.
1181 /* Lock the handle table entry. */
1182 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
1183 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
1187 if (PrevProcId
== HandleProcessId
)
1190 * We're locking an object that belongs to our process or it's a
1191 * global object if HandleProcessId is 0 here.
1194 if ( (Entry
->KernelData
!= NULL
) &&
1195 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
1197 Object
= (POBJ
)Entry
->KernelData
;
1199 GDIDBG_CAPTURESHARELOCKER(HandleIndex
);
1201 if (InterlockedIncrement((PLONG
)&Object
->ulShareCount
) == 1)
1203 memset(GDIHandleLocker
[HandleIndex
], 0x00, GDI_STACK_LEVELS
* sizeof(ULONG
));
1204 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS
, (PVOID
*)GDIHandleShareLocker
[HandleIndex
], NULL
);
1207 InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
1213 * Debugging code. Report attempts to lock deleted handles and
1214 * locking type mismatches.
1216 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
1219 /* Unlock the handle table entry. */
1220 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1227 * The handle is currently locked, wait some time and try again.
1235 KeLeaveCriticalRegion();
1241 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
1243 PGDI_TABLE_ENTRY Entry
;
1247 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1249 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1251 ProcessId
= PsGetCurrentProcessId();
1253 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1254 Ret
= Entry
->KernelData
!= NULL
&&
1255 (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0 &&
1256 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1265 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1268 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1269 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1271 PGDI_TABLE_ENTRY Entry
;
1272 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1276 GDIDBG_INITLOOPTRACE();
1281 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj
);
1283 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1285 if (!GDI_HANDLE_IS_STOCKOBJ(hObj
))
1287 ProcessId
= PsGetCurrentProcessId();
1288 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1290 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
1293 /* lock the object, we must not convert stock objects, so don't check!!! */
1294 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1295 if (PrevProcId
== ProcessId
)
1297 LONG NewType
, PrevType
, OldType
;
1299 /* we're locking an object that belongs to our process. First calculate
1300 the new object type including the stock object flag and then try to
1302 /* On Windows the higher 16 bit of the type field don't contain the
1303 full type from the handle, but the base type.
1304 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1305 OldType
= ((ULONG
)hObj
& GDI_HANDLE_BASETYPE_MASK
) | ((ULONG
)hObj
>> GDI_ENTRY_UPPER_SHIFT
);
1306 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1307 we copy them as we can't get them from the handle */
1308 OldType
|= Entry
->Type
& GDI_ENTRY_FLAGS_MASK
;
1310 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1311 NewType
= OldType
| GDI_ENTRY_STOCK_MASK
;
1313 /* Try to exchange the type field - but only if the old (previous type) matches! */
1314 PrevType
= InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1315 if (PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1317 PTHREADINFO PrevThread
;
1320 /* We successfully set the stock object flag.
1321 KernelData should never be NULL here!!! */
1322 ASSERT(Entry
->KernelData
);
1324 Object
= Entry
->KernelData
;
1326 PrevThread
= Object
->Tid
;
1327 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1329 /* dereference the process' object counter */
1330 if (PrevProcId
!= GDI_GLOBAL_PROCESS
)
1332 PEPROCESS OldProcess
;
1333 PPROCESSINFO W32Process
;
1337 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1338 if (NT_SUCCESS(Status
))
1340 W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
1341 if (W32Process
!= NULL
)
1343 InterlockedDecrement(&W32Process
->GDIHandleCount
);
1345 ObDereferenceObject(OldProcess
);
1349 hObj
= (HGDIOBJ
)((ULONG
)(hObj
) | GDI_HANDLE_STOCK_MASK
);
1351 Object
->hHmgr
= hObj
;
1353 /* remove the process id lock and make it global */
1354 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1356 /* we're done, successfully converted the object */
1361 GDIDBG_TRACELOOP(hObj
, PrevThread
, Thread
);
1363 /* WTF?! The object is already locked by a different thread!
1364 Release the lock, wait a bit and try again!
1365 FIXME - we should give up after some time unless we want to wait forever! */
1366 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1374 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1375 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType
, Entry
->Type
, NewType
, Entry
->KernelData
);
1378 else if (PrevProcId
== LockedProcessId
)
1380 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
1382 /* the object is currently locked, wait some time and try again.
1383 FIXME - we shouldn't loop forever! Give up after some time! */
1390 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1398 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1400 PGDI_TABLE_ENTRY Entry
;
1401 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1405 GDIDBG_INITLOOPTRACE();
1407 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1409 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1411 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1413 ProcessId
= PsGetCurrentProcessId();
1414 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1416 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1419 /* lock the object, we must not convert stock objects, so don't check!!! */
1420 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1421 if (PrevProcId
== ProcessId
)
1423 PTHREADINFO PrevThread
;
1425 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1427 POBJ Object
= Entry
->KernelData
;
1429 PrevThread
= Object
->Tid
;
1430 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1432 PEPROCESS OldProcess
;
1433 PPROCESSINFO W32Process
;
1436 if (NewOwner
!= NULL
)
1438 ProcessId
= PsGetProcessId(NewOwner
);
1443 if((ULONG_PTR
)ProcessId
== ((ULONG_PTR
)PrevProcId
& ~0x1))
1445 DPRINT("Setting same process than previous one, nothing to do\n");
1449 /* dereference the process' object counter */
1451 if ((ULONG_PTR
)PrevProcId
& ~0x1)
1453 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1454 if (NT_SUCCESS(Status
))
1456 W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
1457 if (W32Process
!= NULL
)
1459 InterlockedDecrement(&W32Process
->GDIHandleCount
);
1461 ObDereferenceObject(OldProcess
);
1465 if (NewOwner
!= NULL
)
1467 /* Increase the new process' object counter */
1468 W32Process
= (PPROCESSINFO
)NewOwner
->Win32Process
;
1469 if (W32Process
!= NULL
)
1471 InterlockedIncrement(&W32Process
->GDIHandleCount
);
1476 /* remove the process id lock and change it to the new process id */
1477 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
);
1484 GDIDBG_TRACELOOP(ObjectHandle
, PrevThread
, Thread
);
1486 /* WTF?! The object is already locked by a different thread!
1487 Release the lock, wait a bit and try again! DO reset the pid lock
1488 so we make sure we don't access invalid memory in case the object is
1489 being deleted in the meantime (because we don't have aquired a reference
1491 FIXME - we should give up after some time unless we want to wait forever! */
1492 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1500 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1501 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry
->Type
, Entry
->KernelData
);
1505 else if (PrevProcId
== LockedProcessId
)
1507 GDIDBG_TRACELOOP(ObjectHandle
, PrevProcId
, ProcessId
);
1509 /* the object is currently locked, wait some time and try again.
1510 FIXME - we shouldn't loop forever! Give up after some time! */
1515 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1517 /* allow changing ownership of global objects */
1519 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1522 else if ((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1524 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1529 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1537 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1539 PGDI_TABLE_ENTRY FromEntry
;
1541 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1544 GDIDBG_INITLOOPTRACE();
1546 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1548 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1550 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1552 FromEntry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, CopyFrom
);
1554 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1555 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1558 /* lock the object, we must not convert stock objects, so don't check!!! */
1559 FromPrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1560 if (FromPrevProcId
== FromProcessId
)
1562 PTHREADINFO PrevThread
;
1565 if ((FromEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1567 Object
= FromEntry
->KernelData
;
1569 /* save the pointer to the calling thread so we know it was this thread
1570 that locked the object */
1571 PrevThread
= Object
->Tid
;
1572 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1574 /* now let's change the ownership of the target object */
1576 if (((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1578 PEPROCESS ProcessTo
;
1580 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1582 GDIOBJ_SetOwnership(CopyTo
, ProcessTo
);
1583 ObDereferenceObject(ProcessTo
);
1588 /* mark the object as global */
1589 GDIOBJ_SetOwnership(CopyTo
, NULL
);
1592 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1596 GDIDBG_TRACELOOP(CopyFrom
, PrevThread
, Thread
);
1598 /* WTF?! The object is already locked by a different thread!
1599 Release the lock, wait a bit and try again! DO reset the pid lock
1600 so we make sure we don't access invalid memory in case the object is
1601 being deleted in the meantime (because we don't have aquired a reference
1603 FIXME - we should give up after some time unless we want to wait forever! */
1604 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1607 goto LockHandleFrom
;
1612 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1616 else if (FromPrevProcId
== FromLockedProcessId
)
1618 GDIDBG_TRACELOOP(CopyFrom
, FromPrevProcId
, FromProcessId
);
1620 /* the object is currently locked, wait some time and try again.
1621 FIXME - we shouldn't loop forever! Give up after some time! */
1624 goto LockHandleFrom
;
1626 else if ((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1628 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1629 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1630 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1631 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1632 goto LockHandleFrom
;
1636 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1644 GDI_MapHandleTable(PSECTION_OBJECT SectionObject
, PEPROCESS Process
)
1646 PVOID MappedView
= NULL
;
1648 LARGE_INTEGER Offset
;
1649 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1651 Offset
.QuadPart
= 0;
1653 ASSERT(SectionObject
!= NULL
);
1654 ASSERT(Process
!= NULL
);
1656 Status
= MmMapViewOfSection(SectionObject
,
1667 if (!NT_SUCCESS(Status
))
1673 /* Locks 2 or 3 objects at a time */
1676 GDIOBJ_LockMultipleObjs(ULONG ulCount
,
1680 UINT auiIndices
[3] = {0,1,2};
1682 BOOL bUnsorted
= TRUE
;
1684 /* First is greatest */
1688 for(i
=1; i
<ulCount
; i
++)
1690 if((ULONG_PTR
)ahObj
[auiIndices
[i
-1]] < (ULONG_PTR
)ahObj
[auiIndices
[i
]])
1692 tmp
= auiIndices
[i
-1];
1693 auiIndices
[i
-1] = auiIndices
[i
];
1694 auiIndices
[i
] = tmp
;
1700 for(i
=0;i
<ulCount
;i
++)
1701 apObj
[auiIndices
[i
]] = GDIOBJ_LockObj(ahObj
[auiIndices
[i
]], GDI_OBJECT_TYPE_DONTCARE
);
1705 /** PUBLIC FUNCTIONS **********************************************************/
1709 IntGdiSetRegionOwner(HRGN hRgn
, DWORD OwnerMask
)
1712 PGDI_TABLE_ENTRY Entry
;
1715 These regions do not use attribute sections and when allocated, use gdiobj
1718 // FIXME! HAX!!! Remove this once we get everything right!
1719 Index
= GDI_HANDLE_GET_INDEX(hRgn
);
1720 Entry
= &GdiHandleTable
->Entries
[Index
];
1721 if (Entry
->UserData
) FreeObjectAttr(Entry
->UserData
);
1722 Entry
->UserData
= NULL
;
1724 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1726 return GDIOBJ_SetOwnership(hRgn
, NULL
);
1728 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1730 return GDIOBJ_SetOwnership((HGDIOBJ
) hRgn
, PsGetCurrentProcess() );
1737 IntGdiSetBrushOwner(PBRUSH pbr
, DWORD OwnerMask
)
1740 PEPROCESS Owner
= NULL
;
1741 PGDI_TABLE_ENTRY pEntry
= NULL
;
1743 if (!pbr
) return FALSE
;
1745 hBR
= pbr
->BaseObject
.hHmgr
;
1747 if (!hBR
|| (GDI_HANDLE_GET_TYPE(hBR
) != GDI_OBJECT_TYPE_BRUSH
))
1751 INT Index
= GDI_HANDLE_GET_INDEX((HGDIOBJ
)hBR
);
1752 pEntry
= &GdiHandleTable
->Entries
[Index
];
1755 if (pbr
->flAttrs
& GDIBRUSH_IS_GLOBAL
)
1757 GDIOBJ_ShareUnlockObjByPtr((POBJ
)pbr
);
1761 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1763 // Set this Brush to inaccessible mode and to an Owner of NONE.
1764 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1766 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, Owner
))
1769 // Deny user access to User Data.
1770 pEntry
->UserData
= NULL
; // This hBR is inaccessible!
1773 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1775 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, PsGetCurrentProcess() ))
1778 // Allow user access to User Data.
1779 pEntry
->UserData
= pbr
->pBrushAttr
;
1786 IntGdiSetDCOwnerEx( HDC hDC
, DWORD OwnerMask
, BOOL NoSetBrush
)
1791 if (!hDC
|| (GDI_HANDLE_GET_TYPE(hDC
) != GDI_OBJECT_TYPE_DC
)) return FALSE
;
1793 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1795 pDC
= DC_LockDc ( hDC
);
1796 MmCopyFromCaller(&pDC
->dcattr
, pDC
->pdcattr
, sizeof(DC_ATTR
));
1797 DC_vFreeDcAttr(pDC
);
1800 if (!DC_SetOwnership( hDC
, NULL
)) // This hDC is inaccessible!
1804 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1806 pDC
= DC_LockDc ( hDC
);
1807 ASSERT(pDC
->pdcattr
== &pDC
->dcattr
);
1810 if (!DC_SetOwnership( hDC
, PsGetCurrentProcess() )) return Ret
;
1812 DC_AllocateDcAttr( hDC
); // Allocate new dcattr
1814 DCU_SynchDcAttrtoUser( hDC
); // Copy data from dc to dcattr
1817 if ((OwnerMask
!= GDI_OBJ_HMGR_NONE
) && !NoSetBrush
)
1819 pDC
= DC_LockDc ( hDC
);
1820 if (IntGdiSetBrushOwner((PBRUSH
)pDC
->dclevel
.pbrFill
, OwnerMask
))
1821 IntGdiSetBrushOwner((PBRUSH
)pDC
->dclevel
.pbrLine
, OwnerMask
);
1829 GreGetObjectOwner(HGDIOBJ Handle
, GDIOBJTYPE ObjType
)
1831 INT Ret
= GDI_OBJ_HMGR_RESTRICTED
;
1833 if ( GDI_HANDLE_GET_INDEX(Handle
) < GDI_HANDLE_COUNT
)
1835 PGDI_TABLE_ENTRY pEntry
= &GdiHandleTable
->Entries
[GDI_HANDLE_GET_INDEX(Handle
)];
1837 if (pEntry
->ObjectType
== ObjType
)
1839 if (pEntry
->FullUnique
== (GDI_HANDLE_GET_UPPER(Handle
) >> GDI_ENTRY_UPPER_SHIFT
))
1840 Ret
= pEntry
->ProcessId
& ~1;
1849 NtGdiCreateClientObj(
1856 /* Mask out everything that would change the type in a wrong manner */
1857 ulType
&= (GDI_HANDLE_TYPE_MASK
& ~GDI_HANDLE_BASETYPE_MASK
);
1859 /* Allocate a new object */
1860 pObject
= GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ
| ulType
);
1866 /* get the handle */
1867 handle
= pObject
->hHmgr
;
1870 GDIOBJ_UnlockObjByPtr(pObject
);
1878 NtGdiDeleteClientObj(
1882 /* We first need to get the real type from the handle */
1883 ULONG type
= GDI_HANDLE_GET_TYPE(h
);
1885 /* Check if it's really a CLIENTOBJ */
1886 if ((type
& GDI_HANDLE_BASETYPE_MASK
) != GDILoObjType_LO_CLIENTOBJ_TYPE
)
1888 /* FIXME: SetLastError? */
1891 return GDIOBJ_FreeObjByHandle(h
, type
);
1896 IntGdiGetObject(IN HANDLE Handle
,
1904 pGdiObject
= GDIOBJ_LockObj(Handle
, GDI_OBJECT_TYPE_DONTCARE
);
1907 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1911 dwObjectType
= GDIOBJ_GetObjectType(Handle
);
1912 switch (dwObjectType
)
1914 case GDI_OBJECT_TYPE_PEN
:
1915 case GDI_OBJECT_TYPE_EXTPEN
:
1916 Result
= PEN_GetObject((PBRUSH
) pGdiObject
, cbCount
, (PLOGPEN
) lpBuffer
); // IntGdiCreatePenIndirect
1919 case GDI_OBJECT_TYPE_BRUSH
:
1920 Result
= BRUSH_GetObject((PBRUSH
) pGdiObject
, cbCount
, (LPLOGBRUSH
)lpBuffer
);
1923 case GDI_OBJECT_TYPE_BITMAP
:
1924 Result
= BITMAP_GetObject((SURFACE
*) pGdiObject
, cbCount
, lpBuffer
);
1926 case GDI_OBJECT_TYPE_FONT
:
1927 Result
= FontGetObject((PTEXTOBJ
) pGdiObject
, cbCount
, lpBuffer
);
1929 // Fix the LOGFONT structure for the stock fonts
1930 if (FIRST_STOCK_HANDLE
<= Handle
&& Handle
<= LAST_STOCK_HANDLE
)
1932 FixStockFontSizeW(Handle
, cbCount
, lpBuffer
);
1937 case GDI_OBJECT_TYPE_PALETTE
:
1938 Result
= PALETTE_GetObject((PPALETTE
) pGdiObject
, cbCount
, lpBuffer
);
1942 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType
);
1946 GDIOBJ_UnlockObjByPtr(pGdiObject
);
1956 NtGdiExtGetObjectW(IN HANDLE hGdiObj
,
1958 OUT LPVOID lpBuffer
)
1965 DIBSECTION dibsection
;
1969 EXTLOGFONTW extlogfontw
;
1970 ENUMLOGFONTEXDVW enumlogfontexdvw
;
1973 // Normalize to the largest supported object size
1974 cbCount
= min((UINT
)cbCount
, sizeof(Object
));
1976 // Now do the actual call
1977 iRetCount
= IntGdiGetObject(hGdiObj
, cbCount
, lpBuffer
? &Object
: NULL
);
1978 cbCopyCount
= min((UINT
)cbCount
, (UINT
)iRetCount
);
1980 // Make sure we have a buffer and a copy size
1981 if ((cbCopyCount
) && (lpBuffer
))
1983 // Enter SEH for buffer transfer
1986 // Probe the buffer and copy it
1987 ProbeForWrite(lpBuffer
, cbCopyCount
, sizeof(WORD
));
1988 RtlCopyMemory(lpBuffer
, &Object
, cbCopyCount
);
1990 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1992 // Clear the return value.
1993 // Do *NOT* set last error here!