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 /* apparently the first 10 entries are never used in windows as they are empty */
21 #define RESERVE_ENTRIES_COUNT 10
23 #define BASE_OBJTYPE_COUNT 32
25 #define DelayExecution() \
26 DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
27 KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
29 /* static */ /* FIXME: -fno-unit-at-a-time breaks this */
30 BOOL INTERNAL_CALL
GDI_CleanupDummy(PVOID ObjectBody
);
32 /** GLOBALS *******************************************************************/
39 GDICLEANUPPROC CleanupProc
;
40 } OBJ_TYPE_INFO
, *POBJ_TYPE_INFO
;
43 OBJ_TYPE_INFO ObjTypeInfo
[BASE_OBJTYPE_COUNT
] =
45 {0, 0, 0, NULL
}, /* 00 reserved entry */
46 {1, sizeof(DC
), TAG_DC
, DC_Cleanup
}, /* 01 DC */
47 {1, 0, 0, NULL
}, /* 02 UNUSED1 */
48 {1, 0, 0, NULL
}, /* 03 UNUSED2 */
49 {1, sizeof(ROSRGNDATA
), TAG_REGION
, REGION_Cleanup
}, /* 04 RGN */
50 {1, sizeof(SURFACE
), TAG_SURFACE
, SURFACE_Cleanup
}, /* 05 SURFACE */
51 {1, sizeof(CLIENTOBJ
), TAG_CLIENTOBJ
, GDI_CleanupDummy
}, /* 06 CLIENTOBJ: METADC,... */
52 {1, sizeof(PATH
), TAG_PATH
, GDI_CleanupDummy
}, /* 07 PATH */
53 {1, sizeof(PALGDI
), TAG_PALETTE
, PALETTE_Cleanup
}, /* 08 PAL */
54 {1, sizeof(COLORSPACE
), TAG_ICMLCS
, GDI_CleanupDummy
}, /* 09 ICMLCS, */
55 {1, sizeof(TEXTOBJ
), TAG_LFONT
, GDI_CleanupDummy
}, /* 0a LFONT */
56 {0, 0, TAG_RFONT
, NULL
}, /* 0b RFONT, unused */
57 {0, 0, TAG_PFE
, NULL
}, /* 0c PFE, unused */
58 {0, 0, TAG_PFT
, NULL
}, /* 0d PFT, unused */
59 {0, sizeof(GDICLRXFORM
), TAG_ICMCXF
, GDI_CleanupDummy
}, /* 0e ICMCXF, */
60 {0, 0, TAG_SPRITE
, NULL
}, /* 0f SPRITE, unused */
61 {1, sizeof(GDIBRUSHOBJ
), TAG_BRUSH
, BRUSH_Cleanup
}, /* 10 BRUSH, PEN, EXTPEN */
62 {0, 0, TAG_UMPD
, NULL
}, /* 11 UMPD, unused */
63 {0, 0, 0, NULL
}, /* 12 UNUSED4 */
64 {0, 0, TAG_SPACE
, NULL
}, /* 13 SPACE, unused */
65 {0, 0, 0, NULL
}, /* 14 UNUSED5 */
66 {0, 0, TAG_META
, NULL
}, /* 15 META, unused */
67 {0, 0, TAG_EFSTATE
, NULL
}, /* 16 EFSTATE, unused */
68 {0, 0, TAG_BMFD
, NULL
}, /* 17 BMFD, unused */
69 {0, 0, TAG_VTFD
, NULL
}, /* 18 VTFD, unused */
70 {0, 0, TAG_TTFD
, NULL
}, /* 19 TTFD, unused */
71 {0, 0, TAG_RC
, NULL
}, /* 1a RC, unused */
72 {0, 0, TAG_TEMP
, NULL
}, /* 1b TEMP, unused */
73 {0, 0, TAG_DRVOBJ
, NULL
}, /* 1c DRVOBJ, unused */
74 {0, 0, TAG_DCIOBJ
, NULL
}, /* 1d DCIOBJ, unused */
75 {0, 0, TAG_SPOOL
, NULL
}, /* 1e SPOOL, unused */
76 {0, 0, 0, NULL
}, /* 1f reserved entry */
79 static LARGE_INTEGER ShortDelay
;
81 /** DEBUGGING *****************************************************************/
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()
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 PW32PROCESS W32Process
;
349 POBJ newObject
= NULL
;
350 HANDLE CurrentProcessId
, LockedProcessId
;
353 GDIDBG_INITLOOPTRACE();
355 W32Process
= PsGetCurrentProcessWin32Process();
356 /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
357 to take too many GDI objects, itself. */
358 if (W32Process
&& W32Process
->GDIObjects
>= 0x2710)
360 DPRINT1("Too many objects for process!!!\n");
361 GDIDBG_DUMPHANDLETABLE();
365 ASSERT(ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
);
367 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(ObjectType
);
369 newObject
= GDIOBJ_AllocObj(TypeIndex
);
372 DPRINT1("Not enough memory to allocate gdi object!\n");
377 PGDI_TABLE_ENTRY Entry
;
380 CurrentProcessId
= PsGetCurrentProcessId();
381 LockedProcessId
= (HANDLE
)((ULONG_PTR
)CurrentProcessId
| 0x1);
383 // RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
385 /* On Windows the higher 16 bit of the type field don't contain the
386 full type from the handle, but the base type.
387 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
388 TypeInfo
= (ObjectType
& GDI_HANDLE_BASETYPE_MASK
) | (ObjectType
>> GDI_ENTRY_UPPER_SHIFT
);
390 Index
= InterlockedPopFreeEntry();
395 Entry
= &GdiHandleTable
->Entries
[Index
];
398 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, 0);
399 if (PrevProcId
== NULL
)
401 PW32THREAD Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
404 Entry
->KernelData
= newObject
;
406 /* copy the reuse-counter */
407 TypeInfo
|= Entry
->Type
& GDI_ENTRY_REUSE_MASK
;
409 /* we found a free entry, no need to exchange this field atomically
410 since we're holding the lock */
411 Entry
->Type
= TypeInfo
;
413 /* Create a handle */
414 Handle
= (HGDIOBJ
)((Index
& 0xFFFF) | (TypeInfo
<< GDI_ENTRY_UPPER_SHIFT
));
416 /* Initialize BaseObject fields */
417 newObject
->hHmgr
= Handle
;
418 newObject
->ulShareCount
= 0;
419 newObject
->cExclusiveLock
= 1;
420 newObject
->Tid
= Thread
;
422 /* unlock the entry */
423 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, CurrentProcessId
);
425 GDIDBG_CAPTUREALLOCATOR(Index
);
427 if (W32Process
!= NULL
)
429 InterlockedIncrement(&W32Process
->GDIObjects
);
432 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle
, newObject
);
437 GDIDBG_TRACELOOP(Index
, PrevProcId
, CurrentProcessId
);
438 /* damn, someone is trying to lock the object even though it doesn't
439 even exist anymore, wait a little and try again!
440 FIXME - we shouldn't loop forever! Give up after some time! */
447 GDIOBJ_FreeObj(newObject
, TypeIndex
);
449 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
450 GDIDBG_DUMPHANDLETABLE();
457 GDIOBJ_FreeObj(POBJ pObject
, UCHAR BaseType
)
459 /* Object must not have a handle! */
460 ASSERT(pObject
->hHmgr
== NULL
);
462 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
464 PPAGED_LOOKASIDE_LIST LookasideList
;
466 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
467 ExFreeToPagedLookasideList(LookasideList
, pObject
);
476 * Free memory allocated for the GDI object. For each object type this function calls the
477 * appropriate cleanup routine.
479 * \param hObj - handle of the object to be deleted.
481 * \return Returns TRUE if succesful.
482 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
483 * to the calling process.
486 GDIOBJ_FreeObjByHandle(HGDIOBJ hObj
, DWORD ExpectedType
)
488 PGDI_TABLE_ENTRY Entry
;
489 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
490 ULONG HandleType
, HandleUpper
, TypeIndex
;
493 GDIDBG_INITLOOPTRACE();
495 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj
);
497 if (GDI_HANDLE_IS_STOCKOBJ(hObj
))
499 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj
);
500 GDIDBG_TRACECALLER();
504 ProcessId
= PsGetCurrentProcessId();
505 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
507 Silent
= (ExpectedType
& GDI_OBJECT_TYPE_SILENT
);
508 ExpectedType
&= ~GDI_OBJECT_TYPE_SILENT
;
510 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
511 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
513 /* Check if we have the requested type */
514 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
515 HandleType
!= ExpectedType
) ||
518 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
519 hObj
, HandleType
, ExpectedType
);
520 GDIDBG_TRACECALLER();
524 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
527 /* lock the object, we must not delete global objects, so don't exchange the locking
528 process ID to zero when attempting to lock a global object... */
529 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
530 if (PrevProcId
== ProcessId
)
532 if ( (Entry
->KernelData
!= NULL
) &&
533 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) &&
534 ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == (HandleUpper
& GDI_ENTRY_BASETYPE_MASK
)) )
538 Object
= Entry
->KernelData
;
540 if (Object
->cExclusiveLock
== 0)
543 PW32PROCESS W32Process
= PsGetCurrentProcessWin32Process();
545 /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
546 Entry
->Type
= (Entry
->Type
+ GDI_ENTRY_REUSE_INC
) & ~GDI_ENTRY_BASETYPE_MASK
;
548 /* unlock the handle slot */
549 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
551 /* push this entry to the free list */
552 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable
, Entry
));
554 Object
->hHmgr
= NULL
;
556 if (W32Process
!= NULL
)
558 InterlockedDecrement(&W32Process
->GDIObjects
);
561 /* call the cleanup routine. */
562 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(HandleType
);
563 Ret
= ObjTypeInfo
[TypeIndex
].CleanupProc(Object
);
565 /* Now it's time to free the memory */
566 GDIOBJ_FreeObj(Object
, TypeIndex
);
568 GDIDBG_CAPTUREDELETER(hObj
);
574 * The object is currently locked, so freeing is forbidden!
576 DPRINT1("Object->cExclusiveLock = %d\n", Object
->cExclusiveLock
);
577 GDIDBG_TRACECALLER();
578 GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj
));
579 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
580 /* do not assert here for it will call again from dxg.sys it being call twice */
586 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
587 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
590 else if (PrevProcId
== LockedProcessId
)
592 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
594 /* the object is currently locked, wait some time and try again.
595 FIXME - we shouldn't loop forever! Give up after some time! */
604 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
606 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj
);
608 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
610 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
614 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);
616 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry
->Type
, Entry
->KernelData
, Entry
->ProcessId
);
617 GDIDBG_TRACECALLER();
618 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
627 IsObjectDead(HGDIOBJ hObject
)
629 INT Index
= GDI_HANDLE_GET_INDEX(hObject
);
630 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
631 // We check to see if the objects are knocking on deaths door.
632 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
636 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject
);
637 return TRUE
; // return true and move on.
644 * \param hObject object handle
645 * \return if the function fails the returned value is FALSE.
649 NtGdiDeleteObject(HGDIOBJ hObject
)
651 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
652 if (!IsObjectDead(hObject
))
654 return NULL
!= hObject
655 ? GDIOBJ_FreeObjByHandle(hObject
, GDI_OBJECT_TYPE_DONTCARE
) : FALSE
;
659 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject
);
660 return TRUE
; // return true and move on.
666 IntDeleteHandlesForProcess(struct _EPROCESS
*Process
, ULONG ObjectType
)
668 PGDI_TABLE_ENTRY Entry
, End
;
669 ULONG Index
= RESERVE_ENTRIES_COUNT
;
671 PW32PROCESS W32Process
;
673 W32Process
= (PW32PROCESS
)Process
->Win32Process
;
676 if (W32Process
->GDIObjects
> 0)
678 ProcId
= Process
->UniqueProcessId
;
680 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
681 we should delete it directly here! */
683 End
= &GdiHandleTable
->Entries
[GDI_HANDLE_COUNT
];
684 for (Entry
= &GdiHandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
688 /* ignore the lock bit */
689 if ( (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
)
691 if ( (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == ObjectType
||
692 ObjectType
== GDI_OBJECT_TYPE_DONTCARE
)
694 HGDIOBJ ObjectHandle
;
696 /* Create the object handle for the entry, the lower(!) 16 bit of the
697 Type field includes the type of the object including the stock
698 object flag - but since stock objects don't have a process id we can
699 simply ignore this fact here. */
700 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
702 if (GDIOBJ_FreeObjByHandle(ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
) &&
703 W32Process
->GDIObjects
== 0)
705 /* there are no more gdi handles for this process, bail */
716 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
717 * \param Process - PID of the process that will be destroyed.
720 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
722 PEPROCESS CurrentProcess
;
724 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
725 CurrentProcess
= PsGetCurrentProcess();
726 if (CurrentProcess
!= Process
)
728 KeAttachProcess(&Process
->Pcb
);
731 /* Delete objects. Begin with types that are not referenced by other types */
732 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_DC_TYPE
);
733 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BRUSH_TYPE
);
734 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BITMAP_TYPE
);
736 /* Finally finish with what's left */
737 IntDeleteHandlesForProcess(Process
, GDI_OBJECT_TYPE_DONTCARE
);
739 if (CurrentProcess
!= Process
)
745 GdiDbgHTIntegrityCheck();
748 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
754 * Return pointer to the object by handle.
756 * \param hObj Object handle
757 * \return Pointer to the object.
759 * \note Process can only get pointer to the objects it created or global objects.
761 * \todo Get rid of the ExpectedType parameter!
763 PGDIOBJ INTERNAL_CALL
764 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
767 PGDI_TABLE_ENTRY Entry
;
768 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
770 ULONG HandleType
, HandleUpper
;
772 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
773 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
774 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
776 /* Check that the handle index is valid. */
777 if (HandleIndex
>= GDI_HANDLE_COUNT
)
780 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
782 /* Check if we have the requested type */
783 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
784 HandleType
!= ExpectedType
) ||
787 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
788 hObj
, HandleType
, ExpectedType
);
789 GDIDBG_TRACECALLER();
790 GDIDBG_TRACEALLOCATOR(hObj
);
791 GDIDBG_TRACEDELETER(hObj
);
795 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
796 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
798 /* Check for invalid owner. */
799 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
801 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj
, ProcessId
, HandleProcessId
);
802 GDIDBG_TRACECALLER();
803 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
808 * Prevent the thread from being terminated during the locking process.
809 * It would result in undesired effects and inconsistency of the global
813 KeEnterCriticalRegion();
816 * Loop until we either successfully lock the handle entry & object or
817 * fail some of the check.
822 /* Lock the handle table entry. */
823 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
824 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
828 if (PrevProcId
== HandleProcessId
)
831 * We're locking an object that belongs to our process or it's a
832 * global object if HandleProcessId is 0 here.
835 if ( (Entry
->KernelData
!= NULL
) &&
836 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
838 PW32THREAD Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
839 Object
= Entry
->KernelData
;
841 if (Object
->cExclusiveLock
== 0)
843 Object
->Tid
= Thread
;
844 Object
->cExclusiveLock
= 1;
845 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj
))
849 if (Object
->Tid
!= Thread
)
851 /* Unlock the handle table entry. */
852 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
857 InterlockedIncrement((PLONG
)&Object
->cExclusiveLock
);
863 * Debugging code. Report attempts to lock deleted handles and
864 * locking type mismatches.
866 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
869 /* Unlock the handle table entry. */
870 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
877 * The handle is currently locked, wait some time and try again.
885 KeLeaveCriticalRegion();
892 * Return pointer to the object by handle (and allow sharing of the handle
895 * \param hObj Object handle
896 * \return Pointer to the object.
898 * \note Process can only get pointer to the objects it created or global objects.
900 * \todo Get rid of the ExpectedType parameter!
902 PGDIOBJ INTERNAL_CALL
903 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
906 PGDI_TABLE_ENTRY Entry
;
907 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
909 ULONG_PTR HandleType
, HandleUpper
;
911 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
912 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
913 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
915 /* Check that the handle index is valid. */
916 if (HandleIndex
>= GDI_HANDLE_COUNT
)
919 /* Check if we have the requested type */
920 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
921 HandleType
!= ExpectedType
) ||
924 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
925 hObj
, HandleType
, ExpectedType
);
929 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
931 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
932 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
934 /* Check for invalid owner. */
935 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
941 * Prevent the thread from being terminated during the locking process.
942 * It would result in undesired effects and inconsistency of the global
946 KeEnterCriticalRegion();
949 * Loop until we either successfully lock the handle entry & object or
950 * fail some of the check.
955 /* Lock the handle table entry. */
956 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
957 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
961 if (PrevProcId
== HandleProcessId
)
964 * We're locking an object that belongs to our process or it's a
965 * global object if HandleProcessId is 0 here.
968 if ( (Entry
->KernelData
!= NULL
) &&
969 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
971 Object
= (POBJ
)Entry
->KernelData
;
974 if (InterlockedIncrement((PLONG
)&Object
->ulShareCount
) == 1)
976 memset(GDIHandleLocker
[HandleIndex
], 0x00, GDI_STACK_LEVELS
* sizeof(ULONG
));
977 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS
, (PVOID
*)GDIHandleLocker
[HandleIndex
], NULL
);
980 InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
986 * Debugging code. Report attempts to lock deleted handles and
987 * locking type mismatches.
989 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
992 /* Unlock the handle table entry. */
993 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1000 * The handle is currently locked, wait some time and try again.
1008 KeLeaveCriticalRegion();
1015 * Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
1016 * as soon as you don't need to have access to it's data.
1018 * \param Object Object pointer (as returned by GDIOBJ_LockObj).
1021 GDIOBJ_UnlockObjByPtr(POBJ Object
)
1023 if (InterlockedDecrement((PLONG
)&Object
->cExclusiveLock
) < 0)
1025 DPRINT1("Trying to unlock non-existant object\n");
1030 GDIOBJ_ShareUnlockObjByPtr(POBJ Object
)
1032 if (InterlockedDecrement((PLONG
)&Object
->ulShareCount
) < 0)
1034 DPRINT1("Trying to unlock non-existant object\n");
1039 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
1041 PGDI_TABLE_ENTRY Entry
;
1045 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1047 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1049 ProcessId
= PsGetCurrentProcessId();
1051 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1052 Ret
= Entry
->KernelData
!= NULL
&&
1053 (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0 &&
1054 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1063 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1066 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1067 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1069 PGDI_TABLE_ENTRY Entry
;
1070 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1074 GDIDBG_INITLOOPTRACE();
1079 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj
);
1081 Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
1083 if (!GDI_HANDLE_IS_STOCKOBJ(hObj
))
1085 ProcessId
= PsGetCurrentProcessId();
1086 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1088 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
1091 /* lock the object, we must not convert stock objects, so don't check!!! */
1092 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1093 if (PrevProcId
== ProcessId
)
1095 LONG NewType
, PrevType
, OldType
;
1097 /* we're locking an object that belongs to our process. First calculate
1098 the new object type including the stock object flag and then try to
1100 /* On Windows the higher 16 bit of the type field don't contain the
1101 full type from the handle, but the base type.
1102 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1103 OldType
= ((ULONG
)hObj
& GDI_HANDLE_BASETYPE_MASK
) | ((ULONG
)hObj
>> GDI_ENTRY_UPPER_SHIFT
);
1104 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1105 we copy them as we can't get them from the handle */
1106 OldType
|= Entry
->Type
& GDI_ENTRY_FLAGS_MASK
;
1108 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1109 NewType
= OldType
| GDI_ENTRY_STOCK_MASK
;
1111 /* Try to exchange the type field - but only if the old (previous type) matches! */
1112 PrevType
= InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1113 if (PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1115 PW32THREAD PrevThread
;
1118 /* We successfully set the stock object flag.
1119 KernelData should never be NULL here!!! */
1120 ASSERT(Entry
->KernelData
);
1122 Object
= Entry
->KernelData
;
1124 PrevThread
= Object
->Tid
;
1125 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1127 /* dereference the process' object counter */
1128 if (PrevProcId
!= GDI_GLOBAL_PROCESS
)
1130 PEPROCESS OldProcess
;
1131 PW32PROCESS W32Process
;
1135 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1136 if (NT_SUCCESS(Status
))
1138 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1139 if (W32Process
!= NULL
)
1141 InterlockedDecrement(&W32Process
->GDIObjects
);
1143 ObDereferenceObject(OldProcess
);
1147 hObj
= (HGDIOBJ
)((ULONG
)(hObj
) | GDI_HANDLE_STOCK_MASK
);
1149 Object
->hHmgr
= hObj
;
1151 /* remove the process id lock and make it global */
1152 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1154 /* we're done, successfully converted the object */
1159 GDIDBG_TRACELOOP(hObj
, PrevThread
, Thread
);
1161 /* WTF?! The object is already locked by a different thread!
1162 Release the lock, wait a bit and try again!
1163 FIXME - we should give up after some time unless we want to wait forever! */
1164 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1172 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1173 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType
, Entry
->Type
, NewType
, Entry
->KernelData
);
1176 else if (PrevProcId
== LockedProcessId
)
1178 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
1180 /* the object is currently locked, wait some time and try again.
1181 FIXME - we shouldn't loop forever! Give up after some time! */
1188 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1196 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1198 PGDI_TABLE_ENTRY Entry
;
1199 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1203 GDIDBG_INITLOOPTRACE();
1205 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1207 Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
1209 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1211 ProcessId
= PsGetCurrentProcessId();
1212 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1214 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1217 /* lock the object, we must not convert stock objects, so don't check!!! */
1218 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1219 if (PrevProcId
== ProcessId
)
1221 PW32THREAD PrevThread
;
1223 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1225 POBJ Object
= Entry
->KernelData
;
1227 PrevThread
= Object
->Tid
;
1228 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1230 PEPROCESS OldProcess
;
1231 PW32PROCESS W32Process
;
1234 /* dereference the process' object counter */
1236 if ((ULONG_PTR
)PrevProcId
& ~0x1)
1238 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1239 if (NT_SUCCESS(Status
))
1241 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1242 if (W32Process
!= NULL
)
1244 InterlockedDecrement(&W32Process
->GDIObjects
);
1246 ObDereferenceObject(OldProcess
);
1250 if (NewOwner
!= NULL
)
1252 ProcessId
= PsGetProcessId(NewOwner
);
1254 /* Increase the new process' object counter */
1255 W32Process
= (PW32PROCESS
)NewOwner
->Win32Process
;
1256 if (W32Process
!= NULL
)
1258 InterlockedIncrement(&W32Process
->GDIObjects
);
1264 /* remove the process id lock and change it to the new process id */
1265 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
);
1272 GDIDBG_TRACELOOP(ObjectHandle
, PrevThread
, Thread
);
1274 /* WTF?! The object is already locked by a different thread!
1275 Release the lock, wait a bit and try again! DO reset the pid lock
1276 so we make sure we don't access invalid memory in case the object is
1277 being deleted in the meantime (because we don't have aquired a reference
1279 FIXME - we should give up after some time unless we want to wait forever! */
1280 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1288 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1289 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry
->Type
, Entry
->KernelData
);
1293 else if (PrevProcId
== LockedProcessId
)
1295 GDIDBG_TRACELOOP(ObjectHandle
, PrevProcId
, ProcessId
);
1297 /* the object is currently locked, wait some time and try again.
1298 FIXME - we shouldn't loop forever! Give up after some time! */
1303 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1305 /* allow changing ownership of global objects */
1307 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1310 else if ((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1312 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1317 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1325 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1327 PGDI_TABLE_ENTRY FromEntry
;
1329 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1332 GDIDBG_INITLOOPTRACE();
1334 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1336 Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
1338 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1340 FromEntry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, CopyFrom
);
1342 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1343 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1346 /* lock the object, we must not convert stock objects, so don't check!!! */
1347 FromPrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1348 if (FromPrevProcId
== FromProcessId
)
1350 PW32THREAD PrevThread
;
1353 if ((FromEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1355 Object
= FromEntry
->KernelData
;
1357 /* save the pointer to the calling thread so we know it was this thread
1358 that locked the object */
1359 PrevThread
= Object
->Tid
;
1360 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1362 /* now let's change the ownership of the target object */
1364 if (((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1366 PEPROCESS ProcessTo
;
1368 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1370 GDIOBJ_SetOwnership(CopyTo
, ProcessTo
);
1371 ObDereferenceObject(ProcessTo
);
1376 /* mark the object as global */
1377 GDIOBJ_SetOwnership(CopyTo
, NULL
);
1380 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1384 GDIDBG_TRACELOOP(CopyFrom
, PrevThread
, Thread
);
1386 /* WTF?! The object is already locked by a different thread!
1387 Release the lock, wait a bit and try again! DO reset the pid lock
1388 so we make sure we don't access invalid memory in case the object is
1389 being deleted in the meantime (because we don't have aquired a reference
1391 FIXME - we should give up after some time unless we want to wait forever! */
1392 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1395 goto LockHandleFrom
;
1400 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1404 else if (FromPrevProcId
== FromLockedProcessId
)
1406 GDIDBG_TRACELOOP(CopyFrom
, FromPrevProcId
, FromProcessId
);
1408 /* the object is currently locked, wait some time and try again.
1409 FIXME - we shouldn't loop forever! Give up after some time! */
1412 goto LockHandleFrom
;
1414 else if ((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1416 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1417 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1418 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1419 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1420 goto LockHandleFrom
;
1424 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1432 GDI_MapHandleTable(PSECTION_OBJECT SectionObject
, PEPROCESS Process
)
1434 PVOID MappedView
= NULL
;
1436 LARGE_INTEGER Offset
;
1437 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1439 Offset
.QuadPart
= 0;
1441 ASSERT(SectionObject
!= NULL
);
1442 ASSERT(Process
!= NULL
);
1444 Status
= MmMapViewOfSection(SectionObject
,
1455 if (!NT_SUCCESS(Status
))
1461 /** PUBLIC FUNCTIONS **********************************************************/
1464 Since Brush/Pen and Region objects are sharable,,, we can just use
1465 UserHeapAlloc to allocate the small attribute objects.
1469 // Save Kernel Space Pointer
1470 (PGDIBRUSHOBJ)->pBrushAttr = IntGdiAllocObjAttr(GDIObjType_BRUSH_TYPE);
1472 // Kernel Space to User Space Pointer
1473 (PGDI_TABLE_ENTRY)->UserData = pBrushAttr;
1474 // Gdi will adjust for heap delta.
1478 (PGDI_TABLE_ENTRY)->UserData = NULL; // Zero the user ptr.
1479 UserHeapFree((PGDIBRUSHOBJ)->pBrushAttr); // Free from kernel ptr.
1480 (PGDIBRUSHOBJ)->pBrushAttr = NULL;
1483 Testing with DC_ATTR works but has drawing difficulties.
1484 Base on observation, (Over looking the obvious) we need to supply heap delta
1485 to user space gdi. Now, with testing, looks all normal.
1490 IntGdiAllocObjAttr(GDIOBJTYPE Type
)
1492 PVOID pMemAttr
= NULL
;
1496 case GDIObjType_DC_TYPE
:
1497 pMemAttr
= UserHeapAlloc(sizeof(DC_ATTR
));
1498 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(DC_ATTR
));
1500 case GDIObjType_RGN_TYPE
:
1501 pMemAttr
= UserHeapAlloc(sizeof(RGN_ATTR
));
1502 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(RGN_ATTR
));
1504 case GDIObjType_BRUSH_TYPE
:
1505 pMemAttr
= UserHeapAlloc(sizeof(BRUSH_ATTR
));
1506 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(BRUSH_ATTR
));
1517 IntGdiSetBrushOwner(PGDIBRUSHOBJ pbr
, DWORD OwnerMask
)
1520 PEPROCESS Owner
= NULL
;
1521 PGDI_TABLE_ENTRY pEntry
= NULL
;
1523 if (!pbr
) return FALSE
;
1525 hBR
= pbr
->BaseObject
.hHmgr
;
1527 if (!hBR
|| (GDI_HANDLE_GET_TYPE(hBR
) != GDI_OBJECT_TYPE_BRUSH
))
1531 INT Index
= GDI_HANDLE_GET_INDEX((HGDIOBJ
)hBR
);
1532 pEntry
= &GdiHandleTable
->Entries
[Index
];
1535 if (pbr
->flAttrs
& GDIBRUSH_IS_GLOBAL
)
1537 GDIOBJ_ShareUnlockObjByPtr((POBJ
)pbr
);
1541 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1543 // Set this Brush to inaccessible mode and to an Owner of NONE.
1544 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1546 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, Owner
))
1549 // Deny user access to User Data.
1550 pEntry
->UserData
= NULL
; // This hBR is inaccessible!
1553 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1555 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, PsGetCurrentProcess() ))
1558 // Allow user access to User Data.
1559 pEntry
->UserData
= pbr
->pBrushAttr
;
1567 IntGdiSetDCOwnerEx( HDC hDC
, DWORD OwnerMask
, BOOL NoSetBrush
)
1572 if (!hDC
|| (GDI_HANDLE_GET_TYPE(hDC
) != GDI_OBJECT_TYPE_DC
)) return FALSE
;
1574 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1576 pDC
= DC_LockDc ( hDC
);
1577 MmCopyFromCaller(&pDC
->Dc_Attr
, pDC
->pDc_Attr
, sizeof(DC_ATTR
));
1580 DC_FreeDcAttr( hDC
); // Free the dcattr!
1582 if (!DC_SetOwnership( hDC
, NULL
)) // This hDC is inaccessible!
1586 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1588 pDC
= DC_LockDc ( hDC
);
1589 if ( !pDC
->pDc_Attr
) Ret
= TRUE
; // Must be zero.
1591 if (!Ret
) return Ret
;
1593 if (!DC_SetOwnership( hDC
, PsGetCurrentProcess() )) return Ret
;
1595 DC_AllocateDcAttr( hDC
); // Allocate new dcattr
1597 DCU_SynchDcAttrtoUser( hDC
); // Copy data from dc to dcattr
1600 if ((OwnerMask
!= GDI_OBJ_HMGR_NONE
) && !NoSetBrush
)
1602 pDC
= DC_LockDc ( hDC
);
1603 if (IntGdiSetBrushOwner((PGDIBRUSHOBJ
)pDC
->DcLevel
.pbrFill
, OwnerMask
))
1604 IntGdiSetBrushOwner((PGDIBRUSHOBJ
)pDC
->DcLevel
.pbrLine
, OwnerMask
);
1613 NtGdiCreateClientObj(
1620 /* Mask out everything that would change the type in a wrong manner */
1621 ulType
&= (GDI_HANDLE_TYPE_MASK
& ~GDI_HANDLE_BASETYPE_MASK
);
1623 /* Allocate a new object */
1624 pObject
= GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ
| ulType
);
1630 /* get the handle */
1631 handle
= pObject
->hHmgr
;
1634 GDIOBJ_UnlockObjByPtr(pObject
);
1642 NtGdiDeleteClientObj(
1646 /* We first need to get the real type from the handle */
1647 ULONG type
= GDI_HANDLE_GET_TYPE(h
);
1649 /* Check if it's really a CLIENTOBJ */
1650 if ((type
& GDI_HANDLE_BASETYPE_MASK
) != GDILoObjType_LO_CLIENTOBJ_TYPE
)
1652 /* FIXME: SetLastError? */
1655 return GDIOBJ_FreeObjByHandle(h
, type
);
1660 IntGdiGetObject(IN HANDLE Handle
,
1668 pGdiObject
= GDIOBJ_LockObj(Handle
, GDI_OBJECT_TYPE_DONTCARE
);
1671 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1675 dwObjectType
= GDIOBJ_GetObjectType(Handle
);
1676 switch (dwObjectType
)
1678 case GDI_OBJECT_TYPE_PEN
:
1679 case GDI_OBJECT_TYPE_EXTPEN
:
1680 Result
= PEN_GetObject((PGDIBRUSHOBJ
) pGdiObject
, cbCount
, (PLOGPEN
) lpBuffer
); // IntGdiCreatePenIndirect
1683 case GDI_OBJECT_TYPE_BRUSH
:
1684 Result
= BRUSH_GetObject((PGDIBRUSHOBJ
) pGdiObject
, cbCount
, (LPLOGBRUSH
)lpBuffer
);
1687 case GDI_OBJECT_TYPE_BITMAP
:
1688 Result
= BITMAP_GetObject((SURFACE
*) pGdiObject
, cbCount
, lpBuffer
);
1690 case GDI_OBJECT_TYPE_FONT
:
1691 Result
= FontGetObject((PTEXTOBJ
) pGdiObject
, cbCount
, lpBuffer
);
1693 // Fix the LOGFONT structure for the stock fonts
1694 if (FIRST_STOCK_HANDLE
<= Handle
&& Handle
<= LAST_STOCK_HANDLE
)
1696 FixStockFontSizeW(Handle
, cbCount
, lpBuffer
);
1701 case GDI_OBJECT_TYPE_PALETTE
:
1702 Result
= PALETTE_GetObject((PPALGDI
) pGdiObject
, cbCount
, lpBuffer
);
1706 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType
);
1710 GDIOBJ_UnlockObjByPtr(pGdiObject
);
1720 NtGdiExtGetObjectW(IN HANDLE hGdiObj
,
1722 OUT LPVOID lpBuffer
)
1729 DIBSECTION dibsection
;
1733 EXTLOGFONTW extlogfontw
;
1734 ENUMLOGFONTEXDVW enumlogfontexdvw
;
1737 // Normalize to the largest supported object size
1738 cbCount
= min((UINT
)cbCount
, sizeof(Object
));
1740 // Now do the actual call
1741 iRetCount
= IntGdiGetObject(hGdiObj
, cbCount
, lpBuffer
? &Object
: NULL
);
1742 cbCopyCount
= min((UINT
)cbCount
, (UINT
)iRetCount
);
1744 // Make sure we have a buffer and a copy size
1745 if ((cbCopyCount
) && (lpBuffer
))
1747 // Enter SEH for buffer transfer
1750 // Probe the buffer and copy it
1751 ProbeForWrite(lpBuffer
, cbCopyCount
, sizeof(WORD
));
1752 RtlCopyMemory(lpBuffer
, &Object
, cbCopyCount
);
1754 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1756 // Clear the return value.
1757 // Do *NOT* set last error here!