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 BOOL INTERNAL_CALL
GDI_CleanupDummy(PVOID ObjectBody
);
31 /** GLOBALS *******************************************************************/
38 GDICLEANUPPROC CleanupProc
;
39 } OBJ_TYPE_INFO
, *POBJ_TYPE_INFO
;
42 OBJ_TYPE_INFO ObjTypeInfo
[BASE_OBJTYPE_COUNT
] =
44 {0, 0, 0, NULL
}, /* 00 reserved entry */
45 {1, sizeof(DC
), TAG_DC
, DC_Cleanup
}, /* 01 DC */
46 {1, 0, 0, NULL
}, /* 02 UNUSED1 */
47 {1, 0, 0, NULL
}, /* 03 UNUSED2 */
48 {1, sizeof(ROSRGNDATA
), TAG_REGION
, REGION_Cleanup
}, /* 04 RGN */
49 {1, sizeof(BITMAPOBJ
), TAG_SURFACE
, BITMAP_Cleanup
}, /* 05 SURFACE */
50 {1, sizeof(CLIENTOBJ
), TAG_CLIENTOBJ
, GDI_CleanupDummy
}, /* 06 CLIENTOBJ: METADC,... */
51 {1, sizeof(PATH
), TAG_PATH
, GDI_CleanupDummy
}, /* 07 PATH */
52 {1, sizeof(PALGDI
), TAG_PALETTE
, PALETTE_Cleanup
}, /* 08 PAL */
53 {1, sizeof(COLORSPACE
), TAG_ICMLCS
, GDI_CleanupDummy
}, /* 09 ICMLCS, */
54 {1, sizeof(TEXTOBJ
), TAG_LFONT
, GDI_CleanupDummy
}, /* 0a LFONT */
55 {0, 0, TAG_RFONT
, NULL
}, /* 0b RFONT, unused */
56 {0, 0, TAG_PFE
, NULL
}, /* 0c PFE, unused */
57 {0, 0, TAG_PFT
, NULL
}, /* 0d PFT, unused */
58 {0, sizeof(GDICLRXFORM
), TAG_ICMCXF
, GDI_CleanupDummy
}, /* 0e ICMCXF, */
59 {0, 0, TAG_SPRITE
, NULL
}, /* 0f SPRITE, unused */
60 {1, sizeof(GDIBRUSHOBJ
), TAG_BRUSH
, BRUSH_Cleanup
}, /* 10 BRUSH, PEN, EXTPEN */
61 {0, 0, TAG_UMPD
, NULL
}, /* 11 UMPD, unused */
62 {0, 0, 0, NULL
}, /* 12 UNUSED4 */
63 {0, 0, TAG_SPACE
, NULL
}, /* 13 SPACE, unused */
64 {0, 0, 0, NULL
}, /* 14 UNUSED5 */
65 {0, 0, TAG_META
, NULL
}, /* 15 META, unused */
66 {0, 0, TAG_EFSTATE
, NULL
}, /* 16 EFSTATE, unused */
67 {0, 0, TAG_BMFD
, NULL
}, /* 17 BMFD, unused */
68 {0, 0, TAG_VTFD
, NULL
}, /* 18 VTFD, unused */
69 {0, 0, TAG_TTFD
, NULL
}, /* 19 TTFD, unused */
70 {0, 0, TAG_RC
, NULL
}, /* 1a RC, unused */
71 {0, 0, TAG_TEMP
, NULL
}, /* 1b TEMP, unused */
72 {0, 0, TAG_DRVOBJ
, NULL
}, /* 1c DRVOBJ, unused */
73 {0, 0, TAG_DCIOBJ
, NULL
}, /* 1d DCIOBJ, unused */
74 {0, 0, TAG_SPOOL
, NULL
}, /* 1e SPOOL, unused */
75 {0, 0, 0, NULL
}, /* 1f reserved entry */
78 static LARGE_INTEGER ShortDelay
;
80 /** DEBUGGING *****************************************************************/
84 /** INTERNAL FUNCTIONS ********************************************************/
87 * Dummy GDI Cleanup Callback
89 static BOOL INTERNAL_CALL
90 GDI_CleanupDummy(PVOID ObjectBody
)
96 * Allocate GDI object table.
97 * \param Size - number of entries in the object table.
99 PGDI_HANDLE_TABLE INTERNAL_CALL
100 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT
*SectionObject
)
102 PGDI_HANDLE_TABLE HandleTable
= NULL
;
103 LARGE_INTEGER htSize
;
108 ASSERT(SectionObject
!= NULL
);
110 htSize
.QuadPart
= sizeof(GDI_HANDLE_TABLE
);
112 Status
= MmCreateSection((PVOID
*)SectionObject
,
120 if (!NT_SUCCESS(Status
))
123 /* FIXME - use MmMapViewInSessionSpace once available! */
124 Status
= MmMapViewInSystemSpace(*SectionObject
,
125 (PVOID
*)&HandleTable
,
127 if (!NT_SUCCESS(Status
))
129 ObDereferenceObject(*SectionObject
);
130 *SectionObject
= NULL
;
134 RtlZeroMemory(HandleTable
, sizeof(GDI_HANDLE_TABLE
));
136 HandleTable
->LookasideLists
= ExAllocatePoolWithTag(NonPagedPool
,
137 BASE_OBJTYPE_COUNT
* sizeof(PAGED_LOOKASIDE_LIST
),
139 if (HandleTable
->LookasideLists
== NULL
)
141 MmUnmapViewInSystemSpace(HandleTable
);
142 ObDereferenceObject(*SectionObject
);
143 *SectionObject
= NULL
;
147 for (ObjType
= 0; ObjType
< BASE_OBJTYPE_COUNT
; ObjType
++)
149 if (ObjTypeInfo
[ObjType
].bUseLookaside
)
151 ExInitializePagedLookasideList(HandleTable
->LookasideLists
+ ObjType
,
155 ObjTypeInfo
[ObjType
].ulBodySize
,
156 ObjTypeInfo
[ObjType
].Tag
,
161 ShortDelay
.QuadPart
= -5000LL; /* FIXME - 0.5 ms? */
163 HandleTable
->FirstFree
= 0;
164 HandleTable
->FirstUnused
= RESERVE_ENTRIES_COUNT
;
170 LockErrorDebugOutput(HGDIOBJ hObj
, PGDI_TABLE_ENTRY Entry
, LPSTR Function
)
172 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
174 DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function
, hObj
);
175 GDIDBG_TRACEDELETER(hObj
);
177 else if (GDI_HANDLE_GET_REUSECNT(hObj
) != GDI_ENTRY_GET_REUSECNT(Entry
->Type
))
179 DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
180 Function
, hObj
, GDI_HANDLE_GET_REUSECNT(hObj
), GDI_ENTRY_GET_REUSECNT(Entry
->Type
));
182 else if (GDI_HANDLE_GET_TYPE(hObj
) != ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
))
184 DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
185 Function
, hObj
, GDI_HANDLE_GET_TYPE(hObj
), (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
);
189 DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
190 Function
, hObj
, Entry
->Type
);
192 GDIDBG_TRACECALLER();
197 InterlockedPopFreeEntry()
199 ULONG idxFirstFree
, idxNextFree
, idxPrev
;
200 PGDI_TABLE_ENTRY pFreeEntry
;
202 DPRINT("Enter InterLockedPopFreeEntry\n");
206 idxFirstFree
= GdiHandleTable
->FirstFree
;
209 pFreeEntry
= GdiHandleTable
->Entries
+ idxFirstFree
;
210 ASSERT(((ULONG
)pFreeEntry
->KernelData
& ~GDI_HANDLE_INDEX_MASK
) == 0);
211 idxNextFree
= (ULONG
)pFreeEntry
->KernelData
;
212 idxPrev
= (ULONG
)_InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
, idxNextFree
, idxFirstFree
);
216 idxFirstFree
= GdiHandleTable
->FirstUnused
;
217 idxNextFree
= idxFirstFree
+ 1;
218 if (idxNextFree
>= GDI_HANDLE_COUNT
)
220 DPRINT1("No more gdi handles left!\n");
223 idxPrev
= (ULONG
)_InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstUnused
, idxNextFree
, idxFirstFree
);
226 while (idxPrev
!= idxFirstFree
);
231 /* Pushes an entry of the handle table to the free list,
232 The entry must be unlocked and the base type field must be 0 */
235 InterlockedPushFreeEntry(ULONG idxToFree
)
237 ULONG idxFirstFree
, idxPrev
;
238 PGDI_TABLE_ENTRY pFreeEntry
;
240 DPRINT("Enter InterlockedPushFreeEntry\n");
242 pFreeEntry
= GdiHandleTable
->Entries
+ idxToFree
;
243 ASSERT((pFreeEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0);
244 ASSERT(pFreeEntry
->ProcessId
== 0);
245 pFreeEntry
->UserData
= NULL
;
249 idxFirstFree
= GdiHandleTable
->FirstFree
;
250 pFreeEntry
->KernelData
= (PVOID
)idxFirstFree
;
252 idxPrev
= (ULONG
)_InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
, idxToFree
, idxFirstFree
);
254 while (idxPrev
!= idxFirstFree
);
260 GDIOBJ_ValidateHandle(HGDIOBJ hObj
, ULONG ObjectType
)
262 PGDI_TABLE_ENTRY Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
263 if ((((ULONG_PTR
)hObj
& GDI_HANDLE_TYPE_MASK
) == ObjectType
) &&
264 (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == GDI_HANDLE_GET_UPPER(hObj
))
266 HANDLE pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
267 if (pid
== NULL
|| pid
== PsGetCurrentProcessId())
276 GDIOBJ_AllocObj(UCHAR BaseType
)
280 ASSERT((BaseType
& ~GDIObjTypeTotal
) == 0);
281 // BaseType &= GDI_HANDLE_BASETYPE_MASK;
283 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
285 PPAGED_LOOKASIDE_LIST LookasideList
;
287 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
288 pObject
= ExAllocateFromPagedLookasideList(LookasideList
);
292 pObject
= ExAllocatePoolWithTag(PagedPool
,
293 ObjTypeInfo
[BaseType
].ulBodySize
,
294 ObjTypeInfo
[BaseType
].Tag
);
299 RtlZeroMemory(pObject
, ObjTypeInfo
[BaseType
].ulBodySize
);
307 * Allocate memory for GDI object and return handle to it.
309 * \param ObjectType - type of object \ref GDI object types
311 * \return Pointer to the allocated object, which is locked.
314 GDIOBJ_AllocObjWithHandle(ULONG ObjectType
)
316 PW32PROCESS W32Process
;
317 POBJ newObject
= NULL
;
318 HANDLE CurrentProcessId
, LockedProcessId
;
321 GDIDBG_INITLOOPTRACE();
323 W32Process
= PsGetCurrentProcessWin32Process();
324 /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
325 to take too many GDI objects, itself. */
326 if (W32Process
&& W32Process
->GDIObjects
>= 0x2710)
328 DPRINT1("Too many objects for process!!!\n");
329 GDIDBG_DUMPHANDLETABLE();
333 ASSERT(ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
);
335 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(ObjectType
);
337 newObject
= GDIOBJ_AllocObj(TypeIndex
);
340 DPRINT1("Not enough memory to allocate gdi object!\n");
345 PGDI_TABLE_ENTRY Entry
;
348 CurrentProcessId
= PsGetCurrentProcessId();
349 LockedProcessId
= (HANDLE
)((ULONG_PTR
)CurrentProcessId
| 0x1);
351 // RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
353 /* On Windows the higher 16 bit of the type field don't contain the
354 full type from the handle, but the base type.
355 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
356 TypeInfo
= (ObjectType
& GDI_HANDLE_BASETYPE_MASK
) | (ObjectType
>> GDI_ENTRY_UPPER_SHIFT
);
358 Index
= InterlockedPopFreeEntry();
363 Entry
= &GdiHandleTable
->Entries
[Index
];
366 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, 0);
367 if (PrevProcId
== NULL
)
369 PW32THREAD Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
372 Entry
->KernelData
= newObject
;
374 /* copy the reuse-counter */
375 TypeInfo
|= Entry
->Type
& GDI_ENTRY_REUSE_MASK
;
377 /* we found a free entry, no need to exchange this field atomically
378 since we're holding the lock */
379 Entry
->Type
= TypeInfo
;
381 /* Create a handle */
382 Handle
= (HGDIOBJ
)((Index
& 0xFFFF) | (TypeInfo
<< GDI_ENTRY_UPPER_SHIFT
));
384 /* Initialize BaseObject fields */
385 newObject
->hHmgr
= Handle
;
386 newObject
->ulShareCount
= 0;
387 newObject
->cExclusiveLock
= 1;
388 newObject
->Tid
= Thread
;
390 /* unlock the entry */
391 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, CurrentProcessId
);
393 GDIDBG_CAPTUREALLOCATOR(Index
);
395 if (W32Process
!= NULL
)
397 _InterlockedIncrement(&W32Process
->GDIObjects
);
400 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle
, newObject
);
405 GDIDBG_TRACELOOP(Index
, PrevProcId
, CurrentProcessId
);
406 /* damn, someone is trying to lock the object even though it doesn't
407 even exist anymore, wait a little and try again!
408 FIXME - we shouldn't loop forever! Give up after some time! */
415 GDIOBJ_FreeObj(newObject
, TypeIndex
);
417 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
418 GDIDBG_DUMPHANDLETABLE();
425 GDIOBJ_FreeObj(POBJ pObject
, UCHAR BaseType
)
427 /* Object must not have a handle! */
428 ASSERT(pObject
->hHmgr
== NULL
);
430 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
432 PPAGED_LOOKASIDE_LIST LookasideList
;
434 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
435 ExFreeToPagedLookasideList(LookasideList
, pObject
);
444 * Free memory allocated for the GDI object. For each object type this function calls the
445 * appropriate cleanup routine.
447 * \param hObj - handle of the object to be deleted.
449 * \return Returns TRUE if succesful.
450 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
451 * to the calling process.
454 GDIOBJ_FreeObjByHandle(HGDIOBJ hObj
, DWORD ExpectedType
)
456 PGDI_TABLE_ENTRY Entry
;
457 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
458 ULONG HandleType
, HandleUpper
, TypeIndex
;
461 GDIDBG_INITLOOPTRACE();
463 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj
);
465 if (GDI_HANDLE_IS_STOCKOBJ(hObj
))
467 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj
);
468 GDIDBG_TRACECALLER();
472 ProcessId
= PsGetCurrentProcessId();
473 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
475 Silent
= (ExpectedType
& GDI_OBJECT_TYPE_SILENT
);
476 ExpectedType
&= ~GDI_OBJECT_TYPE_SILENT
;
478 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
479 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
481 /* Check if we have the requested type */
482 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
483 HandleType
!= ExpectedType
) ||
486 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
487 hObj
, HandleType
, ExpectedType
);
488 GDIDBG_TRACECALLER();
492 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
495 /* lock the object, we must not delete global objects, so don't exchange the locking
496 process ID to zero when attempting to lock a global object... */
497 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
498 if (PrevProcId
== ProcessId
)
500 if ( (Entry
->KernelData
!= NULL
) &&
501 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) &&
502 ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == (HandleUpper
& GDI_ENTRY_BASETYPE_MASK
)) )
506 Object
= Entry
->KernelData
;
508 if (Object
->cExclusiveLock
== 0)
511 PW32PROCESS W32Process
= PsGetCurrentProcessWin32Process();
513 /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
514 Entry
->Type
= (Entry
->Type
+ GDI_ENTRY_REUSE_INC
) & ~GDI_ENTRY_BASETYPE_MASK
;
516 /* unlock the handle slot */
517 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
519 /* push this entry to the free list */
520 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable
, Entry
));
522 Object
->hHmgr
= NULL
;
524 if (W32Process
!= NULL
)
526 _InterlockedDecrement(&W32Process
->GDIObjects
);
529 /* call the cleanup routine. */
530 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(HandleType
);
531 Ret
= ObjTypeInfo
[TypeIndex
].CleanupProc(Object
);
533 /* Now it's time to free the memory */
534 GDIOBJ_FreeObj(Object
, TypeIndex
);
536 GDIDBG_CAPTUREDELETER(hObj
);
542 * The object is currently locked, so freeing is forbidden!
544 DPRINT1("Object->cExclusiveLock = %d\n", Object
->cExclusiveLock
);
545 GDIDBG_TRACECALLER();
546 GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj
));
547 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
548 /* do not assert here for it will call again from dxg.sys it being call twice */
554 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
555 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
558 else if (PrevProcId
== LockedProcessId
)
560 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
562 /* the object is currently locked, wait some time and try again.
563 FIXME - we shouldn't loop forever! Give up after some time! */
572 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
574 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj
);
576 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
578 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
582 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);
584 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry
->Type
, Entry
->KernelData
, Entry
->ProcessId
);
585 GDIDBG_TRACECALLER();
586 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
595 IsObjectDead(HGDIOBJ hObject
)
597 INT Index
= GDI_HANDLE_GET_INDEX(hObject
);
598 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
599 // We check to see if the objects are knocking on deaths door.
600 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
604 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject
);
605 return TRUE
; // return true and move on.
612 * \param hObject object handle
613 * \return if the function fails the returned value is FALSE.
617 NtGdiDeleteObject(HGDIOBJ hObject
)
619 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
620 if (!IsObjectDead(hObject
))
622 return NULL
!= hObject
623 ? GDIOBJ_FreeObjByHandle(hObject
, GDI_OBJECT_TYPE_DONTCARE
) : FALSE
;
627 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject
);
628 return TRUE
; // return true and move on.
634 IntDeleteHandlesForProcess(struct _EPROCESS
*Process
, ULONG ObjectType
)
636 PGDI_TABLE_ENTRY Entry
, End
;
637 ULONG Index
= RESERVE_ENTRIES_COUNT
;
639 PW32PROCESS W32Process
;
641 W32Process
= (PW32PROCESS
)Process
->Win32Process
;
644 if (W32Process
->GDIObjects
> 0)
646 ProcId
= Process
->UniqueProcessId
;
648 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
649 we should delete it directly here! */
651 End
= &GdiHandleTable
->Entries
[GDI_HANDLE_COUNT
];
652 for (Entry
= &GdiHandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
656 /* ignore the lock bit */
657 if ( (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
)
659 if ( (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == ObjectType
||
660 ObjectType
== GDI_OBJECT_TYPE_DONTCARE
)
662 HGDIOBJ ObjectHandle
;
664 /* Create the object handle for the entry, the lower(!) 16 bit of the
665 Type field includes the type of the object including the stock
666 object flag - but since stock objects don't have a process id we can
667 simply ignore this fact here. */
668 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
670 if (GDIOBJ_FreeObjByHandle(ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
) &&
671 W32Process
->GDIObjects
== 0)
673 /* there are no more gdi handles for this process, bail */
684 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
685 * \param Process - PID of the process that will be destroyed.
688 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
690 PEPROCESS CurrentProcess
;
692 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
693 CurrentProcess
= PsGetCurrentProcess();
694 if (CurrentProcess
!= Process
)
696 KeAttachProcess(&Process
->Pcb
);
699 /* Delete objects. Begin with types that are not referenced by other types */
700 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_DC_TYPE
);
701 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BRUSH_TYPE
);
702 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BITMAP_TYPE
);
704 /* Finally finish with what's left */
705 IntDeleteHandlesForProcess(Process
, GDI_OBJECT_TYPE_DONTCARE
);
707 if (CurrentProcess
!= Process
)
713 GdiDbgHTIntegrityCheck();
716 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
722 * Return pointer to the object by handle.
724 * \param hObj Object handle
725 * \return Pointer to the object.
727 * \note Process can only get pointer to the objects it created or global objects.
729 * \todo Get rid of the ExpectedType parameter!
731 PGDIOBJ INTERNAL_CALL
732 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
735 PGDI_TABLE_ENTRY Entry
;
736 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
738 ULONG HandleType
, HandleUpper
;
740 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
741 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
742 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
744 /* Check that the handle index is valid. */
745 if (HandleIndex
>= GDI_HANDLE_COUNT
)
748 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
750 /* Check if we have the requested type */
751 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
752 HandleType
!= ExpectedType
) ||
755 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
756 hObj
, HandleType
, ExpectedType
);
757 GDIDBG_TRACECALLER();
758 GDIDBG_TRACEALLOCATOR(hObj
);
759 GDIDBG_TRACEDELETER(hObj
);
763 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
764 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
766 /* Check for invalid owner. */
767 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
769 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj
, ProcessId
, HandleProcessId
);
770 GDIDBG_TRACECALLER();
771 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
776 * Prevent the thread from being terminated during the locking process.
777 * It would result in undesired effects and inconsistency of the global
781 KeEnterCriticalRegion();
784 * Loop until we either successfully lock the handle entry & object or
785 * fail some of the check.
790 /* Lock the handle table entry. */
791 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
792 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
796 if (PrevProcId
== HandleProcessId
)
799 * We're locking an object that belongs to our process or it's a
800 * global object if HandleProcessId is 0 here.
803 if ( (Entry
->KernelData
!= NULL
) &&
804 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
806 PW32THREAD Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
807 Object
= Entry
->KernelData
;
809 if (Object
->cExclusiveLock
== 0)
811 Object
->Tid
= Thread
;
812 Object
->cExclusiveLock
= 1;
813 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj
))
817 if (Object
->Tid
!= Thread
)
819 /* Unlock the handle table entry. */
820 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
825 _InterlockedIncrement((PLONG
)&Object
->cExclusiveLock
);
831 * Debugging code. Report attempts to lock deleted handles and
832 * locking type mismatches.
834 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
837 /* Unlock the handle table entry. */
838 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
845 * The handle is currently locked, wait some time and try again.
853 KeLeaveCriticalRegion();
860 * Return pointer to the object by handle (and allow sharing of the handle
863 * \param hObj Object handle
864 * \return Pointer to the object.
866 * \note Process can only get pointer to the objects it created or global objects.
868 * \todo Get rid of the ExpectedType parameter!
870 PGDIOBJ INTERNAL_CALL
871 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
874 PGDI_TABLE_ENTRY Entry
;
875 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
877 ULONG_PTR HandleType
, HandleUpper
;
879 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
880 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
881 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
883 /* Check that the handle index is valid. */
884 if (HandleIndex
>= GDI_HANDLE_COUNT
)
887 /* Check if we have the requested type */
888 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
889 HandleType
!= ExpectedType
) ||
892 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
893 hObj
, HandleType
, ExpectedType
);
897 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
899 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
900 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
902 /* Check for invalid owner. */
903 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
909 * Prevent the thread from being terminated during the locking process.
910 * It would result in undesired effects and inconsistency of the global
914 KeEnterCriticalRegion();
917 * Loop until we either successfully lock the handle entry & object or
918 * fail some of the check.
923 /* Lock the handle table entry. */
924 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
925 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
929 if (PrevProcId
== HandleProcessId
)
932 * We're locking an object that belongs to our process or it's a
933 * global object if HandleProcessId is 0 here.
936 if ( (Entry
->KernelData
!= NULL
) &&
937 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
939 Object
= (POBJ
)Entry
->KernelData
;
942 if (_InterlockedIncrement((PLONG
)&Object
->ulShareCount
) == 1)
944 memset(GDIHandleLocker
[HandleIndex
], 0x00, GDI_STACK_LEVELS
* sizeof(ULONG
));
945 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS
, (PVOID
*)GDIHandleLocker
[HandleIndex
], NULL
);
948 _InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
954 * Debugging code. Report attempts to lock deleted handles and
955 * locking type mismatches.
957 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
960 /* Unlock the handle table entry. */
961 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
968 * The handle is currently locked, wait some time and try again.
976 KeLeaveCriticalRegion();
983 * Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
984 * as soon as you don't need to have access to it's data.
986 * \param Object Object pointer (as returned by GDIOBJ_LockObj).
989 GDIOBJ_UnlockObjByPtr(POBJ Object
)
991 if (_InterlockedDecrement((PLONG
)&Object
->cExclusiveLock
) < 0)
993 DPRINT1("Trying to unlock non-existant object\n");
998 GDIOBJ_ShareUnlockObjByPtr(POBJ Object
)
1000 if (_InterlockedDecrement((PLONG
)&Object
->ulShareCount
) < 0)
1002 DPRINT1("Trying to unlock non-existant object\n");
1007 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
1009 PGDI_TABLE_ENTRY Entry
;
1013 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1015 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1017 ProcessId
= PsGetCurrentProcessId();
1019 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1020 Ret
= Entry
->KernelData
!= NULL
&&
1021 (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0 &&
1022 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1031 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1034 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1035 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1037 PGDI_TABLE_ENTRY Entry
;
1038 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1042 GDIDBG_INITLOOPTRACE();
1047 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj
);
1049 Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
1051 if (!GDI_HANDLE_IS_STOCKOBJ(hObj
))
1053 ProcessId
= PsGetCurrentProcessId();
1054 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1056 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
1059 /* lock the object, we must not convert stock objects, so don't check!!! */
1060 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1061 if (PrevProcId
== ProcessId
)
1063 LONG NewType
, PrevType
, OldType
;
1065 /* we're locking an object that belongs to our process. First calculate
1066 the new object type including the stock object flag and then try to
1068 /* On Windows the higher 16 bit of the type field don't contain the
1069 full type from the handle, but the base type.
1070 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1071 OldType
= ((ULONG
)hObj
& GDI_HANDLE_BASETYPE_MASK
) | ((ULONG
)hObj
>> GDI_ENTRY_UPPER_SHIFT
);
1072 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1073 we copy them as we can't get them from the handle */
1074 OldType
|= Entry
->Type
& GDI_ENTRY_FLAGS_MASK
;
1076 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1077 NewType
= OldType
| GDI_ENTRY_STOCK_MASK
;
1079 /* Try to exchange the type field - but only if the old (previous type) matches! */
1080 PrevType
= _InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1081 if (PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1083 PW32THREAD PrevThread
;
1086 /* We successfully set the stock object flag.
1087 KernelData should never be NULL here!!! */
1088 ASSERT(Entry
->KernelData
);
1090 Object
= Entry
->KernelData
;
1092 PrevThread
= Object
->Tid
;
1093 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1095 /* dereference the process' object counter */
1096 if (PrevProcId
!= GDI_GLOBAL_PROCESS
)
1098 PEPROCESS OldProcess
;
1099 PW32PROCESS W32Process
;
1103 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1104 if (NT_SUCCESS(Status
))
1106 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1107 if (W32Process
!= NULL
)
1109 _InterlockedDecrement(&W32Process
->GDIObjects
);
1111 ObDereferenceObject(OldProcess
);
1115 hObj
= (HGDIOBJ
)((ULONG
)(hObj
) | GDI_HANDLE_STOCK_MASK
);
1117 Object
->hHmgr
= hObj
;
1119 /* remove the process id lock and make it global */
1120 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1122 /* we're done, successfully converted the object */
1127 GDIDBG_TRACELOOP(hObj
, PrevThread
, Thread
);
1129 /* WTF?! The object is already locked by a different thread!
1130 Release the lock, wait a bit and try again!
1131 FIXME - we should give up after some time unless we want to wait forever! */
1132 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1140 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1141 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType
, Entry
->Type
, NewType
, Entry
->KernelData
);
1144 else if (PrevProcId
== LockedProcessId
)
1146 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
1148 /* the object is currently locked, wait some time and try again.
1149 FIXME - we shouldn't loop forever! Give up after some time! */
1156 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1164 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1166 PGDI_TABLE_ENTRY Entry
;
1167 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1171 GDIDBG_INITLOOPTRACE();
1173 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1175 Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
1177 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1179 ProcessId
= PsGetCurrentProcessId();
1180 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1182 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1185 /* lock the object, we must not convert stock objects, so don't check!!! */
1186 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1187 if (PrevProcId
== ProcessId
)
1189 PW32THREAD PrevThread
;
1191 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1193 POBJ Object
= Entry
->KernelData
;
1195 PrevThread
= Object
->Tid
;
1196 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1198 PEPROCESS OldProcess
;
1199 PW32PROCESS W32Process
;
1202 /* dereference the process' object counter */
1204 if ((ULONG_PTR
)PrevProcId
& ~0x1)
1206 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1207 if (NT_SUCCESS(Status
))
1209 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1210 if (W32Process
!= NULL
)
1212 _InterlockedDecrement(&W32Process
->GDIObjects
);
1214 ObDereferenceObject(OldProcess
);
1218 if (NewOwner
!= NULL
)
1220 ProcessId
= PsGetProcessId(NewOwner
);
1222 /* Increase the new process' object counter */
1223 W32Process
= (PW32PROCESS
)NewOwner
->Win32Process
;
1224 if (W32Process
!= NULL
)
1226 _InterlockedIncrement(&W32Process
->GDIObjects
);
1232 /* remove the process id lock and change it to the new process id */
1233 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
);
1240 GDIDBG_TRACELOOP(ObjectHandle
, PrevThread
, Thread
);
1242 /* WTF?! The object is already locked by a different thread!
1243 Release the lock, wait a bit and try again! DO reset the pid lock
1244 so we make sure we don't access invalid memory in case the object is
1245 being deleted in the meantime (because we don't have aquired a reference
1247 FIXME - we should give up after some time unless we want to wait forever! */
1248 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1256 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1257 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry
->Type
, Entry
->KernelData
);
1261 else if (PrevProcId
== LockedProcessId
)
1263 GDIDBG_TRACELOOP(ObjectHandle
, PrevProcId
, ProcessId
);
1265 /* the object is currently locked, wait some time and try again.
1266 FIXME - we shouldn't loop forever! Give up after some time! */
1271 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1273 /* allow changing ownership of global objects */
1275 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1278 else if ((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1280 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1285 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1293 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1295 PGDI_TABLE_ENTRY FromEntry
;
1297 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1300 GDIDBG_INITLOOPTRACE();
1302 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1304 Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
1306 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1308 FromEntry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, CopyFrom
);
1310 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1311 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1314 /* lock the object, we must not convert stock objects, so don't check!!! */
1315 FromPrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1316 if (FromPrevProcId
== FromProcessId
)
1318 PW32THREAD PrevThread
;
1321 if ((FromEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1323 Object
= FromEntry
->KernelData
;
1325 /* save the pointer to the calling thread so we know it was this thread
1326 that locked the object */
1327 PrevThread
= Object
->Tid
;
1328 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1330 /* now let's change the ownership of the target object */
1332 if (((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1334 PEPROCESS ProcessTo
;
1336 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1338 GDIOBJ_SetOwnership(CopyTo
, ProcessTo
);
1339 ObDereferenceObject(ProcessTo
);
1344 /* mark the object as global */
1345 GDIOBJ_SetOwnership(CopyTo
, NULL
);
1348 (void)_InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1352 GDIDBG_TRACELOOP(CopyFrom
, PrevThread
, Thread
);
1354 /* WTF?! The object is already locked by a different thread!
1355 Release the lock, wait a bit and try again! DO reset the pid lock
1356 so we make sure we don't access invalid memory in case the object is
1357 being deleted in the meantime (because we don't have aquired a reference
1359 FIXME - we should give up after some time unless we want to wait forever! */
1360 (void)_InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1363 goto LockHandleFrom
;
1368 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1372 else if (FromPrevProcId
== FromLockedProcessId
)
1374 GDIDBG_TRACELOOP(CopyFrom
, FromPrevProcId
, FromProcessId
);
1376 /* the object is currently locked, wait some time and try again.
1377 FIXME - we shouldn't loop forever! Give up after some time! */
1380 goto LockHandleFrom
;
1382 else if ((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1384 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1385 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1386 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1387 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1388 goto LockHandleFrom
;
1392 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1400 GDI_MapHandleTable(PSECTION_OBJECT SectionObject
, PEPROCESS Process
)
1402 PVOID MappedView
= NULL
;
1404 LARGE_INTEGER Offset
;
1405 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1407 Offset
.QuadPart
= 0;
1409 ASSERT(SectionObject
!= NULL
);
1410 ASSERT(Process
!= NULL
);
1412 Status
= MmMapViewOfSection(SectionObject
,
1423 if (!NT_SUCCESS(Status
))
1429 /** PUBLIC FUNCTIONS **********************************************************/
1432 Since Brush/Pen and Region objects are sharable,,, we can just use
1433 UserHeapAlloc to allocate the small attribute objects.
1437 // Save Kernel Space Pointer
1438 (PGDIBRUSHOBJ)->pBrushAttr = IntGdiAllocObjAttr(GDIObjType_BRUSH_TYPE);
1440 // Kernel Space to User Space Pointer
1441 (PGDI_TABLE_ENTRY)->UserData = pBrushAttr;
1442 // Gdi will adjust for heap delta.
1446 (PGDI_TABLE_ENTRY)->UserData = NULL; // Zero the user ptr.
1447 UserHeapFree((PGDIBRUSHOBJ)->pBrushAttr); // Free from kernel ptr.
1448 (PGDIBRUSHOBJ)->pBrushAttr = NULL;
1451 Testing with DC_ATTR works but has drawing difficulties.
1452 Base on observation, (Over looking the obvious) we need to supply heap delta
1453 to user space gdi. Now, with testing, looks all normal.
1458 IntGdiAllocObjAttr(GDIOBJTYPE Type
)
1460 PVOID pMemAttr
= NULL
;
1464 case GDIObjType_DC_TYPE
:
1465 pMemAttr
= UserHeapAlloc(sizeof(DC_ATTR
));
1466 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(DC_ATTR
));
1468 case GDIObjType_RGN_TYPE
:
1469 pMemAttr
= UserHeapAlloc(sizeof(RGN_ATTR
));
1470 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(RGN_ATTR
));
1472 case GDIObjType_BRUSH_TYPE
:
1473 pMemAttr
= UserHeapAlloc(sizeof(BRUSH_ATTR
));
1474 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(BRUSH_ATTR
));
1485 IntGdiSetBrushOwner(PGDIBRUSHOBJ pbr
, DWORD OwnerMask
)
1488 PEPROCESS Owner
= NULL
;
1489 PGDI_TABLE_ENTRY pEntry
= NULL
;
1491 if (!pbr
) return FALSE
;
1493 hBR
= pbr
->BaseObject
.hHmgr
;
1495 if (!hBR
|| (GDI_HANDLE_GET_TYPE(hBR
) != GDI_OBJECT_TYPE_BRUSH
))
1499 INT Index
= GDI_HANDLE_GET_INDEX((HGDIOBJ
)hBR
);
1500 pEntry
= &GdiHandleTable
->Entries
[Index
];
1503 if (pbr
->flAttrs
& GDIBRUSH_IS_GLOBAL
)
1505 GDIOBJ_ShareUnlockObjByPtr((POBJ
)pbr
);
1509 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1511 // Set this Brush to inaccessible mode and to an Owner of NONE.
1512 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1514 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, Owner
))
1517 // Deny user access to User Data.
1518 pEntry
->UserData
= NULL
; // This hBR is inaccessible!
1521 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1523 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, PsGetCurrentProcess() ))
1526 // Allow user access to User Data.
1527 pEntry
->UserData
= pbr
->pBrushAttr
;
1535 IntGdiSetDCOwnerEx( HDC hDC
, DWORD OwnerMask
, BOOL NoSetBrush
)
1540 if (!hDC
|| (GDI_HANDLE_GET_TYPE(hDC
) != GDI_OBJECT_TYPE_DC
)) return FALSE
;
1542 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1544 pDC
= DC_LockDc ( hDC
);
1545 MmCopyFromCaller(&pDC
->Dc_Attr
, pDC
->pDc_Attr
, sizeof(DC_ATTR
));
1548 DC_FreeDcAttr( hDC
); // Free the dcattr!
1550 if (!DC_SetOwnership( hDC
, NULL
)) // This hDC is inaccessible!
1554 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1556 pDC
= DC_LockDc ( hDC
);
1557 if ( !pDC
->pDc_Attr
) Ret
= TRUE
; // Must be zero.
1559 if (!Ret
) return Ret
;
1561 if (!DC_SetOwnership( hDC
, PsGetCurrentProcess() )) return Ret
;
1563 DC_AllocateDcAttr( hDC
); // Allocate new dcattr
1565 DCU_SynchDcAttrtoUser( hDC
); // Copy data from dc to dcattr
1568 if ((OwnerMask
!= GDI_OBJ_HMGR_NONE
) && !NoSetBrush
)
1570 pDC
= DC_LockDc ( hDC
);
1571 if (IntGdiSetBrushOwner((PGDIBRUSHOBJ
)pDC
->DcLevel
.pbrFill
, OwnerMask
))
1572 IntGdiSetBrushOwner((PGDIBRUSHOBJ
)pDC
->DcLevel
.pbrLine
, OwnerMask
);
1581 NtGdiCreateClientObj(
1588 /* Mask out everything that would change the type in a wrong manner */
1589 ulType
&= (GDI_HANDLE_TYPE_MASK
& ~GDI_HANDLE_BASETYPE_MASK
);
1591 /* Allocate a new object */
1592 pObject
= GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ
| ulType
);
1598 /* get the handle */
1599 handle
= pObject
->hHmgr
;
1602 GDIOBJ_UnlockObjByPtr(pObject
);
1610 NtGdiDeleteClientObj(
1614 /* We first need to get the real type from the handle */
1615 ULONG type
= GDI_HANDLE_GET_TYPE(h
);
1617 /* Check if it's really a CLIENTOBJ */
1618 if ((type
& GDI_HANDLE_BASETYPE_MASK
) != GDILoObjType_LO_CLIENTOBJ_TYPE
)
1620 /* FIXME: SetLastError? */
1623 return GDIOBJ_FreeObjByHandle(h
, type
);
1628 IntGdiGetObject(IN HANDLE Handle
,
1636 pGdiObject
= GDIOBJ_LockObj(Handle
, GDI_OBJECT_TYPE_DONTCARE
);
1639 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1643 dwObjectType
= GDIOBJ_GetObjectType(Handle
);
1644 switch (dwObjectType
)
1646 case GDI_OBJECT_TYPE_PEN
:
1647 case GDI_OBJECT_TYPE_EXTPEN
:
1648 Result
= PEN_GetObject((PGDIBRUSHOBJ
) pGdiObject
, cbCount
, (PLOGPEN
) lpBuffer
); // IntGdiCreatePenIndirect
1651 case GDI_OBJECT_TYPE_BRUSH
:
1652 Result
= BRUSH_GetObject((PGDIBRUSHOBJ
) pGdiObject
, cbCount
, (LPLOGBRUSH
)lpBuffer
);
1655 case GDI_OBJECT_TYPE_BITMAP
:
1656 Result
= BITMAP_GetObject((BITMAPOBJ
*) pGdiObject
, cbCount
, lpBuffer
);
1658 case GDI_OBJECT_TYPE_FONT
:
1659 Result
= FontGetObject((PTEXTOBJ
) pGdiObject
, cbCount
, lpBuffer
);
1661 // Fix the LOGFONT structure for the stock fonts
1662 if (FIRST_STOCK_HANDLE
<= Handle
&& Handle
<= LAST_STOCK_HANDLE
)
1664 FixStockFontSizeW(Handle
, cbCount
, lpBuffer
);
1669 case GDI_OBJECT_TYPE_PALETTE
:
1670 Result
= PALETTE_GetObject((PPALGDI
) pGdiObject
, cbCount
, lpBuffer
);
1674 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType
);
1678 GDIOBJ_UnlockObjByPtr(pGdiObject
);
1688 NtGdiExtGetObjectW(IN HANDLE hGdiObj
,
1690 OUT LPVOID lpBuffer
)
1697 DIBSECTION dibsection
;
1701 EXTLOGFONTW extlogfontw
;
1702 ENUMLOGFONTEXDVW enumlogfontexdvw
;
1705 // Normalize to the largest supported object size
1706 cbCount
= min((UINT
)cbCount
, sizeof(Object
));
1708 // Now do the actual call
1709 iRetCount
= IntGdiGetObject(hGdiObj
, cbCount
, lpBuffer
? &Object
: NULL
);
1710 cbCopyCount
= min((UINT
)cbCount
, (UINT
)iRetCount
);
1712 // Make sure we have a buffer and a copy size
1713 if ((cbCopyCount
) && (lpBuffer
))
1715 // Enter SEH for buffer transfer
1718 // Probe the buffer and copy it
1719 ProbeForWrite(lpBuffer
, cbCopyCount
, sizeof(WORD
));
1720 RtlCopyMemory(lpBuffer
, &Object
, cbCopyCount
);
1724 // Clear the return value.
1725 // Do *NOT* set last error here!