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 DelayExecution() \
24 DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
25 KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
27 static BOOL INTERNAL_CALL
GDI_CleanupDummy(PVOID ObjectBody
);
29 /** GLOBALS *******************************************************************/
36 GDICLEANUPPROC CleanupProc
;
37 } OBJ_TYPE_INFO
, *POBJ_TYPE_INFO
;
40 OBJ_TYPE_INFO ObjTypeInfo
[] =
42 {0, 0, 0, NULL
}, /* 00 reserved entry */
43 {1, sizeof(DC
), TAG_DC
, DC_Cleanup
}, /* 01 DC */
44 {1, 0, 0, NULL
}, /* 02 UNUSED1 */
45 {1, 0, 0, NULL
}, /* 03 UNUSED2 */
46 {1, sizeof(ROSRGNDATA
), TAG_REGION
, REGION_Cleanup
}, /* 04 RGN */
47 {1, sizeof(BITMAPOBJ
), TAG_SURFACE
, BITMAP_Cleanup
}, /* 05 SURFACE */
48 {1, sizeof(CLIENTOBJ
), TAG_CLIENTOBJ
, GDI_CleanupDummy
}, /* 06 CLIENTOBJ: METADC,... */
49 {0, 0, TAG_PATH
, NULL
}, /* 07 PATH, unused */
50 {1, sizeof(PALGDI
), TAG_PALETTE
, PALETTE_Cleanup
}, /* 08 PAL */
51 {1, sizeof(COLORSPACE
), TAG_ICMLCS
, GDI_CleanupDummy
}, /* 09 ICMLCS, */
52 {1, sizeof(TEXTOBJ
), TAG_LFONT
, GDI_CleanupDummy
}, /* 0a LFONT */
53 {0, 0, TAG_RFONT
, NULL
}, /* 0b RFONT, unused */
54 {0, 0, TAG_PFE
, NULL
}, /* 0c PFE, unused */
55 {0, 0, TAG_PFT
, NULL
}, /* 0d PFT, unused */
56 {0, sizeof(GDICLRXFORM
), TAG_ICMCXF
, GDI_CleanupDummy
}, /* 0e ICMCXF, */
57 {0, 0, TAG_SPRITE
, NULL
}, /* 0f SPRITE, unused */
58 {1, sizeof(GDIBRUSHOBJ
), TAG_BRUSH
, BRUSH_Cleanup
}, /* 10 BRUSH, PEN, EXTPEN */
59 {0, 0, TAG_UMPD
, NULL
}, /* 11 UMPD, unused */
60 {0, 0, 0, NULL
}, /* 12 UNUSED4 */
61 {0, 0, TAG_SPACE
, NULL
}, /* 13 SPACE, unused */
62 {0, 0, 0, NULL
}, /* 14 UNUSED5 */
63 {0, 0, TAG_META
, NULL
}, /* 15 META, unused */
64 {0, 0, TAG_EFSTATE
, NULL
}, /* 16 EFSTATE, unused */
65 {0, 0, TAG_BMFD
, NULL
}, /* 17 BMFD, unused */
66 {0, 0, TAG_VTFD
, NULL
}, /* 18 VTFD, unused */
67 {0, 0, TAG_TTFD
, NULL
}, /* 19 TTFD, unused */
68 {0, 0, TAG_RC
, NULL
}, /* 1a RC, unused */
69 {0, 0, TAG_TEMP
, NULL
}, /* 1b TEMP, unused */
70 {0, 0, TAG_DRVOBJ
, NULL
}, /* 1c DRVOBJ, unused */
71 {0, 0, TAG_DCIOBJ
, NULL
}, /* 1d DCIOBJ, unused */
72 {0, 0, TAG_SPOOL
, NULL
}, /* 1e SPOOL, unused */
75 #define BASE_OBJTYPE_COUNT (sizeof(ObjTypeInfo) / sizeof(ObjTypeInfo[0]))
77 static LARGE_INTEGER ShortDelay
;
79 /** DEBUGGING *****************************************************************/
83 /** INTERNAL FUNCTIONS ********************************************************/
86 * Dummy GDI Cleanup Callback
88 static BOOL INTERNAL_CALL
89 GDI_CleanupDummy(PVOID ObjectBody
)
95 * Allocate GDI object table.
96 * \param Size - number of entries in the object table.
98 PGDI_HANDLE_TABLE INTERNAL_CALL
99 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT
*SectionObject
)
101 PGDI_HANDLE_TABLE HandleTable
= NULL
;
102 LARGE_INTEGER htSize
;
107 ASSERT(SectionObject
!= NULL
);
109 htSize
.QuadPart
= sizeof(GDI_HANDLE_TABLE
);
111 Status
= MmCreateSection((PVOID
*)SectionObject
,
119 if (!NT_SUCCESS(Status
))
122 /* FIXME - use MmMapViewInSessionSpace once available! */
123 Status
= MmMapViewInSystemSpace(*SectionObject
,
124 (PVOID
*)&HandleTable
,
126 if (!NT_SUCCESS(Status
))
128 ObDereferenceObject(*SectionObject
);
129 *SectionObject
= NULL
;
133 RtlZeroMemory(HandleTable
, sizeof(GDI_HANDLE_TABLE
));
135 HandleTable
->LookasideLists
= ExAllocatePoolWithTag(NonPagedPool
,
136 BASE_OBJTYPE_COUNT
* sizeof(PAGED_LOOKASIDE_LIST
),
138 if (HandleTable
->LookasideLists
== NULL
)
140 MmUnmapViewInSystemSpace(HandleTable
);
141 ObDereferenceObject(*SectionObject
);
142 *SectionObject
= NULL
;
146 for (ObjType
= 0; ObjType
< BASE_OBJTYPE_COUNT
; ObjType
++)
148 if (ObjTypeInfo
[ObjType
].bUseLookaside
)
150 ExInitializePagedLookasideList(HandleTable
->LookasideLists
+ ObjType
,
154 ObjTypeInfo
[ObjType
].ulBodySize
,
155 ObjTypeInfo
[ObjType
].Tag
,
160 ShortDelay
.QuadPart
= -5000LL; /* FIXME - 0.5 ms? */
162 HandleTable
->FirstFree
= 0;
163 HandleTable
->FirstUnused
= RESERVE_ENTRIES_COUNT
;
169 LockErrorDebugOutput(HGDIOBJ hObj
, PGDI_TABLE_ENTRY Entry
, LPSTR Function
)
171 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
173 DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function
, hObj
);
174 GDIDBG_TRACEDELETER(hObj
);
176 else if (GDI_HANDLE_GET_REUSECNT(hObj
) != GDI_ENTRY_GET_REUSECNT(Entry
->Type
))
178 DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
179 Function
, hObj
, GDI_HANDLE_GET_REUSECNT(hObj
), GDI_ENTRY_GET_REUSECNT(Entry
->Type
));
181 else if (GDI_HANDLE_GET_TYPE(hObj
) != ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
))
183 DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
184 Function
, hObj
, GDI_HANDLE_GET_TYPE(hObj
), (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
);
188 DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
189 Function
, hObj
, Entry
->Type
);
191 GDIDBG_TRACECALLER();
196 InterlockedPopFreeEntry()
198 ULONG idxFirstFree
, idxNextFree
, idxPrev
;
199 PGDI_TABLE_ENTRY pFreeEntry
;
201 DPRINT("Enter InterLockedPopFreeEntry\n");
205 idxFirstFree
= GdiHandleTable
->FirstFree
;
208 pFreeEntry
= GdiHandleTable
->Entries
+ idxFirstFree
;
209 ASSERT(((ULONG
)pFreeEntry
->KernelData
& ~GDI_HANDLE_INDEX_MASK
) == 0);
210 idxNextFree
= (ULONG
)pFreeEntry
->KernelData
;
211 idxPrev
= (ULONG
)_InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
, idxNextFree
, idxFirstFree
);
215 idxFirstFree
= GdiHandleTable
->FirstUnused
;
216 idxNextFree
= idxFirstFree
+ 1;
217 if (idxNextFree
>= GDI_HANDLE_COUNT
)
219 DPRINT1("No more gdi handles left!\n");
222 idxPrev
= (ULONG
)_InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstUnused
, idxNextFree
, idxFirstFree
);
225 while (idxPrev
!= idxFirstFree
);
230 /* Pushes an entry of the handle table to the free list,
231 The entry must be unlocked and the base type field must be 0 */
234 InterlockedPushFreeEntry(ULONG idxToFree
)
236 ULONG idxFirstFree
, idxPrev
;
237 PGDI_TABLE_ENTRY pFreeEntry
;
239 DPRINT("Enter InterlockedPushFreeEntry\n");
241 pFreeEntry
= GdiHandleTable
->Entries
+ idxToFree
;
242 ASSERT((pFreeEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0);
243 ASSERT(pFreeEntry
->ProcessId
== 0);
244 pFreeEntry
->UserData
= NULL
;
248 idxFirstFree
= GdiHandleTable
->FirstFree
;
249 pFreeEntry
->KernelData
= (PVOID
)idxFirstFree
;
251 idxPrev
= (ULONG
)_InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
, idxToFree
, idxFirstFree
);
253 while (idxPrev
!= idxFirstFree
);
259 GDIOBJ_ValidateHandle(HGDIOBJ hObj
, ULONG ObjectType
)
261 PGDI_TABLE_ENTRY Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
262 if ((((ULONG_PTR
)hObj
& GDI_HANDLE_TYPE_MASK
) == ObjectType
) &&
263 (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == GDI_HANDLE_GET_UPPER(hObj
))
265 HANDLE pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
266 if (pid
== NULL
|| pid
== PsGetCurrentProcessId())
275 GDIOBJ_AllocObj(UCHAR BaseType
)
279 ASSERT((BaseType
& ~GDIObjTypeTotal
) == 0);
280 // BaseType &= GDI_HANDLE_BASETYPE_MASK;
282 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
284 PPAGED_LOOKASIDE_LIST LookasideList
;
286 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
287 pObject
= ExAllocateFromPagedLookasideList(LookasideList
);
291 pObject
= ExAllocatePoolWithTag(PagedPool
,
292 ObjTypeInfo
[BaseType
].ulBodySize
,
293 ObjTypeInfo
[BaseType
].Tag
);
298 RtlZeroMemory(pObject
, ObjTypeInfo
[BaseType
].ulBodySize
);
306 * Allocate memory for GDI object and return handle to it.
308 * \param ObjectType - type of object \ref GDI object types
310 * \return Pointer to the allocated object, which is locked.
313 GDIOBJ_AllocObjWithHandle(ULONG ObjectType
)
315 PW32PROCESS W32Process
;
316 POBJ newObject
= NULL
;
317 HANDLE CurrentProcessId
, LockedProcessId
;
320 GDIDBG_INITLOOPTRACE();
322 W32Process
= PsGetCurrentProcessWin32Process();
323 /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
324 to take too many GDI objects, itself. */
325 if (W32Process
&& W32Process
->GDIObjects
>= 0x2710)
328 ASSERT(ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
);
330 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(ObjectType
);
332 newObject
= GDIOBJ_AllocObj(TypeIndex
);
335 DPRINT1("Not enough memory to allocate gdi object!\n");
340 PGDI_TABLE_ENTRY Entry
;
343 CurrentProcessId
= PsGetCurrentProcessId();
344 LockedProcessId
= (HANDLE
)((ULONG_PTR
)CurrentProcessId
| 0x1);
346 // RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
348 /* On Windows the higher 16 bit of the type field don't contain the
349 full type from the handle, but the base type.
350 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
351 TypeInfo
= (ObjectType
& GDI_HANDLE_BASETYPE_MASK
) | (ObjectType
>> GDI_ENTRY_UPPER_SHIFT
);
353 Index
= InterlockedPopFreeEntry();
358 Entry
= &GdiHandleTable
->Entries
[Index
];
361 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, 0);
362 if (PrevProcId
== NULL
)
364 PW32THREAD Thread
= PsGetCurrentThreadWin32Thread();
367 Entry
->KernelData
= newObject
;
369 /* copy the reuse-counter */
370 TypeInfo
|= Entry
->Type
& GDI_ENTRY_REUSE_MASK
;
372 /* we found a free entry, no need to exchange this field atomically
373 since we're holding the lock */
374 Entry
->Type
= TypeInfo
;
376 /* Create a handle */
377 Handle
= (HGDIOBJ
)((Index
& 0xFFFF) | (TypeInfo
<< GDI_ENTRY_UPPER_SHIFT
));
379 /* Initialize BaseObject fields */
380 newObject
->hHmgr
= Handle
;
381 newObject
->ulShareCount
= 0;
382 newObject
->cExclusiveLock
= 1;
383 newObject
->Tid
= Thread
;
385 /* unlock the entry */
386 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, CurrentProcessId
);
388 GDIDBG_CAPTUREALLOCATOR(Index
);
390 if (W32Process
!= NULL
)
392 _InterlockedIncrement(&W32Process
->GDIObjects
);
395 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle
, newObject
);
400 GDIDBG_TRACELOOP(Index
, PrevProcId
, CurrentProcessId
);
401 /* damn, someone is trying to lock the object even though it doesn't
402 even exist anymore, wait a little and try again!
403 FIXME - we shouldn't loop forever! Give up after some time! */
410 GDIOBJ_FreeObj(newObject
, TypeIndex
);
412 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
413 GDIDBG_DUMPHANDLETABLE();
420 GDIOBJ_FreeObj(POBJ pObject
, UCHAR BaseType
)
422 /* Object must not have a handle! */
423 ASSERT(pObject
->hHmgr
== NULL
);
425 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
427 PPAGED_LOOKASIDE_LIST LookasideList
;
429 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
430 ExFreeToPagedLookasideList(LookasideList
, pObject
);
439 * Free memory allocated for the GDI object. For each object type this function calls the
440 * appropriate cleanup routine.
442 * \param hObj - handle of the object to be deleted.
444 * \return Returns TRUE if succesful.
445 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
446 * to the calling process.
449 GDIOBJ_FreeObjByHandle(HGDIOBJ hObj
, DWORD ExpectedType
)
451 PGDI_TABLE_ENTRY Entry
;
452 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
453 ULONG HandleType
, HandleUpper
, TypeIndex
;
456 GDIDBG_INITLOOPTRACE();
458 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj
);
460 if (GDI_HANDLE_IS_STOCKOBJ(hObj
))
462 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj
);
463 GDIDBG_TRACECALLER();
467 ProcessId
= PsGetCurrentProcessId();
468 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
470 Silent
= (ExpectedType
& GDI_OBJECT_TYPE_SILENT
);
471 ExpectedType
&= ~GDI_OBJECT_TYPE_SILENT
;
473 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
474 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
476 /* Check if we have the requested type */
477 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
478 HandleType
!= ExpectedType
) ||
481 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
482 hObj
, HandleType
, ExpectedType
);
483 GDIDBG_TRACECALLER();
487 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
490 /* lock the object, we must not delete global objects, so don't exchange the locking
491 process ID to zero when attempting to lock a global object... */
492 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
493 if (PrevProcId
== ProcessId
)
495 if ( (Entry
->KernelData
!= NULL
) &&
496 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) &&
497 ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == (HandleUpper
& GDI_ENTRY_BASETYPE_MASK
)) )
501 Object
= Entry
->KernelData
;
503 if (Object
->cExclusiveLock
== 0)
506 PW32PROCESS W32Process
= PsGetCurrentProcessWin32Process();
508 /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
509 Entry
->Type
= (Entry
->Type
+ GDI_ENTRY_REUSE_INC
) & ~GDI_ENTRY_BASETYPE_MASK
;
511 /* unlock the handle slot */
512 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
514 /* push this entry to the free list */
515 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable
, Entry
));
517 Object
->hHmgr
= NULL
;
519 if (W32Process
!= NULL
)
521 _InterlockedDecrement(&W32Process
->GDIObjects
);
524 /* call the cleanup routine. */
525 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(HandleType
);
526 Ret
= ObjTypeInfo
[TypeIndex
].CleanupProc(Object
);
528 /* Now it's time to free the memory */
529 GDIOBJ_FreeObj(Object
, TypeIndex
);
531 GDIDBG_CAPTUREDELETER(hObj
);
537 * The object is currently locked, so freeing is forbidden!
539 DPRINT1("Object->cExclusiveLock = %d\n", Object
->cExclusiveLock
);
540 GDIDBG_TRACECALLER();
541 GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj
));
542 /* do not assert here for it will call again from dxg.sys it being call twice */
548 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
549 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
552 else if (PrevProcId
== LockedProcessId
)
554 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
556 /* the object is currently locked, wait some time and try again.
557 FIXME - we shouldn't loop forever! Give up after some time! */
566 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
568 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj
);
570 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
572 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
576 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);
578 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry
->Type
, Entry
->KernelData
, Entry
->ProcessId
);
579 GDIDBG_TRACECALLER();
580 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
589 IsObjectDead(HGDIOBJ hObject
)
591 INT Index
= GDI_HANDLE_GET_INDEX(hObject
);
592 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
593 // We check to see if the objects are knocking on deaths door.
594 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
598 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject
);
599 return TRUE
; // return true and move on.
606 * \param hObject object handle
607 * \return if the function fails the returned value is FALSE.
611 NtGdiDeleteObject(HGDIOBJ hObject
)
613 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
614 if (!IsObjectDead(hObject
))
616 return NULL
!= hObject
617 ? GDIOBJ_FreeObjByHandle(hObject
, GDI_OBJECT_TYPE_DONTCARE
) : FALSE
;
621 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject
);
622 return TRUE
; // return true and move on.
628 IntDeleteHandlesForProcess(struct _EPROCESS
*Process
, ULONG ObjectType
)
630 PGDI_TABLE_ENTRY Entry
, End
;
631 ULONG Index
= RESERVE_ENTRIES_COUNT
;
633 PW32PROCESS W32Process
;
635 W32Process
= (PW32PROCESS
)Process
->Win32Process
;
638 if (W32Process
->GDIObjects
> 0)
640 ProcId
= Process
->UniqueProcessId
;
642 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
643 we should delete it directly here! */
645 End
= &GdiHandleTable
->Entries
[GDI_HANDLE_COUNT
];
646 for (Entry
= &GdiHandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
650 /* ignore the lock bit */
651 if ( (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
)
653 if ( (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == ObjectType
||
654 ObjectType
== GDI_OBJECT_TYPE_DONTCARE
)
656 HGDIOBJ ObjectHandle
;
658 /* Create the object handle for the entry, the lower(!) 16 bit of the
659 Type field includes the type of the object including the stock
660 object flag - but since stock objects don't have a process id we can
661 simply ignore this fact here. */
662 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
664 if (GDIOBJ_FreeObjByHandle(ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
) &&
665 W32Process
->GDIObjects
== 0)
667 /* there are no more gdi handles for this process, bail */
678 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
679 * \param Process - PID of the process that will be destroyed.
682 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
684 PEPROCESS CurrentProcess
;
686 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
687 CurrentProcess
= PsGetCurrentProcess();
688 if (CurrentProcess
!= Process
)
690 KeAttachProcess(&Process
->Pcb
);
693 /* Delete objects. Begin with types that are not referenced by other types */
694 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_DC_TYPE
);
695 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BRUSH_TYPE
);
696 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BITMAP_TYPE
);
698 /* Finally finish with what's left */
699 IntDeleteHandlesForProcess(Process
, GDI_OBJECT_TYPE_DONTCARE
);
701 if (CurrentProcess
!= Process
)
707 GdiDbgHTIntegrityCheck();
710 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
716 * Return pointer to the object by handle.
718 * \param hObj Object handle
719 * \return Pointer to the object.
721 * \note Process can only get pointer to the objects it created or global objects.
723 * \todo Get rid of the ExpectedType parameter!
725 PGDIOBJ INTERNAL_CALL
726 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
729 PGDI_TABLE_ENTRY Entry
;
730 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
732 ULONG HandleType
, HandleUpper
;
734 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
735 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
736 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
738 /* Check that the handle index is valid. */
739 if (HandleIndex
>= GDI_HANDLE_COUNT
)
742 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
744 /* Check if we have the requested type */
745 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
746 HandleType
!= ExpectedType
) ||
749 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
750 hObj
, HandleType
, ExpectedType
);
751 GDIDBG_TRACECALLER();
752 GDIDBG_TRACEALLOCATOR(hObj
);
753 GDIDBG_TRACEDELETER(hObj
);
757 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
758 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
760 /* Check for invalid owner. */
761 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
763 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj
, ProcessId
, HandleProcessId
);
764 GDIDBG_TRACECALLER();
765 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
770 * Prevent the thread from being terminated during the locking process.
771 * It would result in undesired effects and inconsistency of the global
775 KeEnterCriticalRegion();
778 * Loop until we either successfully lock the handle entry & object or
779 * fail some of the check.
784 /* Lock the handle table entry. */
785 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
786 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
790 if (PrevProcId
== HandleProcessId
)
793 * We're locking an object that belongs to our process or it's a
794 * global object if HandleProcessId is 0 here.
797 if ( (Entry
->KernelData
!= NULL
) &&
798 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
800 PW32THREAD Thread
= PsGetCurrentThreadWin32Thread();
801 Object
= Entry
->KernelData
;
803 if (Object
->cExclusiveLock
== 0)
805 Object
->Tid
= Thread
;
806 Object
->cExclusiveLock
= 1;
807 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj
))
811 if (Object
->Tid
!= Thread
)
813 /* Unlock the handle table entry. */
814 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
819 _InterlockedIncrement((PLONG
)&Object
->cExclusiveLock
);
825 * Debugging code. Report attempts to lock deleted handles and
826 * locking type mismatches.
828 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
831 /* Unlock the handle table entry. */
832 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
839 * The handle is currently locked, wait some time and try again.
847 KeLeaveCriticalRegion();
854 * Return pointer to the object by handle (and allow sharing of the handle
857 * \param hObj Object handle
858 * \return Pointer to the object.
860 * \note Process can only get pointer to the objects it created or global objects.
862 * \todo Get rid of the ExpectedType parameter!
864 PGDIOBJ INTERNAL_CALL
865 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
868 PGDI_TABLE_ENTRY Entry
;
869 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
871 ULONG_PTR HandleType
, HandleUpper
;
873 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
874 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
875 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
877 /* Check that the handle index is valid. */
878 if (HandleIndex
>= GDI_HANDLE_COUNT
)
881 /* Check if we have the requested type */
882 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
883 HandleType
!= ExpectedType
) ||
886 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
887 hObj
, HandleType
, ExpectedType
);
891 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
893 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
894 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
896 /* Check for invalid owner. */
897 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
903 * Prevent the thread from being terminated during the locking process.
904 * It would result in undesired effects and inconsistency of the global
908 KeEnterCriticalRegion();
911 * Loop until we either successfully lock the handle entry & object or
912 * fail some of the check.
917 /* Lock the handle table entry. */
918 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
919 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
923 if (PrevProcId
== HandleProcessId
)
926 * We're locking an object that belongs to our process or it's a
927 * global object if HandleProcessId is 0 here.
930 if ( (Entry
->KernelData
!= NULL
) &&
931 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
933 Object
= (POBJ
)Entry
->KernelData
;
936 if (_InterlockedIncrement((PLONG
)&Object
->ulShareCount
) == 1)
938 memset(GDIHandleLocker
[HandleIndex
], 0x00, GDI_STACK_LEVELS
* sizeof(ULONG
));
939 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS
, (PVOID
*)GDIHandleLocker
[HandleIndex
], NULL
);
942 _InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
948 * Debugging code. Report attempts to lock deleted handles and
949 * locking type mismatches.
951 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
954 /* Unlock the handle table entry. */
955 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
962 * The handle is currently locked, wait some time and try again.
970 KeLeaveCriticalRegion();
977 * Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
978 * as soon as you don't need to have access to it's data.
980 * \param Object Object pointer (as returned by GDIOBJ_LockObj).
983 GDIOBJ_UnlockObjByPtr(POBJ Object
)
985 if (_InterlockedDecrement((PLONG
)&Object
->cExclusiveLock
) < 0)
987 DPRINT1("Trying to unlock non-existant object\n");
992 GDIOBJ_ShareUnlockObjByPtr(POBJ Object
)
994 if (_InterlockedDecrement((PLONG
)&Object
->ulShareCount
) < 0)
996 DPRINT1("Trying to unlock non-existant object\n");
1001 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
1003 PGDI_TABLE_ENTRY Entry
;
1007 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1009 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1011 ProcessId
= PsGetCurrentProcessId();
1013 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1014 Ret
= Entry
->KernelData
!= NULL
&&
1015 (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0 &&
1016 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1025 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1028 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1029 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1031 PGDI_TABLE_ENTRY Entry
;
1032 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1036 GDIDBG_INITLOOPTRACE();
1041 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj
);
1043 Thread
= PsGetCurrentThreadWin32Thread();
1045 if (!GDI_HANDLE_IS_STOCKOBJ(hObj
))
1047 ProcessId
= PsGetCurrentProcessId();
1048 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1050 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
1053 /* lock the object, we must not convert stock objects, so don't check!!! */
1054 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1055 if (PrevProcId
== ProcessId
)
1057 LONG NewType
, PrevType
, OldType
;
1059 /* we're locking an object that belongs to our process. First calculate
1060 the new object type including the stock object flag and then try to
1062 /* On Windows the higher 16 bit of the type field don't contain the
1063 full type from the handle, but the base type.
1064 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1065 OldType
= ((ULONG
)hObj
& GDI_HANDLE_BASETYPE_MASK
) | ((ULONG
)hObj
>> GDI_ENTRY_UPPER_SHIFT
);
1066 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1067 we copy them as we can't get them from the handle */
1068 OldType
|= Entry
->Type
& GDI_ENTRY_FLAGS_MASK
;
1070 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1071 NewType
= OldType
| GDI_ENTRY_STOCK_MASK
;
1073 /* Try to exchange the type field - but only if the old (previous type) matches! */
1074 PrevType
= _InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1075 if (PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1077 PW32THREAD PrevThread
;
1080 /* We successfully set the stock object flag.
1081 KernelData should never be NULL here!!! */
1082 ASSERT(Entry
->KernelData
);
1084 Object
= Entry
->KernelData
;
1086 PrevThread
= Object
->Tid
;
1087 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1089 /* dereference the process' object counter */
1090 if (PrevProcId
!= GDI_GLOBAL_PROCESS
)
1092 PEPROCESS OldProcess
;
1093 PW32PROCESS W32Process
;
1097 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1098 if (NT_SUCCESS(Status
))
1100 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1101 if (W32Process
!= NULL
)
1103 _InterlockedDecrement(&W32Process
->GDIObjects
);
1105 ObDereferenceObject(OldProcess
);
1109 hObj
= (HGDIOBJ
)((ULONG
)(hObj
) | GDI_HANDLE_STOCK_MASK
);
1111 Object
->hHmgr
= hObj
;
1113 /* remove the process id lock and make it global */
1114 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1116 /* we're done, successfully converted the object */
1121 GDIDBG_TRACELOOP(hObj
, PrevThread
, Thread
);
1123 /* WTF?! The object is already locked by a different thread!
1124 Release the lock, wait a bit and try again!
1125 FIXME - we should give up after some time unless we want to wait forever! */
1126 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1134 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1135 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType
, Entry
->Type
, NewType
, Entry
->KernelData
);
1138 else if (PrevProcId
== LockedProcessId
)
1140 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
1142 /* the object is currently locked, wait some time and try again.
1143 FIXME - we shouldn't loop forever! Give up after some time! */
1150 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1158 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1160 PGDI_TABLE_ENTRY Entry
;
1161 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1165 GDIDBG_INITLOOPTRACE();
1167 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1169 Thread
= PsGetCurrentThreadWin32Thread();
1171 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1173 ProcessId
= PsGetCurrentProcessId();
1174 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1176 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1179 /* lock the object, we must not convert stock objects, so don't check!!! */
1180 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1181 if (PrevProcId
== ProcessId
)
1183 PW32THREAD PrevThread
;
1185 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1187 POBJ Object
= Entry
->KernelData
;
1189 PrevThread
= Object
->Tid
;
1190 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1192 PEPROCESS OldProcess
;
1193 PW32PROCESS W32Process
;
1196 /* dereference the process' object counter */
1198 if ((ULONG_PTR
)PrevProcId
& ~0x1)
1200 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1201 if (NT_SUCCESS(Status
))
1203 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1204 if (W32Process
!= NULL
)
1206 _InterlockedDecrement(&W32Process
->GDIObjects
);
1208 ObDereferenceObject(OldProcess
);
1212 if (NewOwner
!= NULL
)
1214 ProcessId
= PsGetProcessId(NewOwner
);
1216 /* Increase the new process' object counter */
1217 W32Process
= (PW32PROCESS
)NewOwner
->Win32Process
;
1218 if (W32Process
!= NULL
)
1220 _InterlockedIncrement(&W32Process
->GDIObjects
);
1226 /* remove the process id lock and change it to the new process id */
1227 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
);
1234 GDIDBG_TRACELOOP(ObjectHandle
, PrevThread
, Thread
);
1236 /* WTF?! The object is already locked by a different thread!
1237 Release the lock, wait a bit and try again! DO reset the pid lock
1238 so we make sure we don't access invalid memory in case the object is
1239 being deleted in the meantime (because we don't have aquired a reference
1241 FIXME - we should give up after some time unless we want to wait forever! */
1242 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1250 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1251 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry
->Type
, Entry
->KernelData
);
1255 else if (PrevProcId
== LockedProcessId
)
1257 GDIDBG_TRACELOOP(ObjectHandle
, PrevProcId
, ProcessId
);
1259 /* the object is currently locked, wait some time and try again.
1260 FIXME - we shouldn't loop forever! Give up after some time! */
1265 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1267 /* allow changing ownership of global objects */
1269 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1272 else if ((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1274 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1279 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1287 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1289 PGDI_TABLE_ENTRY FromEntry
;
1291 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1294 GDIDBG_INITLOOPTRACE();
1296 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1298 Thread
= PsGetCurrentThreadWin32Thread();
1300 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1302 FromEntry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, CopyFrom
);
1304 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1305 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1308 /* lock the object, we must not convert stock objects, so don't check!!! */
1309 FromPrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1310 if (FromPrevProcId
== FromProcessId
)
1312 PW32THREAD PrevThread
;
1315 if ((FromEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1317 Object
= FromEntry
->KernelData
;
1319 /* save the pointer to the calling thread so we know it was this thread
1320 that locked the object */
1321 PrevThread
= Object
->Tid
;
1322 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1324 /* now let's change the ownership of the target object */
1326 if (((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1328 PEPROCESS ProcessTo
;
1330 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1332 GDIOBJ_SetOwnership(CopyTo
, ProcessTo
);
1333 ObDereferenceObject(ProcessTo
);
1338 /* mark the object as global */
1339 GDIOBJ_SetOwnership(CopyTo
, NULL
);
1342 (void)_InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1346 GDIDBG_TRACELOOP(CopyFrom
, PrevThread
, Thread
);
1348 /* WTF?! The object is already locked by a different thread!
1349 Release the lock, wait a bit and try again! DO reset the pid lock
1350 so we make sure we don't access invalid memory in case the object is
1351 being deleted in the meantime (because we don't have aquired a reference
1353 FIXME - we should give up after some time unless we want to wait forever! */
1354 (void)_InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1357 goto LockHandleFrom
;
1362 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1366 else if (FromPrevProcId
== FromLockedProcessId
)
1368 GDIDBG_TRACELOOP(CopyFrom
, FromPrevProcId
, FromProcessId
);
1370 /* the object is currently locked, wait some time and try again.
1371 FIXME - we shouldn't loop forever! Give up after some time! */
1374 goto LockHandleFrom
;
1376 else if ((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1378 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1379 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1380 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1381 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1382 goto LockHandleFrom
;
1386 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1394 GDI_MapHandleTable(PSECTION_OBJECT SectionObject
, PEPROCESS Process
)
1396 PVOID MappedView
= NULL
;
1398 LARGE_INTEGER Offset
;
1399 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1401 Offset
.QuadPart
= 0;
1403 ASSERT(SectionObject
!= NULL
);
1404 ASSERT(Process
!= NULL
);
1406 Status
= MmMapViewOfSection(SectionObject
,
1417 if (!NT_SUCCESS(Status
))
1423 /** PUBLIC FUNCTIONS **********************************************************/
1426 Since Brush/Pen and Region objects are sharable,,, we can just use
1427 UserHeapAlloc to allocate the small attribute objects.
1431 // Save Kernel Space Pointer
1432 (PGDIBRUSHOBJ)->pBrushAttr = IntGdiAllocObjAttr(GDIObjType_BRUSH_TYPE);
1434 // Kernel Space to User Space Pointer
1435 (PGDI_TABLE_ENTRY)->UserData = pBrushAttr;
1436 // Gdi will adjust for heap delta.
1440 (PGDI_TABLE_ENTRY)->UserData = NULL; // Zero the user ptr.
1441 UserHeapFree((PGDIBRUSHOBJ)->pBrushAttr); // Free from kernel ptr.
1442 (PGDIBRUSHOBJ)->pBrushAttr = NULL;
1445 Testing with DC_ATTR works but has drawing difficulties.
1446 Base on observation, (Over looking the obvious) we need to supply heap delta
1447 to user space gdi. Now, with testing, looks all normal.
1452 IntGdiAllocObjAttr(GDIOBJTYPE Type
)
1454 PVOID pMemAttr
= NULL
;
1458 case GDIObjType_DC_TYPE
:
1459 pMemAttr
= UserHeapAlloc(sizeof(DC_ATTR
));
1460 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(DC_ATTR
));
1462 case GDIObjType_RGN_TYPE
:
1463 pMemAttr
= UserHeapAlloc(sizeof(RGN_ATTR
));
1464 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(RGN_ATTR
));
1466 case GDIObjType_BRUSH_TYPE
:
1467 pMemAttr
= UserHeapAlloc(sizeof(BRUSH_ATTR
));
1468 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(BRUSH_ATTR
));
1479 IntGdiSetBrushOwner(PGDIBRUSHOBJ pbr
, DWORD OwnerMask
)
1482 PEPROCESS Owner
= NULL
;
1483 PGDI_TABLE_ENTRY pEntry
= NULL
;
1485 if (!pbr
) return FALSE
;
1487 hBR
= pbr
->BaseObject
.hHmgr
;
1489 if (!hBR
|| (GDI_HANDLE_GET_TYPE(hBR
) != GDI_OBJECT_TYPE_BRUSH
))
1493 INT Index
= GDI_HANDLE_GET_INDEX((HGDIOBJ
)hBR
);
1494 pEntry
= &GdiHandleTable
->Entries
[Index
];
1497 if (pbr
->flAttrs
& GDIBRUSH_IS_GLOBAL
)
1499 GDIOBJ_ShareUnlockObjByPtr((POBJ
)pbr
);
1503 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1505 // Set this Brush to inaccessible mode and to an Owner of NONE.
1506 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1508 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, Owner
))
1511 // Deny user access to User Data.
1512 pEntry
->UserData
= NULL
; // This hBR is inaccessible!
1515 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1517 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, PsGetCurrentProcess() ))
1520 // Allow user access to User Data.
1521 pEntry
->UserData
= pbr
->pBrushAttr
;
1529 IntGdiSetDCOwnerEx( HDC hDC
, DWORD OwnerMask
, BOOL NoSetBrush
)
1534 if (!hDC
|| (GDI_HANDLE_GET_TYPE(hDC
) != GDI_OBJECT_TYPE_DC
)) return FALSE
;
1536 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1538 pDC
= DC_LockDc ( hDC
);
1539 MmCopyFromCaller(&pDC
->Dc_Attr
, pDC
->pDc_Attr
, sizeof(DC_ATTR
));
1542 DC_FreeDcAttr( hDC
); // Free the dcattr!
1544 if (!DC_SetOwnership( hDC
, NULL
)) // This hDC is inaccessible!
1548 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1550 pDC
= DC_LockDc ( hDC
);
1551 if ( !pDC
->pDc_Attr
) Ret
= TRUE
; // Must be zero.
1553 if (!Ret
) return Ret
;
1555 if (!DC_SetOwnership( hDC
, PsGetCurrentProcess() )) return Ret
;
1557 DC_AllocateDcAttr( hDC
); // Allocate new dcattr
1559 DCU_SynchDcAttrtoUser( hDC
); // Copy data from dc to dcattr
1562 if ((OwnerMask
!= GDI_OBJ_HMGR_NONE
) && !NoSetBrush
)
1564 pDC
= DC_LockDc ( hDC
);
1565 if (IntGdiSetBrushOwner((PGDIBRUSHOBJ
)pDC
->DcLevel
.pbrFill
, OwnerMask
))
1566 IntGdiSetBrushOwner((PGDIBRUSHOBJ
)pDC
->DcLevel
.pbrLine
, OwnerMask
);
1575 NtGdiCreateClientObj(
1582 /* Mask out everything that would change the type in a wrong manner */
1583 ulType
&= (GDI_HANDLE_TYPE_MASK
& ~GDI_HANDLE_BASETYPE_MASK
);
1585 /* Allocate a new object */
1586 pObject
= GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ
| ulType
);
1592 /* get the handle */
1593 handle
= pObject
->hHmgr
;
1596 GDIOBJ_UnlockObjByPtr(pObject
);
1604 NtGdiDeleteClientObj(
1608 /* We first need to get the real type from the handle */
1609 ULONG type
= GDI_HANDLE_GET_TYPE(h
);
1611 /* Check if it's really a CLIENTOBJ */
1612 if ((type
& GDI_HANDLE_BASETYPE_MASK
) != GDILoObjType_LO_CLIENTOBJ_TYPE
)
1614 /* FIXME: SetLastError? */
1617 return GDIOBJ_FreeObjByHandle(h
, type
);
1622 IntGdiGetObject(IN HANDLE Handle
,
1630 pGdiObject
= GDIOBJ_LockObj(Handle
, GDI_OBJECT_TYPE_DONTCARE
);
1633 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1637 dwObjectType
= GDIOBJ_GetObjectType(Handle
);
1638 switch (dwObjectType
)
1640 case GDI_OBJECT_TYPE_PEN
:
1641 case GDI_OBJECT_TYPE_EXTPEN
:
1642 Result
= PEN_GetObject((PGDIBRUSHOBJ
) pGdiObject
, cbCount
, (PLOGPEN
) lpBuffer
); // IntGdiCreatePenIndirect
1645 case GDI_OBJECT_TYPE_BRUSH
:
1646 Result
= BRUSH_GetObject((PGDIBRUSHOBJ
) pGdiObject
, cbCount
, (LPLOGBRUSH
)lpBuffer
);
1649 case GDI_OBJECT_TYPE_BITMAP
:
1650 Result
= BITMAP_GetObject((BITMAPOBJ
*) pGdiObject
, cbCount
, lpBuffer
);
1652 case GDI_OBJECT_TYPE_FONT
:
1653 Result
= FontGetObject((PTEXTOBJ
) pGdiObject
, cbCount
, lpBuffer
);
1655 // Fix the LOGFONT structure for the stock fonts
1656 if (FIRST_STOCK_HANDLE
<= Handle
&& Handle
<= LAST_STOCK_HANDLE
)
1658 FixStockFontSizeW(Handle
, cbCount
, lpBuffer
);
1663 case GDI_OBJECT_TYPE_PALETTE
:
1664 Result
= PALETTE_GetObject((PPALGDI
) pGdiObject
, cbCount
, lpBuffer
);
1668 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType
);
1672 GDIOBJ_UnlockObjByPtr(pGdiObject
);
1682 NtGdiExtGetObjectW(IN HANDLE hGdiObj
,
1684 OUT LPVOID lpBuffer
)
1691 DIBSECTION dibsection
;
1695 EXTLOGFONTW extlogfontw
;
1696 ENUMLOGFONTEXDVW enumlogfontexdvw
;
1699 // Normalize to the largest supported object size
1700 cbCount
= min((UINT
)cbCount
, sizeof(Object
));
1702 // Now do the actual call
1703 iRetCount
= IntGdiGetObject(hGdiObj
, cbCount
, lpBuffer
? &Object
: NULL
);
1704 cbCopyCount
= min((UINT
)cbCount
, (UINT
)iRetCount
);
1706 // Make sure we have a buffer and a copy size
1707 if ((cbCopyCount
) && (lpBuffer
))
1709 // Enter SEH for buffer transfer
1712 // Probe the buffer and copy it
1713 ProbeForWrite(lpBuffer
, cbCopyCount
, sizeof(WORD
));
1714 RtlCopyMemory(lpBuffer
, &Object
, cbCopyCount
);
1718 // Clear the return value.
1719 // Do *NOT* set last error here!