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)
33 /* static */ /* FIXME: -fno-unit-at-a-time breaks this */
34 BOOL INTERNAL_CALL
GDI_CleanupDummy(PVOID ObjectBody
);
36 /** GLOBALS *******************************************************************/
43 GDICLEANUPPROC CleanupProc
;
44 } OBJ_TYPE_INFO
, *POBJ_TYPE_INFO
;
47 OBJ_TYPE_INFO ObjTypeInfo
[BASE_OBJTYPE_COUNT
] =
49 {0, 0, 0, NULL
}, /* 00 reserved entry */
50 {1, sizeof(DC
), TAG_DC
, DC_Cleanup
}, /* 01 DC */
51 {1, 0, 0, NULL
}, /* 02 UNUSED1 */
52 {1, 0, 0, NULL
}, /* 03 UNUSED2 */
53 {1, sizeof(ROSRGNDATA
), TAG_REGION
, REGION_Cleanup
}, /* 04 RGN */
54 {1, sizeof(SURFACE
), TAG_SURFACE
, SURFACE_Cleanup
}, /* 05 SURFACE */
55 {1, sizeof(CLIENTOBJ
), TAG_CLIENTOBJ
, GDI_CleanupDummy
}, /* 06 CLIENTOBJ: METADC,... */
56 {1, sizeof(PATH
), TAG_PATH
, GDI_CleanupDummy
}, /* 07 PATH */
57 {1, sizeof(PALETTE
), TAG_PALETTE
, PALETTE_Cleanup
}, /* 08 PAL */
58 {1, sizeof(COLORSPACE
), TAG_ICMLCS
, GDI_CleanupDummy
}, /* 09 ICMLCS, */
59 {1, sizeof(TEXTOBJ
), TAG_LFONT
, GDI_CleanupDummy
}, /* 0a LFONT */
60 {0, 0, TAG_RFONT
, NULL
}, /* 0b RFONT, unused */
61 {0, 0, TAG_PFE
, NULL
}, /* 0c PFE, unused */
62 {0, 0, TAG_PFT
, NULL
}, /* 0d PFT, unused */
63 {0, sizeof(GDICLRXFORM
), TAG_ICMCXF
, GDI_CleanupDummy
}, /* 0e ICMCXF, */
64 {0, 0, TAG_SPRITE
, NULL
}, /* 0f SPRITE, unused */
65 {1, sizeof(BRUSH
), TAG_BRUSH
, BRUSH_Cleanup
}, /* 10 BRUSH, PEN, EXTPEN */
66 {0, 0, TAG_UMPD
, NULL
}, /* 11 UMPD, unused */
67 {0, 0, 0, NULL
}, /* 12 UNUSED4 */
68 {0, 0, TAG_SPACE
, NULL
}, /* 13 SPACE, unused */
69 {0, 0, 0, NULL
}, /* 14 UNUSED5 */
70 {0, 0, TAG_META
, NULL
}, /* 15 META, unused */
71 {0, 0, TAG_EFSTATE
, NULL
}, /* 16 EFSTATE, unused */
72 {0, 0, TAG_BMFD
, NULL
}, /* 17 BMFD, unused */
73 {0, 0, TAG_VTFD
, NULL
}, /* 18 VTFD, unused */
74 {0, 0, TAG_TTFD
, NULL
}, /* 19 TTFD, unused */
75 {0, 0, TAG_RC
, NULL
}, /* 1a RC, unused */
76 {0, 0, TAG_TEMP
, NULL
}, /* 1b TEMP, unused */
77 {0, sizeof(EDRIVEROBJ
), TAG_DRVOBJ
, DRIVEROBJ_Cleanup
},/* 1c DRVOBJ */
78 {0, 0, TAG_DCIOBJ
, NULL
}, /* 1d DCIOBJ, unused */
79 {0, 0, TAG_SPOOL
, NULL
}, /* 1e SPOOL, unused */
80 {0, 0, 0, NULL
}, /* 1f reserved entry */
83 static LARGE_INTEGER ShortDelay
;
85 /** INTERNAL FUNCTIONS ********************************************************/
88 * Dummy GDI Cleanup Callback
90 /* static */ /* FIXME: -fno-unit-at-a-time breaks this */
92 GDI_CleanupDummy(PVOID ObjectBody
)
98 * Allocate GDI object table.
99 * \param Size - number of entries in the object table.
101 PGDI_HANDLE_TABLE INTERNAL_CALL
102 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT
*SectionObject
)
104 PGDI_HANDLE_TABLE HandleTable
= NULL
;
105 LARGE_INTEGER htSize
;
110 ASSERT(SectionObject
!= NULL
);
112 htSize
.QuadPart
= sizeof(GDI_HANDLE_TABLE
);
114 Status
= MmCreateSection((PVOID
*)SectionObject
,
122 if (!NT_SUCCESS(Status
))
125 /* FIXME - use MmMapViewInSessionSpace once available! */
126 Status
= MmMapViewInSystemSpace(*SectionObject
,
127 (PVOID
*)&HandleTable
,
129 if (!NT_SUCCESS(Status
))
131 ObDereferenceObject(*SectionObject
);
132 *SectionObject
= NULL
;
136 RtlZeroMemory(HandleTable
, sizeof(GDI_HANDLE_TABLE
));
138 HandleTable
->LookasideLists
= ExAllocatePoolWithTag(NonPagedPool
,
139 BASE_OBJTYPE_COUNT
* sizeof(PAGED_LOOKASIDE_LIST
),
141 if (HandleTable
->LookasideLists
== NULL
)
143 MmUnmapViewInSystemSpace(HandleTable
);
144 ObDereferenceObject(*SectionObject
);
145 *SectionObject
= NULL
;
149 for (ObjType
= 0; ObjType
< BASE_OBJTYPE_COUNT
; ObjType
++)
151 if (ObjTypeInfo
[ObjType
].bUseLookaside
)
153 ExInitializePagedLookasideList(HandleTable
->LookasideLists
+ ObjType
,
157 ObjTypeInfo
[ObjType
].ulBodySize
,
158 ObjTypeInfo
[ObjType
].Tag
,
163 ShortDelay
.QuadPart
= -5000LL; /* FIXME - 0.5 ms? */
165 HandleTable
->FirstFree
= 0;
166 HandleTable
->FirstUnused
= RESERVE_ENTRIES_COUNT
;
172 LockErrorDebugOutput(HGDIOBJ hObj
, PGDI_TABLE_ENTRY Entry
, LPSTR Function
)
174 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
176 DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function
, hObj
);
177 GDIDBG_TRACEDELETER(hObj
);
179 else if (GDI_HANDLE_GET_REUSECNT(hObj
) != GDI_ENTRY_GET_REUSECNT(Entry
->Type
))
181 DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
182 Function
, hObj
, GDI_HANDLE_GET_REUSECNT(hObj
), GDI_ENTRY_GET_REUSECNT(Entry
->Type
));
184 else if (GDI_HANDLE_GET_TYPE(hObj
) != ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
))
186 DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
187 Function
, hObj
, GDI_HANDLE_GET_TYPE(hObj
), (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
);
191 DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
192 Function
, hObj
, Entry
->Type
);
194 GDIDBG_TRACECALLER();
199 InterlockedPopFreeEntry(VOID
)
201 ULONG idxFirst
, idxNext
, idxPrev
;
202 PGDI_TABLE_ENTRY pEntry
;
205 DPRINT("Enter InterLockedPopFreeEntry\n");
209 idxFirst
= GdiHandleTable
->FirstFree
;
213 /* Increment FirstUnused and get the new index */
214 idxFirst
= InterlockedIncrement((LONG
*)&GdiHandleTable
->FirstUnused
) - 1;
216 /* Check if we have entries left */
217 if (idxFirst
>= GDI_HANDLE_COUNT
)
219 DPRINT1("No more gdi handles left!\n");
223 /* Return the old index */
227 /* Get a pointer to the first free entry */
228 pEntry
= GdiHandleTable
->Entries
+ idxFirst
;
230 /* Try to lock the entry */
231 PrevProcId
= InterlockedCompareExchange((LONG
*)&pEntry
->ProcessId
, 1, 0);
234 /* The entry was locked or not free, wait and start over */
239 /* Sanity check: is entry really free? */
240 ASSERT(((ULONG_PTR
)pEntry
->KernelData
& ~GDI_HANDLE_INDEX_MASK
) == 0);
242 /* Try to exchange the FirstFree value */
243 idxNext
= (ULONG_PTR
)pEntry
->KernelData
;
244 idxPrev
= InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
,
248 /* Unlock the free entry */
249 (void)InterlockedExchange((LONG
*)&pEntry
->ProcessId
, 0);
251 /* If we succeeded, break out of the loop */
252 if (idxPrev
== idxFirst
)
261 /* Pushes an entry of the handle table to the free list,
262 The entry must be unlocked and the base type field must be 0 */
265 InterlockedPushFreeEntry(ULONG idxToFree
)
267 ULONG idxFirstFree
, idxPrev
;
268 PGDI_TABLE_ENTRY pFreeEntry
;
270 DPRINT("Enter InterlockedPushFreeEntry\n");
272 pFreeEntry
= GdiHandleTable
->Entries
+ idxToFree
;
273 ASSERT((pFreeEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0);
274 ASSERT(pFreeEntry
->ProcessId
== 0);
275 pFreeEntry
->UserData
= NULL
;
279 idxFirstFree
= GdiHandleTable
->FirstFree
;
280 pFreeEntry
->KernelData
= (PVOID
)(ULONG_PTR
)idxFirstFree
;
282 idxPrev
= InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
,
286 while (idxPrev
!= idxFirstFree
);
292 GDIOBJ_ValidateHandle(HGDIOBJ hObj
, ULONG ObjectType
)
294 PGDI_TABLE_ENTRY Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
295 if ((((ULONG_PTR
)hObj
& GDI_HANDLE_TYPE_MASK
) == ObjectType
) &&
296 (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == GDI_HANDLE_GET_UPPER(hObj
))
298 HANDLE pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
299 if (pid
== NULL
|| pid
== PsGetCurrentProcessId())
308 GDIOBJ_AllocObj(UCHAR BaseType
)
312 ASSERT((BaseType
& ~GDIObjTypeTotal
) == 0);
313 // BaseType &= GDI_HANDLE_BASETYPE_MASK;
315 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
317 PPAGED_LOOKASIDE_LIST LookasideList
;
319 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
320 pObject
= ExAllocateFromPagedLookasideList(LookasideList
);
324 pObject
= ExAllocatePoolWithTag(PagedPool
,
325 ObjTypeInfo
[BaseType
].ulBodySize
,
326 ObjTypeInfo
[BaseType
].Tag
);
331 RtlZeroMemory(pObject
, ObjTypeInfo
[BaseType
].ulBodySize
);
339 * Allocate memory for GDI object and return handle to it.
341 * \param ObjectType - type of object \ref GDI object types
343 * \return Pointer to the allocated object, which is locked.
346 GDIOBJ_AllocObjWithHandle(ULONG ObjectType
)
348 PPROCESSINFO W32Process
;
349 POBJ newObject
= NULL
;
350 HANDLE CurrentProcessId
, LockedProcessId
;
353 PGDI_TABLE_ENTRY Entry
;
356 GDIDBG_INITLOOPTRACE();
358 W32Process
= PsGetCurrentProcessWin32Process();
359 /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
360 to take too many GDI objects, itself. */
361 if (W32Process
&& W32Process
->GDIHandleCount
>= 0x2710)
363 DPRINT1("Too many objects for process!!!\n");
364 GDIDBG_DUMPHANDLETABLE();
368 ASSERT(ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
);
370 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(ObjectType
);
372 newObject
= GDIOBJ_AllocObj(TypeIndex
);
375 DPRINT1("Not enough memory to allocate gdi object!\n");
379 CurrentProcessId
= PsGetCurrentProcessId();
380 LockedProcessId
= (HANDLE
)((ULONG_PTR
)CurrentProcessId
| 0x1);
382 // RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
384 /* On Windows the higher 16 bit of the type field don't contain the
385 full type from the handle, but the base type.
386 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
387 TypeInfo
= (ObjectType
& GDI_HANDLE_BASETYPE_MASK
) | (ObjectType
>> GDI_ENTRY_UPPER_SHIFT
);
389 Index
= InterlockedPopFreeEntry();
394 Entry
= &GdiHandleTable
->Entries
[Index
];
397 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, 0);
398 if (PrevProcId
== NULL
)
400 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
403 Entry
->KernelData
= newObject
;
405 /* copy the reuse-counter */
406 TypeInfo
|= Entry
->Type
& GDI_ENTRY_REUSE_MASK
;
408 /* we found a free entry, no need to exchange this field atomically
409 since we're holding the lock */
410 Entry
->Type
= TypeInfo
;
412 /* Create a handle */
413 Handle
= (HGDIOBJ
)((Index
& 0xFFFF) | (TypeInfo
<< GDI_ENTRY_UPPER_SHIFT
));
415 /* Initialize BaseObject fields */
416 newObject
->hHmgr
= Handle
;
417 newObject
->ulShareCount
= 0;
418 newObject
->cExclusiveLock
= 1;
419 newObject
->Tid
= Thread
;
421 /* unlock the entry */
422 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, CurrentProcessId
);
424 GDIDBG_CAPTUREALLOCATOR(Index
);
426 if (W32Process
!= NULL
)
428 InterlockedIncrement(&W32Process
->GDIHandleCount
);
431 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle
, newObject
);
436 GDIDBG_TRACELOOP(Index
, PrevProcId
, CurrentProcessId
);
437 /* damn, someone is trying to lock the object even though it doesn't
438 even exist anymore, wait a little and try again!
439 FIXME - we shouldn't loop forever! Give up after some time! */
446 GDIOBJ_FreeObj(newObject
, TypeIndex
);
448 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
449 GDIDBG_DUMPHANDLETABLE();
456 GDIOBJ_FreeObj(POBJ pObject
, UCHAR BaseType
)
458 /* Object must not have a handle! */
459 ASSERT(pObject
->hHmgr
== NULL
);
461 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
463 PPAGED_LOOKASIDE_LIST LookasideList
;
465 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
466 ExFreeToPagedLookasideList(LookasideList
, pObject
);
475 * Free memory allocated for the GDI object. For each object type this function calls the
476 * appropriate cleanup routine.
478 * \param hObj - handle of the object to be deleted.
480 * \return Returns TRUE if succesful.
481 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
482 * to the calling process.
484 * \bug This function should return VOID and kill the object no matter what...
487 GDIOBJ_FreeObjByHandle(HGDIOBJ hObj
, DWORD ExpectedType
)
489 PGDI_TABLE_ENTRY Entry
;
490 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
491 ULONG HandleType
, HandleUpper
, TypeIndex
;
494 GDIDBG_INITLOOPTRACE();
496 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj
);
498 if (GDI_HANDLE_IS_STOCKOBJ(hObj
))
500 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj
);
501 GDIDBG_TRACECALLER();
505 ProcessId
= PsGetCurrentProcessId();
506 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
508 Silent
= (ExpectedType
& GDI_OBJECT_TYPE_SILENT
);
509 ExpectedType
&= ~GDI_OBJECT_TYPE_SILENT
;
511 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
512 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
514 /* Check if we have the requested type */
515 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
516 HandleType
!= ExpectedType
) ||
519 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
520 hObj
, HandleType
, ExpectedType
);
521 GDIDBG_TRACECALLER();
525 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
528 /* lock the object, we must not delete global objects, so don't exchange the locking
529 process ID to zero when attempting to lock a global object... */
530 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
531 if (PrevProcId
== ProcessId
)
533 if ( (Entry
->KernelData
!= NULL
) &&
534 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) &&
535 ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == (HandleUpper
& GDI_ENTRY_BASETYPE_MASK
)) )
539 Object
= Entry
->KernelData
;
541 if ((Object
->cExclusiveLock
== 0 ||
542 Object
->Tid
== (PTHREADINFO
)PsGetCurrentThreadWin32Thread()) &&
543 Object
->ulShareCount
== 0)
546 PPROCESSINFO W32Process
= PsGetCurrentProcessWin32Process();
548 /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
549 Entry
->Type
= (Entry
->Type
+ GDI_ENTRY_REUSE_INC
) & ~GDI_ENTRY_BASETYPE_MASK
;
551 /* unlock the handle slot */
552 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
554 /* push this entry to the free list */
555 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable
, Entry
));
557 Object
->hHmgr
= NULL
;
559 if (W32Process
!= NULL
)
561 InterlockedDecrement(&W32Process
->GDIHandleCount
);
564 /* call the cleanup routine. */
565 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(HandleType
);
566 Ret
= ObjTypeInfo
[TypeIndex
].CleanupProc(Object
);
568 /* Now it's time to free the memory */
569 GDIOBJ_FreeObj(Object
, TypeIndex
);
571 GDIDBG_CAPTUREDELETER(hObj
);
574 else if (Object
->ulShareCount
!= 0)
576 Object
->BaseFlags
|= BASEFLAG_READY_TO_DIE
;
577 DPRINT("Object %p, ulShareCount = %d\n", Object
->hHmgr
, Object
->ulShareCount
);
578 //GDIDBG_TRACECALLER();
579 //GDIDBG_TRACESHARELOCKER(GDI_HANDLE_GET_INDEX(hObj));
580 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
581 /* Don't wait on shared locks */
587 * The object is currently locked by another thread, so freeing is forbidden!
589 DPRINT1("Object->cExclusiveLock = %d\n", Object
->cExclusiveLock
);
590 GDIDBG_TRACECALLER();
591 GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj
));
592 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
593 /* do not assert here for it will call again from dxg.sys it being call twice */
601 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
602 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
605 else if (PrevProcId
== LockedProcessId
)
607 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
609 /* the object is currently locked, wait some time and try again.
610 FIXME - we shouldn't loop forever! Give up after some time! */
619 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
621 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj
);
623 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
625 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
629 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);
631 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry
->Type
, Entry
->KernelData
, Entry
->ProcessId
);
632 GDIDBG_TRACECALLER();
633 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
642 IsObjectDead(HGDIOBJ hObject
)
644 INT Index
= GDI_HANDLE_GET_INDEX(hObject
);
645 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
646 // We check to see if the objects are knocking on deaths door.
647 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
651 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject
);
652 return TRUE
; // return true and move on.
659 * \param hObject object handle
660 * \return if the function fails the returned value is FALSE.
664 GreDeleteObject(HGDIOBJ hObject
)
666 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
667 if (!IsObjectDead(hObject
))
669 return NULL
!= hObject
670 ? GDIOBJ_FreeObjByHandle(hObject
, GDI_OBJECT_TYPE_DONTCARE
) : FALSE
;
674 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject
);
675 return TRUE
; // return true and move on.
681 IntDeleteHandlesForProcess(struct _EPROCESS
*Process
, ULONG ObjectType
)
683 PGDI_TABLE_ENTRY Entry
, End
;
684 ULONG Index
= RESERVE_ENTRIES_COUNT
;
686 PPROCESSINFO W32Process
;
688 W32Process
= (PPROCESSINFO
)Process
->Win32Process
;
691 if (W32Process
->GDIHandleCount
> 0)
693 ProcId
= Process
->UniqueProcessId
;
695 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
696 we should delete it directly here! */
698 End
= &GdiHandleTable
->Entries
[GDI_HANDLE_COUNT
];
699 for (Entry
= &GdiHandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
703 /* ignore the lock bit */
704 if ( (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
)
706 if ( (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == ObjectType
||
707 ObjectType
== GDI_OBJECT_TYPE_DONTCARE
)
709 HGDIOBJ ObjectHandle
;
711 /* Create the object handle for the entry, the lower(!) 16 bit of the
712 Type field includes the type of the object including the stock
713 object flag - but since stock objects don't have a process id we can
714 simply ignore this fact here. */
715 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
717 if (!GDIOBJ_FreeObjByHandle(ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
))
719 DPRINT1("Failed to delete object %p!\n", ObjectHandle
);
722 if (W32Process
->GDIHandleCount
== 0)
724 /* there are no more gdi handles for this process, bail */
735 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
736 * \param Process - PID of the process that will be destroyed.
739 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
741 PEPROCESS CurrentProcess
;
742 PPROCESSINFO W32Process
;
744 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
745 CurrentProcess
= PsGetCurrentProcess();
746 if (CurrentProcess
!= Process
)
748 KeAttachProcess(&Process
->Pcb
);
751 W32Process
= (PPROCESSINFO
)CurrentProcess
->Win32Process
;
753 /* Delete objects. Begin with types that are not referenced by other types */
754 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_DC_TYPE
);
755 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BRUSH_TYPE
);
756 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BITMAP_TYPE
);
758 /* Finally finish with what's left */
759 IntDeleteHandlesForProcess(Process
, GDI_OBJECT_TYPE_DONTCARE
);
761 if (CurrentProcess
!= Process
)
767 GdiDbgHTIntegrityCheck();
770 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
771 if (W32Process
->GDIHandleCount
> 0)
773 DPRINT1("Leaking %d handles!\n", W32Process
->GDIHandleCount
);
780 * Return pointer to the object by handle.
782 * \param hObj Object handle
783 * \return Pointer to the object.
785 * \note Process can only get pointer to the objects it created or global objects.
787 * \todo Get rid of the ExpectedType parameter!
789 PGDIOBJ INTERNAL_CALL
790 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
793 PGDI_TABLE_ENTRY Entry
;
794 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
796 ULONG HandleType
, HandleUpper
;
798 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
799 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
800 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
802 /* Check that the handle index is valid. */
803 if (HandleIndex
>= GDI_HANDLE_COUNT
)
806 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
808 /* Check if we have the requested type */
809 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
810 HandleType
!= ExpectedType
) ||
813 DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
814 hObj
, HandleType
, ExpectedType
);
815 GDIDBG_TRACECALLER();
816 GDIDBG_TRACEALLOCATOR(hObj
);
817 GDIDBG_TRACEDELETER(hObj
);
821 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
822 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
824 /* Check for invalid owner. */
825 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
827 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj
, ProcessId
, HandleProcessId
);
828 GDIDBG_TRACECALLER();
829 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
834 * Prevent the thread from being terminated during the locking process.
835 * It would result in undesired effects and inconsistency of the global
839 KeEnterCriticalRegion();
842 * Loop until we either successfully lock the handle entry & object or
843 * fail some of the check.
848 /* Lock the handle table entry. */
849 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
850 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
854 if (PrevProcId
== HandleProcessId
)
857 * We're locking an object that belongs to our process or it's a
858 * global object if HandleProcessId is 0 here.
861 if ( (Entry
->KernelData
!= NULL
) &&
862 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
864 PTHREADINFO Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
865 Object
= Entry
->KernelData
;
867 if (Object
->cExclusiveLock
== 0)
869 Object
->Tid
= Thread
;
870 Object
->cExclusiveLock
= 1;
871 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj
))
875 if (Object
->Tid
!= Thread
)
877 /* Unlock the handle table entry. */
878 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
883 InterlockedIncrement((PLONG
)&Object
->cExclusiveLock
);
889 * Debugging code. Report attempts to lock deleted handles and
890 * locking type mismatches.
892 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
895 /* Unlock the handle table entry. */
896 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
903 * The handle is currently locked, wait some time and try again.
911 KeLeaveCriticalRegion();
918 * Return pointer to the object by handle (and allow sharing of the handle
921 * \param hObj Object handle
922 * \return Pointer to the object.
924 * \note Process can only get pointer to the objects it created or global objects.
926 * \todo Get rid of the ExpectedType parameter!
928 PGDIOBJ INTERNAL_CALL
929 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
932 PGDI_TABLE_ENTRY Entry
;
933 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
935 ULONG_PTR HandleType
, HandleUpper
;
937 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
938 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
939 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
941 /* Check that the handle index is valid. */
942 if (HandleIndex
>= GDI_HANDLE_COUNT
)
945 /* Check if we have the requested type */
946 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
947 HandleType
!= ExpectedType
) ||
950 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
951 hObj
, HandleType
, ExpectedType
);
955 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
957 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
958 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
960 /* Check for invalid owner. */
961 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
967 * Prevent the thread from being terminated during the locking process.
968 * It would result in undesired effects and inconsistency of the global
972 KeEnterCriticalRegion();
975 * Loop until we either successfully lock the handle entry & object or
976 * fail some of the check.
981 /* Lock the handle table entry. */
982 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
983 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
987 if (PrevProcId
== HandleProcessId
)
990 * We're locking an object that belongs to our process or it's a
991 * global object if HandleProcessId is 0 here.
994 if ( (Entry
->KernelData
!= NULL
) &&
995 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
997 Object
= (POBJ
)Entry
->KernelData
;
999 GDIDBG_CAPTURESHARELOCKER(HandleIndex
);
1001 if (InterlockedIncrement((PLONG
)&Object
->ulShareCount
) == 1)
1003 memset(GDIHandleLocker
[HandleIndex
], 0x00, GDI_STACK_LEVELS
* sizeof(ULONG
));
1004 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS
, (PVOID
*)GDIHandleShareLocker
[HandleIndex
], NULL
);
1007 InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
1013 * Debugging code. Report attempts to lock deleted handles and
1014 * locking type mismatches.
1016 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
1019 /* Unlock the handle table entry. */
1020 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1027 * The handle is currently locked, wait some time and try again.
1035 KeLeaveCriticalRegion();
1041 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
1043 PGDI_TABLE_ENTRY Entry
;
1047 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1049 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1051 ProcessId
= PsGetCurrentProcessId();
1053 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1054 Ret
= Entry
->KernelData
!= NULL
&&
1055 (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0 &&
1056 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1065 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1068 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1069 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1071 PGDI_TABLE_ENTRY Entry
;
1072 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1076 GDIDBG_INITLOOPTRACE();
1081 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj
);
1083 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1085 if (!GDI_HANDLE_IS_STOCKOBJ(hObj
))
1087 ProcessId
= PsGetCurrentProcessId();
1088 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1090 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
1093 /* lock the object, we must not convert stock objects, so don't check!!! */
1094 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1095 if (PrevProcId
== ProcessId
)
1097 LONG NewType
, PrevType
, OldType
;
1099 /* we're locking an object that belongs to our process. First calculate
1100 the new object type including the stock object flag and then try to
1102 /* On Windows the higher 16 bit of the type field don't contain the
1103 full type from the handle, but the base type.
1104 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1105 OldType
= ((ULONG
)hObj
& GDI_HANDLE_BASETYPE_MASK
) | ((ULONG
)hObj
>> GDI_ENTRY_UPPER_SHIFT
);
1106 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1107 we copy them as we can't get them from the handle */
1108 OldType
|= Entry
->Type
& GDI_ENTRY_FLAGS_MASK
;
1110 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1111 NewType
= OldType
| GDI_ENTRY_STOCK_MASK
;
1113 /* Try to exchange the type field - but only if the old (previous type) matches! */
1114 PrevType
= InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1115 if (PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1117 PTHREADINFO PrevThread
;
1120 /* We successfully set the stock object flag.
1121 KernelData should never be NULL here!!! */
1122 ASSERT(Entry
->KernelData
);
1124 Object
= Entry
->KernelData
;
1126 PrevThread
= Object
->Tid
;
1127 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1129 /* dereference the process' object counter */
1130 if (PrevProcId
!= GDI_GLOBAL_PROCESS
)
1132 PEPROCESS OldProcess
;
1133 PPROCESSINFO W32Process
;
1137 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1138 if (NT_SUCCESS(Status
))
1140 W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
1141 if (W32Process
!= NULL
)
1143 InterlockedDecrement(&W32Process
->GDIHandleCount
);
1145 ObDereferenceObject(OldProcess
);
1149 hObj
= (HGDIOBJ
)((ULONG
)(hObj
) | GDI_HANDLE_STOCK_MASK
);
1151 Object
->hHmgr
= hObj
;
1153 /* remove the process id lock and make it global */
1154 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1156 /* we're done, successfully converted the object */
1161 GDIDBG_TRACELOOP(hObj
, PrevThread
, Thread
);
1163 /* WTF?! The object is already locked by a different thread!
1164 Release the lock, wait a bit and try again!
1165 FIXME - we should give up after some time unless we want to wait forever! */
1166 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1174 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1175 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType
, Entry
->Type
, NewType
, Entry
->KernelData
);
1178 else if (PrevProcId
== LockedProcessId
)
1180 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
1182 /* the object is currently locked, wait some time and try again.
1183 FIXME - we shouldn't loop forever! Give up after some time! */
1190 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1198 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1200 PGDI_TABLE_ENTRY Entry
;
1201 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1205 GDIDBG_INITLOOPTRACE();
1207 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1209 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1211 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1213 ProcessId
= PsGetCurrentProcessId();
1214 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1216 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1219 /* lock the object, we must not convert stock objects, so don't check!!! */
1220 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1221 if (PrevProcId
== ProcessId
)
1223 PTHREADINFO PrevThread
;
1225 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1227 POBJ Object
= Entry
->KernelData
;
1229 PrevThread
= Object
->Tid
;
1230 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1232 PEPROCESS OldProcess
;
1233 PPROCESSINFO W32Process
;
1236 /* dereference the process' object counter */
1238 if ((ULONG_PTR
)PrevProcId
& ~0x1)
1240 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1241 if (NT_SUCCESS(Status
))
1243 W32Process
= (PPROCESSINFO
)OldProcess
->Win32Process
;
1244 if (W32Process
!= NULL
)
1246 InterlockedDecrement(&W32Process
->GDIHandleCount
);
1248 ObDereferenceObject(OldProcess
);
1252 if (NewOwner
!= NULL
)
1254 ProcessId
= PsGetProcessId(NewOwner
);
1256 /* Increase the new process' object counter */
1257 W32Process
= (PPROCESSINFO
)NewOwner
->Win32Process
;
1258 if (W32Process
!= NULL
)
1260 InterlockedIncrement(&W32Process
->GDIHandleCount
);
1266 /* remove the process id lock and change it to the new process id */
1267 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
);
1274 GDIDBG_TRACELOOP(ObjectHandle
, PrevThread
, Thread
);
1276 /* WTF?! The object is already locked by a different thread!
1277 Release the lock, wait a bit and try again! DO reset the pid lock
1278 so we make sure we don't access invalid memory in case the object is
1279 being deleted in the meantime (because we don't have aquired a reference
1281 FIXME - we should give up after some time unless we want to wait forever! */
1282 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1290 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1291 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry
->Type
, Entry
->KernelData
);
1295 else if (PrevProcId
== LockedProcessId
)
1297 GDIDBG_TRACELOOP(ObjectHandle
, PrevProcId
, ProcessId
);
1299 /* the object is currently locked, wait some time and try again.
1300 FIXME - we shouldn't loop forever! Give up after some time! */
1305 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1307 /* allow changing ownership of global objects */
1309 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1312 else if ((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1314 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1319 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1327 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1329 PGDI_TABLE_ENTRY FromEntry
;
1331 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1334 GDIDBG_INITLOOPTRACE();
1336 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1338 Thread
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
1340 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1342 FromEntry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, CopyFrom
);
1344 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1345 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1348 /* lock the object, we must not convert stock objects, so don't check!!! */
1349 FromPrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1350 if (FromPrevProcId
== FromProcessId
)
1352 PTHREADINFO PrevThread
;
1355 if ((FromEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1357 Object
= FromEntry
->KernelData
;
1359 /* save the pointer to the calling thread so we know it was this thread
1360 that locked the object */
1361 PrevThread
= Object
->Tid
;
1362 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1364 /* now let's change the ownership of the target object */
1366 if (((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1368 PEPROCESS ProcessTo
;
1370 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1372 GDIOBJ_SetOwnership(CopyTo
, ProcessTo
);
1373 ObDereferenceObject(ProcessTo
);
1378 /* mark the object as global */
1379 GDIOBJ_SetOwnership(CopyTo
, NULL
);
1382 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1386 GDIDBG_TRACELOOP(CopyFrom
, PrevThread
, Thread
);
1388 /* WTF?! The object is already locked by a different thread!
1389 Release the lock, wait a bit and try again! DO reset the pid lock
1390 so we make sure we don't access invalid memory in case the object is
1391 being deleted in the meantime (because we don't have aquired a reference
1393 FIXME - we should give up after some time unless we want to wait forever! */
1394 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1397 goto LockHandleFrom
;
1402 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1406 else if (FromPrevProcId
== FromLockedProcessId
)
1408 GDIDBG_TRACELOOP(CopyFrom
, FromPrevProcId
, FromProcessId
);
1410 /* the object is currently locked, wait some time and try again.
1411 FIXME - we shouldn't loop forever! Give up after some time! */
1414 goto LockHandleFrom
;
1416 else if ((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1418 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1419 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1420 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1421 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1422 goto LockHandleFrom
;
1426 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1434 GDI_MapHandleTable(PSECTION_OBJECT SectionObject
, PEPROCESS Process
)
1436 PVOID MappedView
= NULL
;
1438 LARGE_INTEGER Offset
;
1439 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1441 Offset
.QuadPart
= 0;
1443 ASSERT(SectionObject
!= NULL
);
1444 ASSERT(Process
!= NULL
);
1446 Status
= MmMapViewOfSection(SectionObject
,
1457 if (!NT_SUCCESS(Status
))
1463 /** PUBLIC FUNCTIONS **********************************************************/
1466 Since Brush/Pen and Region objects are sharable,,, we can just use
1467 UserHeapAlloc to allocate the small attribute objects.
1471 // Save Kernel Space Pointer
1472 (PBRUSH)->pBrushAttr = IntGdiAllocObjAttr(GDIObjType_BRUSH_TYPE);
1474 // Kernel Space to User Space Pointer
1475 (PGDI_TABLE_ENTRY)->UserData = pBrushAttr;
1476 // Gdi will adjust for heap delta.
1480 (PGDI_TABLE_ENTRY)->UserData = NULL; // Zero the user ptr.
1481 UserHeapFree((PBRUSH)->pBrushAttr); // Free from kernel ptr.
1482 (PBRUSH)->pBrushAttr = NULL;
1485 Testing with DC_ATTR works but has drawing difficulties.
1486 Base on observation, (Over looking the obvious) we need to supply heap delta
1487 to user space gdi. Now, with testing, looks all normal.
1492 IntGdiAllocObjAttr(GDIOBJTYPE Type
)
1494 PVOID pMemAttr
= NULL
;
1498 case GDIObjType_DC_TYPE
:
1499 pMemAttr
= UserHeapAlloc(sizeof(DC_ATTR
));
1500 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(DC_ATTR
));
1502 case GDIObjType_RGN_TYPE
:
1503 pMemAttr
= UserHeapAlloc(sizeof(RGN_ATTR
));
1504 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(RGN_ATTR
));
1506 case GDIObjType_BRUSH_TYPE
:
1507 pMemAttr
= UserHeapAlloc(sizeof(BRUSH_ATTR
));
1508 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(BRUSH_ATTR
));
1519 IntGdiSetBrushOwner(PBRUSH pbr
, DWORD OwnerMask
)
1522 PEPROCESS Owner
= NULL
;
1523 PGDI_TABLE_ENTRY pEntry
= NULL
;
1525 if (!pbr
) return FALSE
;
1527 hBR
= pbr
->BaseObject
.hHmgr
;
1529 if (!hBR
|| (GDI_HANDLE_GET_TYPE(hBR
) != GDI_OBJECT_TYPE_BRUSH
))
1533 INT Index
= GDI_HANDLE_GET_INDEX((HGDIOBJ
)hBR
);
1534 pEntry
= &GdiHandleTable
->Entries
[Index
];
1537 if (pbr
->flAttrs
& GDIBRUSH_IS_GLOBAL
)
1539 GDIOBJ_ShareUnlockObjByPtr((POBJ
)pbr
);
1543 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1545 // Set this Brush to inaccessible mode and to an Owner of NONE.
1546 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1548 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, Owner
))
1551 // Deny user access to User Data.
1552 pEntry
->UserData
= NULL
; // This hBR is inaccessible!
1555 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1557 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, PsGetCurrentProcess() ))
1560 // Allow user access to User Data.
1561 pEntry
->UserData
= pbr
->pBrushAttr
;
1569 IntGdiSetDCOwnerEx( HDC hDC
, DWORD OwnerMask
, BOOL NoSetBrush
)
1574 if (!hDC
|| (GDI_HANDLE_GET_TYPE(hDC
) != GDI_OBJECT_TYPE_DC
)) return FALSE
;
1576 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1578 pDC
= DC_LockDc ( hDC
);
1579 MmCopyFromCaller(&pDC
->dcattr
, pDC
->pdcattr
, sizeof(DC_ATTR
));
1582 DC_FreeDcAttr( hDC
); // Free the dcattr!
1584 if (!DC_SetOwnership( hDC
, NULL
)) // This hDC is inaccessible!
1588 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1590 pDC
= DC_LockDc ( hDC
);
1591 ASSERT(pDC
->pdcattr
== &pDC
->dcattr
);
1594 if (!DC_SetOwnership( hDC
, PsGetCurrentProcess() )) return Ret
;
1596 DC_AllocateDcAttr( hDC
); // Allocate new dcattr
1598 DCU_SynchDcAttrtoUser( hDC
); // Copy data from dc to dcattr
1601 if ((OwnerMask
!= GDI_OBJ_HMGR_NONE
) && !NoSetBrush
)
1603 pDC
= DC_LockDc ( hDC
);
1604 if (IntGdiSetBrushOwner((PBRUSH
)pDC
->dclevel
.pbrFill
, OwnerMask
))
1605 IntGdiSetBrushOwner((PBRUSH
)pDC
->dclevel
.pbrLine
, OwnerMask
);
1613 GreGetObjectOwner(HGDIOBJ Handle
, GDIOBJTYPE ObjType
)
1615 INT Ret
= GDI_OBJ_HMGR_RESTRICTED
;
1617 if ( GDI_HANDLE_GET_INDEX(Handle
) < GDI_HANDLE_COUNT
)
1619 PGDI_TABLE_ENTRY pEntry
= &GdiHandleTable
->Entries
[GDI_HANDLE_GET_INDEX(Handle
)];
1621 if (pEntry
->ObjectType
== ObjType
)
1623 if (pEntry
->FullUnique
== (GDI_HANDLE_GET_UPPER(Handle
) >> GDI_ENTRY_UPPER_SHIFT
))
1624 Ret
= pEntry
->ProcessId
& ~1;
1634 NtGdiCreateClientObj(
1641 /* Mask out everything that would change the type in a wrong manner */
1642 ulType
&= (GDI_HANDLE_TYPE_MASK
& ~GDI_HANDLE_BASETYPE_MASK
);
1644 /* Allocate a new object */
1645 pObject
= GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ
| ulType
);
1651 /* get the handle */
1652 handle
= pObject
->hHmgr
;
1655 GDIOBJ_UnlockObjByPtr(pObject
);
1663 NtGdiDeleteClientObj(
1667 /* We first need to get the real type from the handle */
1668 ULONG type
= GDI_HANDLE_GET_TYPE(h
);
1670 /* Check if it's really a CLIENTOBJ */
1671 if ((type
& GDI_HANDLE_BASETYPE_MASK
) != GDILoObjType_LO_CLIENTOBJ_TYPE
)
1673 /* FIXME: SetLastError? */
1676 return GDIOBJ_FreeObjByHandle(h
, type
);
1681 IntGdiGetObject(IN HANDLE Handle
,
1689 pGdiObject
= GDIOBJ_LockObj(Handle
, GDI_OBJECT_TYPE_DONTCARE
);
1692 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1696 dwObjectType
= GDIOBJ_GetObjectType(Handle
);
1697 switch (dwObjectType
)
1699 case GDI_OBJECT_TYPE_PEN
:
1700 case GDI_OBJECT_TYPE_EXTPEN
:
1701 Result
= PEN_GetObject((PBRUSH
) pGdiObject
, cbCount
, (PLOGPEN
) lpBuffer
); // IntGdiCreatePenIndirect
1704 case GDI_OBJECT_TYPE_BRUSH
:
1705 Result
= BRUSH_GetObject((PBRUSH
) pGdiObject
, cbCount
, (LPLOGBRUSH
)lpBuffer
);
1708 case GDI_OBJECT_TYPE_BITMAP
:
1709 Result
= BITMAP_GetObject((SURFACE
*) pGdiObject
, cbCount
, lpBuffer
);
1711 case GDI_OBJECT_TYPE_FONT
:
1712 Result
= FontGetObject((PTEXTOBJ
) pGdiObject
, cbCount
, lpBuffer
);
1714 // Fix the LOGFONT structure for the stock fonts
1715 if (FIRST_STOCK_HANDLE
<= Handle
&& Handle
<= LAST_STOCK_HANDLE
)
1717 FixStockFontSizeW(Handle
, cbCount
, lpBuffer
);
1722 case GDI_OBJECT_TYPE_PALETTE
:
1723 Result
= PALETTE_GetObject((PPALETTE
) pGdiObject
, cbCount
, lpBuffer
);
1727 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType
);
1731 GDIOBJ_UnlockObjByPtr(pGdiObject
);
1741 NtGdiExtGetObjectW(IN HANDLE hGdiObj
,
1743 OUT LPVOID lpBuffer
)
1750 DIBSECTION dibsection
;
1754 EXTLOGFONTW extlogfontw
;
1755 ENUMLOGFONTEXDVW enumlogfontexdvw
;
1758 // Normalize to the largest supported object size
1759 cbCount
= min((UINT
)cbCount
, sizeof(Object
));
1761 // Now do the actual call
1762 iRetCount
= IntGdiGetObject(hGdiObj
, cbCount
, lpBuffer
? &Object
: NULL
);
1763 cbCopyCount
= min((UINT
)cbCount
, (UINT
)iRetCount
);
1765 // Make sure we have a buffer and a copy size
1766 if ((cbCopyCount
) && (lpBuffer
))
1768 // Enter SEH for buffer transfer
1771 // Probe the buffer and copy it
1772 ProbeForWrite(lpBuffer
, cbCopyCount
, sizeof(WORD
));
1773 RtlCopyMemory(lpBuffer
, &Object
, cbCopyCount
);
1775 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1777 // Clear the return value.
1778 // Do *NOT* set last error here!