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 {1, sizeof(PATH
), TAG_PATH
, GDI_CleanupDummy
}, /* 07 PATH */
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)
327 DPRINT1("Too many objects for process!!!\n");
328 GDIDBG_DUMPHANDLETABLE();
332 ASSERT(ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
);
334 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(ObjectType
);
336 newObject
= GDIOBJ_AllocObj(TypeIndex
);
339 DPRINT1("Not enough memory to allocate gdi object!\n");
344 PGDI_TABLE_ENTRY Entry
;
347 CurrentProcessId
= PsGetCurrentProcessId();
348 LockedProcessId
= (HANDLE
)((ULONG_PTR
)CurrentProcessId
| 0x1);
350 // RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
352 /* On Windows the higher 16 bit of the type field don't contain the
353 full type from the handle, but the base type.
354 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
355 TypeInfo
= (ObjectType
& GDI_HANDLE_BASETYPE_MASK
) | (ObjectType
>> GDI_ENTRY_UPPER_SHIFT
);
357 Index
= InterlockedPopFreeEntry();
362 Entry
= &GdiHandleTable
->Entries
[Index
];
365 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, 0);
366 if (PrevProcId
== NULL
)
368 PW32THREAD Thread
= PsGetCurrentThreadWin32Thread();
371 Entry
->KernelData
= newObject
;
373 /* copy the reuse-counter */
374 TypeInfo
|= Entry
->Type
& GDI_ENTRY_REUSE_MASK
;
376 /* we found a free entry, no need to exchange this field atomically
377 since we're holding the lock */
378 Entry
->Type
= TypeInfo
;
380 /* Create a handle */
381 Handle
= (HGDIOBJ
)((Index
& 0xFFFF) | (TypeInfo
<< GDI_ENTRY_UPPER_SHIFT
));
383 /* Initialize BaseObject fields */
384 newObject
->hHmgr
= Handle
;
385 newObject
->ulShareCount
= 0;
386 newObject
->cExclusiveLock
= 1;
387 newObject
->Tid
= Thread
;
389 /* unlock the entry */
390 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, CurrentProcessId
);
392 GDIDBG_CAPTUREALLOCATOR(Index
);
394 if (W32Process
!= NULL
)
396 _InterlockedIncrement(&W32Process
->GDIObjects
);
399 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle
, newObject
);
404 GDIDBG_TRACELOOP(Index
, PrevProcId
, CurrentProcessId
);
405 /* damn, someone is trying to lock the object even though it doesn't
406 even exist anymore, wait a little and try again!
407 FIXME - we shouldn't loop forever! Give up after some time! */
414 GDIOBJ_FreeObj(newObject
, TypeIndex
);
416 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
417 GDIDBG_DUMPHANDLETABLE();
424 GDIOBJ_FreeObj(POBJ pObject
, UCHAR BaseType
)
426 /* Object must not have a handle! */
427 ASSERT(pObject
->hHmgr
== NULL
);
429 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
431 PPAGED_LOOKASIDE_LIST LookasideList
;
433 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
434 ExFreeToPagedLookasideList(LookasideList
, pObject
);
443 * Free memory allocated for the GDI object. For each object type this function calls the
444 * appropriate cleanup routine.
446 * \param hObj - handle of the object to be deleted.
448 * \return Returns TRUE if succesful.
449 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
450 * to the calling process.
453 GDIOBJ_FreeObjByHandle(HGDIOBJ hObj
, DWORD ExpectedType
)
455 PGDI_TABLE_ENTRY Entry
;
456 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
457 ULONG HandleType
, HandleUpper
, TypeIndex
;
460 GDIDBG_INITLOOPTRACE();
462 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj
);
464 if (GDI_HANDLE_IS_STOCKOBJ(hObj
))
466 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj
);
467 GDIDBG_TRACECALLER();
471 ProcessId
= PsGetCurrentProcessId();
472 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
474 Silent
= (ExpectedType
& GDI_OBJECT_TYPE_SILENT
);
475 ExpectedType
&= ~GDI_OBJECT_TYPE_SILENT
;
477 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
478 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
480 /* Check if we have the requested type */
481 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
482 HandleType
!= ExpectedType
) ||
485 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
486 hObj
, HandleType
, ExpectedType
);
487 GDIDBG_TRACECALLER();
491 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
494 /* lock the object, we must not delete global objects, so don't exchange the locking
495 process ID to zero when attempting to lock a global object... */
496 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
497 if (PrevProcId
== ProcessId
)
499 if ( (Entry
->KernelData
!= NULL
) &&
500 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) &&
501 ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == (HandleUpper
& GDI_ENTRY_BASETYPE_MASK
)) )
505 Object
= Entry
->KernelData
;
507 if (Object
->cExclusiveLock
== 0)
510 PW32PROCESS W32Process
= PsGetCurrentProcessWin32Process();
512 /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
513 Entry
->Type
= (Entry
->Type
+ GDI_ENTRY_REUSE_INC
) & ~GDI_ENTRY_BASETYPE_MASK
;
515 /* unlock the handle slot */
516 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
518 /* push this entry to the free list */
519 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable
, Entry
));
521 Object
->hHmgr
= NULL
;
523 if (W32Process
!= NULL
)
525 _InterlockedDecrement(&W32Process
->GDIObjects
);
528 /* call the cleanup routine. */
529 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(HandleType
);
530 Ret
= ObjTypeInfo
[TypeIndex
].CleanupProc(Object
);
532 /* Now it's time to free the memory */
533 GDIOBJ_FreeObj(Object
, TypeIndex
);
535 GDIDBG_CAPTUREDELETER(hObj
);
541 * The object is currently locked, so freeing is forbidden!
543 DPRINT1("Object->cExclusiveLock = %d\n", Object
->cExclusiveLock
);
544 GDIDBG_TRACECALLER();
545 GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj
));
546 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
547 /* do not assert here for it will call again from dxg.sys it being call twice */
553 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
554 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
557 else if (PrevProcId
== LockedProcessId
)
559 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
561 /* the object is currently locked, wait some time and try again.
562 FIXME - we shouldn't loop forever! Give up after some time! */
571 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
573 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj
);
575 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
577 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
581 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);
583 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry
->Type
, Entry
->KernelData
, Entry
->ProcessId
);
584 GDIDBG_TRACECALLER();
585 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
594 IsObjectDead(HGDIOBJ hObject
)
596 INT Index
= GDI_HANDLE_GET_INDEX(hObject
);
597 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
598 // We check to see if the objects are knocking on deaths door.
599 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
603 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject
);
604 return TRUE
; // return true and move on.
611 * \param hObject object handle
612 * \return if the function fails the returned value is FALSE.
616 NtGdiDeleteObject(HGDIOBJ hObject
)
618 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
619 if (!IsObjectDead(hObject
))
621 return NULL
!= hObject
622 ? GDIOBJ_FreeObjByHandle(hObject
, GDI_OBJECT_TYPE_DONTCARE
) : FALSE
;
626 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject
);
627 return TRUE
; // return true and move on.
633 IntDeleteHandlesForProcess(struct _EPROCESS
*Process
, ULONG ObjectType
)
635 PGDI_TABLE_ENTRY Entry
, End
;
636 ULONG Index
= RESERVE_ENTRIES_COUNT
;
638 PW32PROCESS W32Process
;
640 W32Process
= (PW32PROCESS
)Process
->Win32Process
;
643 if (W32Process
->GDIObjects
> 0)
645 ProcId
= Process
->UniqueProcessId
;
647 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
648 we should delete it directly here! */
650 End
= &GdiHandleTable
->Entries
[GDI_HANDLE_COUNT
];
651 for (Entry
= &GdiHandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
655 /* ignore the lock bit */
656 if ( (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
)
658 if ( (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == ObjectType
||
659 ObjectType
== GDI_OBJECT_TYPE_DONTCARE
)
661 HGDIOBJ ObjectHandle
;
663 /* Create the object handle for the entry, the lower(!) 16 bit of the
664 Type field includes the type of the object including the stock
665 object flag - but since stock objects don't have a process id we can
666 simply ignore this fact here. */
667 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
669 if (GDIOBJ_FreeObjByHandle(ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
) &&
670 W32Process
->GDIObjects
== 0)
672 /* there are no more gdi handles for this process, bail */
683 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
684 * \param Process - PID of the process that will be destroyed.
687 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
689 PEPROCESS CurrentProcess
;
691 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
692 CurrentProcess
= PsGetCurrentProcess();
693 if (CurrentProcess
!= Process
)
695 KeAttachProcess(&Process
->Pcb
);
698 /* Delete objects. Begin with types that are not referenced by other types */
699 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_DC_TYPE
);
700 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BRUSH_TYPE
);
701 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BITMAP_TYPE
);
703 /* Finally finish with what's left */
704 IntDeleteHandlesForProcess(Process
, GDI_OBJECT_TYPE_DONTCARE
);
706 if (CurrentProcess
!= Process
)
712 GdiDbgHTIntegrityCheck();
715 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
721 * Return pointer to the object by handle.
723 * \param hObj Object handle
724 * \return Pointer to the object.
726 * \note Process can only get pointer to the objects it created or global objects.
728 * \todo Get rid of the ExpectedType parameter!
730 PGDIOBJ INTERNAL_CALL
731 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
734 PGDI_TABLE_ENTRY Entry
;
735 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
737 ULONG HandleType
, HandleUpper
;
739 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
740 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
741 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
743 /* Check that the handle index is valid. */
744 if (HandleIndex
>= GDI_HANDLE_COUNT
)
747 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
749 /* Check if we have the requested type */
750 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
751 HandleType
!= ExpectedType
) ||
754 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
755 hObj
, HandleType
, ExpectedType
);
756 GDIDBG_TRACECALLER();
757 GDIDBG_TRACEALLOCATOR(hObj
);
758 GDIDBG_TRACEDELETER(hObj
);
762 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
763 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
765 /* Check for invalid owner. */
766 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
768 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj
, ProcessId
, HandleProcessId
);
769 GDIDBG_TRACECALLER();
770 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
775 * Prevent the thread from being terminated during the locking process.
776 * It would result in undesired effects and inconsistency of the global
780 KeEnterCriticalRegion();
783 * Loop until we either successfully lock the handle entry & object or
784 * fail some of the check.
789 /* Lock the handle table entry. */
790 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
791 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
795 if (PrevProcId
== HandleProcessId
)
798 * We're locking an object that belongs to our process or it's a
799 * global object if HandleProcessId is 0 here.
802 if ( (Entry
->KernelData
!= NULL
) &&
803 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
805 PW32THREAD Thread
= PsGetCurrentThreadWin32Thread();
806 Object
= Entry
->KernelData
;
808 if (Object
->cExclusiveLock
== 0)
810 Object
->Tid
= Thread
;
811 Object
->cExclusiveLock
= 1;
812 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj
))
816 if (Object
->Tid
!= Thread
)
818 /* Unlock the handle table entry. */
819 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
824 _InterlockedIncrement((PLONG
)&Object
->cExclusiveLock
);
830 * Debugging code. Report attempts to lock deleted handles and
831 * locking type mismatches.
833 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
836 /* Unlock the handle table entry. */
837 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
844 * The handle is currently locked, wait some time and try again.
852 KeLeaveCriticalRegion();
859 * Return pointer to the object by handle (and allow sharing of the handle
862 * \param hObj Object handle
863 * \return Pointer to the object.
865 * \note Process can only get pointer to the objects it created or global objects.
867 * \todo Get rid of the ExpectedType parameter!
869 PGDIOBJ INTERNAL_CALL
870 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
873 PGDI_TABLE_ENTRY Entry
;
874 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
876 ULONG_PTR HandleType
, HandleUpper
;
878 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
879 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
880 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
882 /* Check that the handle index is valid. */
883 if (HandleIndex
>= GDI_HANDLE_COUNT
)
886 /* Check if we have the requested type */
887 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
888 HandleType
!= ExpectedType
) ||
891 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
892 hObj
, HandleType
, ExpectedType
);
896 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
898 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
899 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
901 /* Check for invalid owner. */
902 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
908 * Prevent the thread from being terminated during the locking process.
909 * It would result in undesired effects and inconsistency of the global
913 KeEnterCriticalRegion();
916 * Loop until we either successfully lock the handle entry & object or
917 * fail some of the check.
922 /* Lock the handle table entry. */
923 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
924 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
928 if (PrevProcId
== HandleProcessId
)
931 * We're locking an object that belongs to our process or it's a
932 * global object if HandleProcessId is 0 here.
935 if ( (Entry
->KernelData
!= NULL
) &&
936 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
938 Object
= (POBJ
)Entry
->KernelData
;
941 if (_InterlockedIncrement((PLONG
)&Object
->ulShareCount
) == 1)
943 memset(GDIHandleLocker
[HandleIndex
], 0x00, GDI_STACK_LEVELS
* sizeof(ULONG
));
944 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS
, (PVOID
*)GDIHandleLocker
[HandleIndex
], NULL
);
947 _InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
953 * Debugging code. Report attempts to lock deleted handles and
954 * locking type mismatches.
956 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
959 /* Unlock the handle table entry. */
960 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
967 * The handle is currently locked, wait some time and try again.
975 KeLeaveCriticalRegion();
982 * Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
983 * as soon as you don't need to have access to it's data.
985 * \param Object Object pointer (as returned by GDIOBJ_LockObj).
988 GDIOBJ_UnlockObjByPtr(POBJ Object
)
990 if (_InterlockedDecrement((PLONG
)&Object
->cExclusiveLock
) < 0)
992 DPRINT1("Trying to unlock non-existant object\n");
997 GDIOBJ_ShareUnlockObjByPtr(POBJ Object
)
999 if (_InterlockedDecrement((PLONG
)&Object
->ulShareCount
) < 0)
1001 DPRINT1("Trying to unlock non-existant object\n");
1006 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
1008 PGDI_TABLE_ENTRY Entry
;
1012 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1014 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1016 ProcessId
= PsGetCurrentProcessId();
1018 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1019 Ret
= Entry
->KernelData
!= NULL
&&
1020 (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0 &&
1021 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1030 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1033 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1034 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1036 PGDI_TABLE_ENTRY Entry
;
1037 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1041 GDIDBG_INITLOOPTRACE();
1046 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj
);
1048 Thread
= PsGetCurrentThreadWin32Thread();
1050 if (!GDI_HANDLE_IS_STOCKOBJ(hObj
))
1052 ProcessId
= PsGetCurrentProcessId();
1053 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1055 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
1058 /* lock the object, we must not convert stock objects, so don't check!!! */
1059 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1060 if (PrevProcId
== ProcessId
)
1062 LONG NewType
, PrevType
, OldType
;
1064 /* we're locking an object that belongs to our process. First calculate
1065 the new object type including the stock object flag and then try to
1067 /* On Windows the higher 16 bit of the type field don't contain the
1068 full type from the handle, but the base type.
1069 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1070 OldType
= ((ULONG
)hObj
& GDI_HANDLE_BASETYPE_MASK
) | ((ULONG
)hObj
>> GDI_ENTRY_UPPER_SHIFT
);
1071 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1072 we copy them as we can't get them from the handle */
1073 OldType
|= Entry
->Type
& GDI_ENTRY_FLAGS_MASK
;
1075 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1076 NewType
= OldType
| GDI_ENTRY_STOCK_MASK
;
1078 /* Try to exchange the type field - but only if the old (previous type) matches! */
1079 PrevType
= _InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1080 if (PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1082 PW32THREAD PrevThread
;
1085 /* We successfully set the stock object flag.
1086 KernelData should never be NULL here!!! */
1087 ASSERT(Entry
->KernelData
);
1089 Object
= Entry
->KernelData
;
1091 PrevThread
= Object
->Tid
;
1092 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1094 /* dereference the process' object counter */
1095 if (PrevProcId
!= GDI_GLOBAL_PROCESS
)
1097 PEPROCESS OldProcess
;
1098 PW32PROCESS W32Process
;
1102 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1103 if (NT_SUCCESS(Status
))
1105 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1106 if (W32Process
!= NULL
)
1108 _InterlockedDecrement(&W32Process
->GDIObjects
);
1110 ObDereferenceObject(OldProcess
);
1114 hObj
= (HGDIOBJ
)((ULONG
)(hObj
) | GDI_HANDLE_STOCK_MASK
);
1116 Object
->hHmgr
= hObj
;
1118 /* remove the process id lock and make it global */
1119 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1121 /* we're done, successfully converted the object */
1126 GDIDBG_TRACELOOP(hObj
, PrevThread
, Thread
);
1128 /* WTF?! The object is already locked by a different thread!
1129 Release the lock, wait a bit and try again!
1130 FIXME - we should give up after some time unless we want to wait forever! */
1131 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1139 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1140 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType
, Entry
->Type
, NewType
, Entry
->KernelData
);
1143 else if (PrevProcId
== LockedProcessId
)
1145 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
1147 /* the object is currently locked, wait some time and try again.
1148 FIXME - we shouldn't loop forever! Give up after some time! */
1155 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1163 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1165 PGDI_TABLE_ENTRY Entry
;
1166 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1170 GDIDBG_INITLOOPTRACE();
1172 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1174 Thread
= PsGetCurrentThreadWin32Thread();
1176 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1178 ProcessId
= PsGetCurrentProcessId();
1179 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1181 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1184 /* lock the object, we must not convert stock objects, so don't check!!! */
1185 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1186 if (PrevProcId
== ProcessId
)
1188 PW32THREAD PrevThread
;
1190 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1192 POBJ Object
= Entry
->KernelData
;
1194 PrevThread
= Object
->Tid
;
1195 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1197 PEPROCESS OldProcess
;
1198 PW32PROCESS W32Process
;
1201 /* dereference the process' object counter */
1203 if ((ULONG_PTR
)PrevProcId
& ~0x1)
1205 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1206 if (NT_SUCCESS(Status
))
1208 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1209 if (W32Process
!= NULL
)
1211 _InterlockedDecrement(&W32Process
->GDIObjects
);
1213 ObDereferenceObject(OldProcess
);
1217 if (NewOwner
!= NULL
)
1219 ProcessId
= PsGetProcessId(NewOwner
);
1221 /* Increase the new process' object counter */
1222 W32Process
= (PW32PROCESS
)NewOwner
->Win32Process
;
1223 if (W32Process
!= NULL
)
1225 _InterlockedIncrement(&W32Process
->GDIObjects
);
1231 /* remove the process id lock and change it to the new process id */
1232 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
);
1239 GDIDBG_TRACELOOP(ObjectHandle
, PrevThread
, Thread
);
1241 /* WTF?! The object is already locked by a different thread!
1242 Release the lock, wait a bit and try again! DO reset the pid lock
1243 so we make sure we don't access invalid memory in case the object is
1244 being deleted in the meantime (because we don't have aquired a reference
1246 FIXME - we should give up after some time unless we want to wait forever! */
1247 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1255 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1256 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry
->Type
, Entry
->KernelData
);
1260 else if (PrevProcId
== LockedProcessId
)
1262 GDIDBG_TRACELOOP(ObjectHandle
, PrevProcId
, ProcessId
);
1264 /* the object is currently locked, wait some time and try again.
1265 FIXME - we shouldn't loop forever! Give up after some time! */
1270 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1272 /* allow changing ownership of global objects */
1274 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1277 else if ((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1279 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1284 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1292 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1294 PGDI_TABLE_ENTRY FromEntry
;
1296 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1299 GDIDBG_INITLOOPTRACE();
1301 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1303 Thread
= PsGetCurrentThreadWin32Thread();
1305 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1307 FromEntry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, CopyFrom
);
1309 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1310 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1313 /* lock the object, we must not convert stock objects, so don't check!!! */
1314 FromPrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1315 if (FromPrevProcId
== FromProcessId
)
1317 PW32THREAD PrevThread
;
1320 if ((FromEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1322 Object
= FromEntry
->KernelData
;
1324 /* save the pointer to the calling thread so we know it was this thread
1325 that locked the object */
1326 PrevThread
= Object
->Tid
;
1327 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1329 /* now let's change the ownership of the target object */
1331 if (((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1333 PEPROCESS ProcessTo
;
1335 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1337 GDIOBJ_SetOwnership(CopyTo
, ProcessTo
);
1338 ObDereferenceObject(ProcessTo
);
1343 /* mark the object as global */
1344 GDIOBJ_SetOwnership(CopyTo
, NULL
);
1347 (void)_InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1351 GDIDBG_TRACELOOP(CopyFrom
, PrevThread
, Thread
);
1353 /* WTF?! The object is already locked by a different thread!
1354 Release the lock, wait a bit and try again! DO reset the pid lock
1355 so we make sure we don't access invalid memory in case the object is
1356 being deleted in the meantime (because we don't have aquired a reference
1358 FIXME - we should give up after some time unless we want to wait forever! */
1359 (void)_InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1362 goto LockHandleFrom
;
1367 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1371 else if (FromPrevProcId
== FromLockedProcessId
)
1373 GDIDBG_TRACELOOP(CopyFrom
, FromPrevProcId
, FromProcessId
);
1375 /* the object is currently locked, wait some time and try again.
1376 FIXME - we shouldn't loop forever! Give up after some time! */
1379 goto LockHandleFrom
;
1381 else if ((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1383 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1384 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1385 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1386 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1387 goto LockHandleFrom
;
1391 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1399 GDI_MapHandleTable(PSECTION_OBJECT SectionObject
, PEPROCESS Process
)
1401 PVOID MappedView
= NULL
;
1403 LARGE_INTEGER Offset
;
1404 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1406 Offset
.QuadPart
= 0;
1408 ASSERT(SectionObject
!= NULL
);
1409 ASSERT(Process
!= NULL
);
1411 Status
= MmMapViewOfSection(SectionObject
,
1422 if (!NT_SUCCESS(Status
))
1428 /** PUBLIC FUNCTIONS **********************************************************/
1431 Since Brush/Pen and Region objects are sharable,,, we can just use
1432 UserHeapAlloc to allocate the small attribute objects.
1436 // Save Kernel Space Pointer
1437 (PGDIBRUSHOBJ)->pBrushAttr = IntGdiAllocObjAttr(GDIObjType_BRUSH_TYPE);
1439 // Kernel Space to User Space Pointer
1440 (PGDI_TABLE_ENTRY)->UserData = pBrushAttr;
1441 // Gdi will adjust for heap delta.
1445 (PGDI_TABLE_ENTRY)->UserData = NULL; // Zero the user ptr.
1446 UserHeapFree((PGDIBRUSHOBJ)->pBrushAttr); // Free from kernel ptr.
1447 (PGDIBRUSHOBJ)->pBrushAttr = NULL;
1450 Testing with DC_ATTR works but has drawing difficulties.
1451 Base on observation, (Over looking the obvious) we need to supply heap delta
1452 to user space gdi. Now, with testing, looks all normal.
1457 IntGdiAllocObjAttr(GDIOBJTYPE Type
)
1459 PVOID pMemAttr
= NULL
;
1463 case GDIObjType_DC_TYPE
:
1464 pMemAttr
= UserHeapAlloc(sizeof(DC_ATTR
));
1465 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(DC_ATTR
));
1467 case GDIObjType_RGN_TYPE
:
1468 pMemAttr
= UserHeapAlloc(sizeof(RGN_ATTR
));
1469 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(RGN_ATTR
));
1471 case GDIObjType_BRUSH_TYPE
:
1472 pMemAttr
= UserHeapAlloc(sizeof(BRUSH_ATTR
));
1473 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(BRUSH_ATTR
));
1484 IntGdiSetBrushOwner(PGDIBRUSHOBJ pbr
, DWORD OwnerMask
)
1487 PEPROCESS Owner
= NULL
;
1488 PGDI_TABLE_ENTRY pEntry
= NULL
;
1490 if (!pbr
) return FALSE
;
1492 hBR
= pbr
->BaseObject
.hHmgr
;
1494 if (!hBR
|| (GDI_HANDLE_GET_TYPE(hBR
) != GDI_OBJECT_TYPE_BRUSH
))
1498 INT Index
= GDI_HANDLE_GET_INDEX((HGDIOBJ
)hBR
);
1499 pEntry
= &GdiHandleTable
->Entries
[Index
];
1502 if (pbr
->flAttrs
& GDIBRUSH_IS_GLOBAL
)
1504 GDIOBJ_ShareUnlockObjByPtr((POBJ
)pbr
);
1508 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1510 // Set this Brush to inaccessible mode and to an Owner of NONE.
1511 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1513 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, Owner
))
1516 // Deny user access to User Data.
1517 pEntry
->UserData
= NULL
; // This hBR is inaccessible!
1520 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1522 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, PsGetCurrentProcess() ))
1525 // Allow user access to User Data.
1526 pEntry
->UserData
= pbr
->pBrushAttr
;
1534 IntGdiSetDCOwnerEx( HDC hDC
, DWORD OwnerMask
, BOOL NoSetBrush
)
1539 if (!hDC
|| (GDI_HANDLE_GET_TYPE(hDC
) != GDI_OBJECT_TYPE_DC
)) return FALSE
;
1541 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1543 pDC
= DC_LockDc ( hDC
);
1544 MmCopyFromCaller(&pDC
->Dc_Attr
, pDC
->pDc_Attr
, sizeof(DC_ATTR
));
1547 DC_FreeDcAttr( hDC
); // Free the dcattr!
1549 if (!DC_SetOwnership( hDC
, NULL
)) // This hDC is inaccessible!
1553 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1555 pDC
= DC_LockDc ( hDC
);
1556 if ( !pDC
->pDc_Attr
) Ret
= TRUE
; // Must be zero.
1558 if (!Ret
) return Ret
;
1560 if (!DC_SetOwnership( hDC
, PsGetCurrentProcess() )) return Ret
;
1562 DC_AllocateDcAttr( hDC
); // Allocate new dcattr
1564 DCU_SynchDcAttrtoUser( hDC
); // Copy data from dc to dcattr
1567 if ((OwnerMask
!= GDI_OBJ_HMGR_NONE
) && !NoSetBrush
)
1569 pDC
= DC_LockDc ( hDC
);
1570 if (IntGdiSetBrushOwner((PGDIBRUSHOBJ
)pDC
->DcLevel
.pbrFill
, OwnerMask
))
1571 IntGdiSetBrushOwner((PGDIBRUSHOBJ
)pDC
->DcLevel
.pbrLine
, OwnerMask
);
1580 NtGdiCreateClientObj(
1587 /* Mask out everything that would change the type in a wrong manner */
1588 ulType
&= (GDI_HANDLE_TYPE_MASK
& ~GDI_HANDLE_BASETYPE_MASK
);
1590 /* Allocate a new object */
1591 pObject
= GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ
| ulType
);
1597 /* get the handle */
1598 handle
= pObject
->hHmgr
;
1601 GDIOBJ_UnlockObjByPtr(pObject
);
1609 NtGdiDeleteClientObj(
1613 /* We first need to get the real type from the handle */
1614 ULONG type
= GDI_HANDLE_GET_TYPE(h
);
1616 /* Check if it's really a CLIENTOBJ */
1617 if ((type
& GDI_HANDLE_BASETYPE_MASK
) != GDILoObjType_LO_CLIENTOBJ_TYPE
)
1619 /* FIXME: SetLastError? */
1622 return GDIOBJ_FreeObjByHandle(h
, type
);
1627 IntGdiGetObject(IN HANDLE Handle
,
1635 pGdiObject
= GDIOBJ_LockObj(Handle
, GDI_OBJECT_TYPE_DONTCARE
);
1638 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1642 dwObjectType
= GDIOBJ_GetObjectType(Handle
);
1643 switch (dwObjectType
)
1645 case GDI_OBJECT_TYPE_PEN
:
1646 case GDI_OBJECT_TYPE_EXTPEN
:
1647 Result
= PEN_GetObject((PGDIBRUSHOBJ
) pGdiObject
, cbCount
, (PLOGPEN
) lpBuffer
); // IntGdiCreatePenIndirect
1650 case GDI_OBJECT_TYPE_BRUSH
:
1651 Result
= BRUSH_GetObject((PGDIBRUSHOBJ
) pGdiObject
, cbCount
, (LPLOGBRUSH
)lpBuffer
);
1654 case GDI_OBJECT_TYPE_BITMAP
:
1655 Result
= BITMAP_GetObject((BITMAPOBJ
*) pGdiObject
, cbCount
, lpBuffer
);
1657 case GDI_OBJECT_TYPE_FONT
:
1658 Result
= FontGetObject((PTEXTOBJ
) pGdiObject
, cbCount
, lpBuffer
);
1660 // Fix the LOGFONT structure for the stock fonts
1661 if (FIRST_STOCK_HANDLE
<= Handle
&& Handle
<= LAST_STOCK_HANDLE
)
1663 FixStockFontSizeW(Handle
, cbCount
, lpBuffer
);
1668 case GDI_OBJECT_TYPE_PALETTE
:
1669 Result
= PALETTE_GetObject((PPALGDI
) pGdiObject
, cbCount
, lpBuffer
);
1673 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType
);
1677 GDIOBJ_UnlockObjByPtr(pGdiObject
);
1687 NtGdiExtGetObjectW(IN HANDLE hGdiObj
,
1689 OUT LPVOID lpBuffer
)
1696 DIBSECTION dibsection
;
1700 EXTLOGFONTW extlogfontw
;
1701 ENUMLOGFONTEXDVW enumlogfontexdvw
;
1704 // Normalize to the largest supported object size
1705 cbCount
= min((UINT
)cbCount
, sizeof(Object
));
1707 // Now do the actual call
1708 iRetCount
= IntGdiGetObject(hGdiObj
, cbCount
, lpBuffer
? &Object
: NULL
);
1709 cbCopyCount
= min((UINT
)cbCount
, (UINT
)iRetCount
);
1711 // Make sure we have a buffer and a copy size
1712 if ((cbCopyCount
) && (lpBuffer
))
1714 // Enter SEH for buffer transfer
1717 // Probe the buffer and copy it
1718 ProbeForWrite(lpBuffer
, cbCopyCount
, sizeof(WORD
));
1719 RtlCopyMemory(lpBuffer
, &Object
, cbCopyCount
);
1723 // Clear the return value.
1724 // Do *NOT* set last error here!