2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/objects/gdiobj.c
5 * PURPOSE: General GDI object manipulation routines
9 /** INCLUDES ******************************************************************/
15 #define GDI_ENTRY_TO_INDEX(ht, e) \
16 (((ULONG_PTR)(e) - (ULONG_PTR)&((ht)->Entries[0])) / sizeof(GDI_TABLE_ENTRY))
17 #define GDI_HANDLE_GET_ENTRY(HandleTable, h) \
18 (&(HandleTable)->Entries[GDI_HANDLE_GET_INDEX((h))])
20 /* apparently the first 10 entries are never used in windows as they are empty */
21 #define RESERVE_ENTRIES_COUNT 10
23 #define BASE_OBJTYPE_COUNT 32
25 #define DelayExecution() \
26 DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
27 KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
29 /* static */ /* FIXME: -fno-unit-at-a-time breaks this */
30 BOOL INTERNAL_CALL
GDI_CleanupDummy(PVOID ObjectBody
);
32 /** GLOBALS *******************************************************************/
39 GDICLEANUPPROC CleanupProc
;
40 } OBJ_TYPE_INFO
, *POBJ_TYPE_INFO
;
43 OBJ_TYPE_INFO ObjTypeInfo
[BASE_OBJTYPE_COUNT
] =
45 {0, 0, 0, NULL
}, /* 00 reserved entry */
46 {1, sizeof(DC
), TAG_DC
, DC_Cleanup
}, /* 01 DC */
47 {1, 0, 0, NULL
}, /* 02 UNUSED1 */
48 {1, 0, 0, NULL
}, /* 03 UNUSED2 */
49 {1, sizeof(ROSRGNDATA
), TAG_REGION
, REGION_Cleanup
}, /* 04 RGN */
50 {1, sizeof(SURFACE
), TAG_SURFACE
, SURFACE_Cleanup
}, /* 05 SURFACE */
51 {1, sizeof(CLIENTOBJ
), TAG_CLIENTOBJ
, GDI_CleanupDummy
}, /* 06 CLIENTOBJ: METADC,... */
52 {1, sizeof(PATH
), TAG_PATH
, GDI_CleanupDummy
}, /* 07 PATH */
53 {1, sizeof(PALGDI
), TAG_PALETTE
, PALETTE_Cleanup
}, /* 08 PAL */
54 {1, sizeof(COLORSPACE
), TAG_ICMLCS
, GDI_CleanupDummy
}, /* 09 ICMLCS, */
55 {1, sizeof(TEXTOBJ
), TAG_LFONT
, GDI_CleanupDummy
}, /* 0a LFONT */
56 {0, 0, TAG_RFONT
, NULL
}, /* 0b RFONT, unused */
57 {0, 0, TAG_PFE
, NULL
}, /* 0c PFE, unused */
58 {0, 0, TAG_PFT
, NULL
}, /* 0d PFT, unused */
59 {0, sizeof(GDICLRXFORM
), TAG_ICMCXF
, GDI_CleanupDummy
}, /* 0e ICMCXF, */
60 {0, 0, TAG_SPRITE
, NULL
}, /* 0f SPRITE, unused */
61 {1, sizeof(GDIBRUSHOBJ
), TAG_BRUSH
, BRUSH_Cleanup
}, /* 10 BRUSH, PEN, EXTPEN */
62 {0, 0, TAG_UMPD
, NULL
}, /* 11 UMPD, unused */
63 {0, 0, 0, NULL
}, /* 12 UNUSED4 */
64 {0, 0, TAG_SPACE
, NULL
}, /* 13 SPACE, unused */
65 {0, 0, 0, NULL
}, /* 14 UNUSED5 */
66 {0, 0, TAG_META
, NULL
}, /* 15 META, unused */
67 {0, 0, TAG_EFSTATE
, NULL
}, /* 16 EFSTATE, unused */
68 {0, 0, TAG_BMFD
, NULL
}, /* 17 BMFD, unused */
69 {0, 0, TAG_VTFD
, NULL
}, /* 18 VTFD, unused */
70 {0, 0, TAG_TTFD
, NULL
}, /* 19 TTFD, unused */
71 {0, 0, TAG_RC
, NULL
}, /* 1a RC, unused */
72 {0, 0, TAG_TEMP
, NULL
}, /* 1b TEMP, unused */
73 {0, sizeof(EDRIVEROBJ
), TAG_DRVOBJ
, DRIVEROBJ_Cleanup
},/* 1c DRVOBJ */
74 {0, 0, TAG_DCIOBJ
, NULL
}, /* 1d DCIOBJ, unused */
75 {0, 0, TAG_SPOOL
, NULL
}, /* 1e SPOOL, unused */
76 {0, 0, 0, NULL
}, /* 1f reserved entry */
79 static LARGE_INTEGER ShortDelay
;
81 /** DEBUGGING *****************************************************************/
85 /** INTERNAL FUNCTIONS ********************************************************/
88 * Dummy GDI Cleanup Callback
90 /* static */ /* FIXME: -fno-unit-at-a-time breaks this */
92 GDI_CleanupDummy(PVOID ObjectBody
)
98 * Allocate GDI object table.
99 * \param Size - number of entries in the object table.
101 PGDI_HANDLE_TABLE INTERNAL_CALL
102 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT
*SectionObject
)
104 PGDI_HANDLE_TABLE HandleTable
= NULL
;
105 LARGE_INTEGER htSize
;
110 ASSERT(SectionObject
!= NULL
);
112 htSize
.QuadPart
= sizeof(GDI_HANDLE_TABLE
);
114 Status
= MmCreateSection((PVOID
*)SectionObject
,
122 if (!NT_SUCCESS(Status
))
125 /* FIXME - use MmMapViewInSessionSpace once available! */
126 Status
= MmMapViewInSystemSpace(*SectionObject
,
127 (PVOID
*)&HandleTable
,
129 if (!NT_SUCCESS(Status
))
131 ObDereferenceObject(*SectionObject
);
132 *SectionObject
= NULL
;
136 RtlZeroMemory(HandleTable
, sizeof(GDI_HANDLE_TABLE
));
138 HandleTable
->LookasideLists
= ExAllocatePoolWithTag(NonPagedPool
,
139 BASE_OBJTYPE_COUNT
* sizeof(PAGED_LOOKASIDE_LIST
),
141 if (HandleTable
->LookasideLists
== NULL
)
143 MmUnmapViewInSystemSpace(HandleTable
);
144 ObDereferenceObject(*SectionObject
);
145 *SectionObject
= NULL
;
149 for (ObjType
= 0; ObjType
< BASE_OBJTYPE_COUNT
; ObjType
++)
151 if (ObjTypeInfo
[ObjType
].bUseLookaside
)
153 ExInitializePagedLookasideList(HandleTable
->LookasideLists
+ ObjType
,
157 ObjTypeInfo
[ObjType
].ulBodySize
,
158 ObjTypeInfo
[ObjType
].Tag
,
163 ShortDelay
.QuadPart
= -5000LL; /* FIXME - 0.5 ms? */
165 HandleTable
->FirstFree
= 0;
166 HandleTable
->FirstUnused
= RESERVE_ENTRIES_COUNT
;
172 LockErrorDebugOutput(HGDIOBJ hObj
, PGDI_TABLE_ENTRY Entry
, LPSTR Function
)
174 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
176 DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function
, hObj
);
177 GDIDBG_TRACEDELETER(hObj
);
179 else if (GDI_HANDLE_GET_REUSECNT(hObj
) != GDI_ENTRY_GET_REUSECNT(Entry
->Type
))
181 DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
182 Function
, hObj
, GDI_HANDLE_GET_REUSECNT(hObj
), GDI_ENTRY_GET_REUSECNT(Entry
->Type
));
184 else if (GDI_HANDLE_GET_TYPE(hObj
) != ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
))
186 DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
187 Function
, hObj
, GDI_HANDLE_GET_TYPE(hObj
), (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
);
191 DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
192 Function
, hObj
, Entry
->Type
);
194 GDIDBG_TRACECALLER();
199 InterlockedPopFreeEntry()
201 ULONG idxFirst
, idxNext
, idxPrev
;
202 PGDI_TABLE_ENTRY pEntry
;
205 DPRINT("Enter InterLockedPopFreeEntry\n");
209 idxFirst
= GdiHandleTable
->FirstFree
;
213 /* Increment FirstUnused and get the new index */
214 idxFirst
= InterlockedIncrement((LONG
*)&GdiHandleTable
->FirstUnused
) - 1;
216 /* Check if we have entries left */
217 if (idxFirst
>= GDI_HANDLE_COUNT
)
219 DPRINT1("No more gdi handles left!\n");
223 /* Return the old index */
227 /* Get a pointer to the first free entry */
228 pEntry
= GdiHandleTable
->Entries
+ idxFirst
;
230 /* Try to lock the entry */
231 PrevProcId
= InterlockedCompareExchange((LONG
*)&pEntry
->ProcessId
, 1, 0);
234 /* The entry was locked or not free, wait and start over */
239 /* Sanity check: is entry really free? */
240 ASSERT(((ULONG_PTR
)pEntry
->KernelData
& ~GDI_HANDLE_INDEX_MASK
) == 0);
242 /* Try to exchange the FirstFree value */
243 idxNext
= (ULONG_PTR
)pEntry
->KernelData
;
244 idxPrev
= InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
,
248 /* Unlock the free entry */
249 (void)InterlockedExchange((LONG
*)&pEntry
->ProcessId
, 0);
251 /* If we succeeded, break out of the loop */
252 if (idxPrev
== idxFirst
)
261 /* Pushes an entry of the handle table to the free list,
262 The entry must be unlocked and the base type field must be 0 */
265 InterlockedPushFreeEntry(ULONG idxToFree
)
267 ULONG idxFirstFree
, idxPrev
;
268 PGDI_TABLE_ENTRY pFreeEntry
;
270 DPRINT("Enter InterlockedPushFreeEntry\n");
272 pFreeEntry
= GdiHandleTable
->Entries
+ idxToFree
;
273 ASSERT((pFreeEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0);
274 ASSERT(pFreeEntry
->ProcessId
== 0);
275 pFreeEntry
->UserData
= NULL
;
279 idxFirstFree
= GdiHandleTable
->FirstFree
;
280 pFreeEntry
->KernelData
= (PVOID
)(ULONG_PTR
)idxFirstFree
;
282 idxPrev
= InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
,
286 while (idxPrev
!= idxFirstFree
);
292 GDIOBJ_ValidateHandle(HGDIOBJ hObj
, ULONG ObjectType
)
294 PGDI_TABLE_ENTRY Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
295 if ((((ULONG_PTR
)hObj
& GDI_HANDLE_TYPE_MASK
) == ObjectType
) &&
296 (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == GDI_HANDLE_GET_UPPER(hObj
))
298 HANDLE pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
299 if (pid
== NULL
|| pid
== PsGetCurrentProcessId())
308 GDIOBJ_AllocObj(UCHAR BaseType
)
312 ASSERT((BaseType
& ~GDIObjTypeTotal
) == 0);
313 // BaseType &= GDI_HANDLE_BASETYPE_MASK;
315 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
317 PPAGED_LOOKASIDE_LIST LookasideList
;
319 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
320 pObject
= ExAllocateFromPagedLookasideList(LookasideList
);
324 pObject
= ExAllocatePoolWithTag(PagedPool
,
325 ObjTypeInfo
[BaseType
].ulBodySize
,
326 ObjTypeInfo
[BaseType
].Tag
);
331 RtlZeroMemory(pObject
, ObjTypeInfo
[BaseType
].ulBodySize
);
339 * Allocate memory for GDI object and return handle to it.
341 * \param ObjectType - type of object \ref GDI object types
343 * \return Pointer to the allocated object, which is locked.
346 GDIOBJ_AllocObjWithHandle(ULONG ObjectType
)
348 PW32PROCESS W32Process
;
349 POBJ newObject
= NULL
;
350 HANDLE CurrentProcessId
, LockedProcessId
;
353 GDIDBG_INITLOOPTRACE();
355 W32Process
= PsGetCurrentProcessWin32Process();
356 /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
357 to take too many GDI objects, itself. */
358 if (W32Process
&& W32Process
->GDIObjects
>= 0x2710)
360 DPRINT1("Too many objects for process!!!\n");
361 GDIDBG_DUMPHANDLETABLE();
365 ASSERT(ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
);
367 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(ObjectType
);
369 newObject
= GDIOBJ_AllocObj(TypeIndex
);
372 DPRINT1("Not enough memory to allocate gdi object!\n");
377 PGDI_TABLE_ENTRY Entry
;
380 CurrentProcessId
= PsGetCurrentProcessId();
381 LockedProcessId
= (HANDLE
)((ULONG_PTR
)CurrentProcessId
| 0x1);
383 // RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
385 /* On Windows the higher 16 bit of the type field don't contain the
386 full type from the handle, but the base type.
387 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
388 TypeInfo
= (ObjectType
& GDI_HANDLE_BASETYPE_MASK
) | (ObjectType
>> GDI_ENTRY_UPPER_SHIFT
);
390 Index
= InterlockedPopFreeEntry();
395 Entry
= &GdiHandleTable
->Entries
[Index
];
398 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, 0);
399 if (PrevProcId
== NULL
)
401 PW32THREAD Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
404 Entry
->KernelData
= newObject
;
406 /* copy the reuse-counter */
407 TypeInfo
|= Entry
->Type
& GDI_ENTRY_REUSE_MASK
;
409 /* we found a free entry, no need to exchange this field atomically
410 since we're holding the lock */
411 Entry
->Type
= TypeInfo
;
413 /* Create a handle */
414 Handle
= (HGDIOBJ
)((Index
& 0xFFFF) | (TypeInfo
<< GDI_ENTRY_UPPER_SHIFT
));
416 /* Initialize BaseObject fields */
417 newObject
->hHmgr
= Handle
;
418 newObject
->ulShareCount
= 0;
419 newObject
->cExclusiveLock
= 1;
420 newObject
->Tid
= Thread
;
422 /* unlock the entry */
423 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, CurrentProcessId
);
425 GDIDBG_CAPTUREALLOCATOR(Index
);
427 if (W32Process
!= NULL
)
429 InterlockedIncrement(&W32Process
->GDIObjects
);
432 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle
, newObject
);
437 GDIDBG_TRACELOOP(Index
, PrevProcId
, CurrentProcessId
);
438 /* damn, someone is trying to lock the object even though it doesn't
439 even exist anymore, wait a little and try again!
440 FIXME - we shouldn't loop forever! Give up after some time! */
447 GDIOBJ_FreeObj(newObject
, TypeIndex
);
449 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
450 GDIDBG_DUMPHANDLETABLE();
457 GDIOBJ_FreeObj(POBJ pObject
, UCHAR BaseType
)
459 /* Object must not have a handle! */
460 ASSERT(pObject
->hHmgr
== NULL
);
462 if (ObjTypeInfo
[BaseType
].bUseLookaside
)
464 PPAGED_LOOKASIDE_LIST LookasideList
;
466 LookasideList
= GdiHandleTable
->LookasideLists
+ BaseType
;
467 ExFreeToPagedLookasideList(LookasideList
, pObject
);
476 * Free memory allocated for the GDI object. For each object type this function calls the
477 * appropriate cleanup routine.
479 * \param hObj - handle of the object to be deleted.
481 * \return Returns TRUE if succesful.
482 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
483 * to the calling process.
486 GDIOBJ_FreeObjByHandle(HGDIOBJ hObj
, DWORD ExpectedType
)
488 PGDI_TABLE_ENTRY Entry
;
489 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
490 ULONG HandleType
, HandleUpper
, TypeIndex
;
493 GDIDBG_INITLOOPTRACE();
495 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj
);
497 if (GDI_HANDLE_IS_STOCKOBJ(hObj
))
499 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj
);
500 GDIDBG_TRACECALLER();
504 ProcessId
= PsGetCurrentProcessId();
505 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
507 Silent
= (ExpectedType
& GDI_OBJECT_TYPE_SILENT
);
508 ExpectedType
&= ~GDI_OBJECT_TYPE_SILENT
;
510 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
511 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
513 /* Check if we have the requested type */
514 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
515 HandleType
!= ExpectedType
) ||
518 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
519 hObj
, HandleType
, ExpectedType
);
520 GDIDBG_TRACECALLER();
524 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
527 /* lock the object, we must not delete global objects, so don't exchange the locking
528 process ID to zero when attempting to lock a global object... */
529 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
530 if (PrevProcId
== ProcessId
)
532 if ( (Entry
->KernelData
!= NULL
) &&
533 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) &&
534 ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == (HandleUpper
& GDI_ENTRY_BASETYPE_MASK
)) )
538 Object
= Entry
->KernelData
;
540 if (Object
->cExclusiveLock
== 0 ||
541 Object
->Tid
== (PW32THREAD
)PsGetCurrentThreadWin32Thread())
544 PW32PROCESS W32Process
= PsGetCurrentProcessWin32Process();
546 /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
547 Entry
->Type
= (Entry
->Type
+ GDI_ENTRY_REUSE_INC
) & ~GDI_ENTRY_BASETYPE_MASK
;
549 /* unlock the handle slot */
550 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
552 /* push this entry to the free list */
553 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable
, Entry
));
555 Object
->hHmgr
= NULL
;
557 if (W32Process
!= NULL
)
559 InterlockedDecrement(&W32Process
->GDIObjects
);
562 /* call the cleanup routine. */
563 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(HandleType
);
564 Ret
= ObjTypeInfo
[TypeIndex
].CleanupProc(Object
);
566 /* Now it's time to free the memory */
567 GDIOBJ_FreeObj(Object
, TypeIndex
);
569 GDIDBG_CAPTUREDELETER(hObj
);
575 * The object is currently locked by another thread, so freeing is forbidden!
577 DPRINT1("Object->cExclusiveLock = %d\n", Object
->cExclusiveLock
);
578 GDIDBG_TRACECALLER();
579 GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj
));
580 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
581 /* do not assert here for it will call again from dxg.sys it being call twice */
589 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
590 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
593 else if (PrevProcId
== LockedProcessId
)
595 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
597 /* the object is currently locked, wait some time and try again.
598 FIXME - we shouldn't loop forever! Give up after some time! */
607 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
609 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj
);
611 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
613 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
617 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);
619 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry
->Type
, Entry
->KernelData
, Entry
->ProcessId
);
620 GDIDBG_TRACECALLER();
621 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
630 IsObjectDead(HGDIOBJ hObject
)
632 INT Index
= GDI_HANDLE_GET_INDEX(hObject
);
633 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
634 // We check to see if the objects are knocking on deaths door.
635 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
639 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject
);
640 return TRUE
; // return true and move on.
647 * \param hObject object handle
648 * \return if the function fails the returned value is FALSE.
652 NtGdiDeleteObject(HGDIOBJ hObject
)
654 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
655 if (!IsObjectDead(hObject
))
657 return NULL
!= hObject
658 ? GDIOBJ_FreeObjByHandle(hObject
, GDI_OBJECT_TYPE_DONTCARE
) : FALSE
;
662 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject
);
663 return TRUE
; // return true and move on.
669 IntDeleteHandlesForProcess(struct _EPROCESS
*Process
, ULONG ObjectType
)
671 PGDI_TABLE_ENTRY Entry
, End
;
672 ULONG Index
= RESERVE_ENTRIES_COUNT
;
674 PW32PROCESS W32Process
;
676 W32Process
= (PW32PROCESS
)Process
->Win32Process
;
679 if (W32Process
->GDIObjects
> 0)
681 ProcId
= Process
->UniqueProcessId
;
683 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
684 we should delete it directly here! */
686 End
= &GdiHandleTable
->Entries
[GDI_HANDLE_COUNT
];
687 for (Entry
= &GdiHandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
691 /* ignore the lock bit */
692 if ( (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
)
694 if ( (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == ObjectType
||
695 ObjectType
== GDI_OBJECT_TYPE_DONTCARE
)
697 HGDIOBJ ObjectHandle
;
699 /* Create the object handle for the entry, the lower(!) 16 bit of the
700 Type field includes the type of the object including the stock
701 object flag - but since stock objects don't have a process id we can
702 simply ignore this fact here. */
703 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
705 if (GDIOBJ_FreeObjByHandle(ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
) &&
706 W32Process
->GDIObjects
== 0)
708 /* there are no more gdi handles for this process, bail */
719 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
720 * \param Process - PID of the process that will be destroyed.
723 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
725 PEPROCESS CurrentProcess
;
727 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
728 CurrentProcess
= PsGetCurrentProcess();
729 if (CurrentProcess
!= Process
)
731 KeAttachProcess(&Process
->Pcb
);
734 /* Delete objects. Begin with types that are not referenced by other types */
735 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_DC_TYPE
);
736 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BRUSH_TYPE
);
737 IntDeleteHandlesForProcess(Process
, GDILoObjType_LO_BITMAP_TYPE
);
739 /* Finally finish with what's left */
740 IntDeleteHandlesForProcess(Process
, GDI_OBJECT_TYPE_DONTCARE
);
742 if (CurrentProcess
!= Process
)
748 GdiDbgHTIntegrityCheck();
751 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
757 * Return pointer to the object by handle.
759 * \param hObj Object handle
760 * \return Pointer to the object.
762 * \note Process can only get pointer to the objects it created or global objects.
764 * \todo Get rid of the ExpectedType parameter!
766 PGDIOBJ INTERNAL_CALL
767 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
770 PGDI_TABLE_ENTRY Entry
;
771 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
773 ULONG HandleType
, HandleUpper
;
775 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
776 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
777 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
779 /* Check that the handle index is valid. */
780 if (HandleIndex
>= GDI_HANDLE_COUNT
)
783 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
785 /* Check if we have the requested type */
786 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
787 HandleType
!= ExpectedType
) ||
790 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
791 hObj
, HandleType
, ExpectedType
);
792 GDIDBG_TRACECALLER();
793 GDIDBG_TRACEALLOCATOR(hObj
);
794 GDIDBG_TRACEDELETER(hObj
);
798 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
799 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
801 /* Check for invalid owner. */
802 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
804 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj
, ProcessId
, HandleProcessId
);
805 GDIDBG_TRACECALLER();
806 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
811 * Prevent the thread from being terminated during the locking process.
812 * It would result in undesired effects and inconsistency of the global
816 KeEnterCriticalRegion();
819 * Loop until we either successfully lock the handle entry & object or
820 * fail some of the check.
825 /* Lock the handle table entry. */
826 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
827 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
831 if (PrevProcId
== HandleProcessId
)
834 * We're locking an object that belongs to our process or it's a
835 * global object if HandleProcessId is 0 here.
838 if ( (Entry
->KernelData
!= NULL
) &&
839 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
841 PW32THREAD Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
842 Object
= Entry
->KernelData
;
844 if (Object
->cExclusiveLock
== 0)
846 Object
->Tid
= Thread
;
847 Object
->cExclusiveLock
= 1;
848 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj
))
852 if (Object
->Tid
!= Thread
)
854 /* Unlock the handle table entry. */
855 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
860 InterlockedIncrement((PLONG
)&Object
->cExclusiveLock
);
866 * Debugging code. Report attempts to lock deleted handles and
867 * locking type mismatches.
869 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
872 /* Unlock the handle table entry. */
873 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
880 * The handle is currently locked, wait some time and try again.
888 KeLeaveCriticalRegion();
895 * Return pointer to the object by handle (and allow sharing of the handle
898 * \param hObj Object handle
899 * \return Pointer to the object.
901 * \note Process can only get pointer to the objects it created or global objects.
903 * \todo Get rid of the ExpectedType parameter!
905 PGDIOBJ INTERNAL_CALL
906 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
909 PGDI_TABLE_ENTRY Entry
;
910 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
912 ULONG_PTR HandleType
, HandleUpper
;
914 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
915 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
916 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
918 /* Check that the handle index is valid. */
919 if (HandleIndex
>= GDI_HANDLE_COUNT
)
922 /* Check if we have the requested type */
923 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
924 HandleType
!= ExpectedType
) ||
927 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
928 hObj
, HandleType
, ExpectedType
);
932 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
934 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
935 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
937 /* Check for invalid owner. */
938 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
944 * Prevent the thread from being terminated during the locking process.
945 * It would result in undesired effects and inconsistency of the global
949 KeEnterCriticalRegion();
952 * Loop until we either successfully lock the handle entry & object or
953 * fail some of the check.
958 /* Lock the handle table entry. */
959 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
960 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
964 if (PrevProcId
== HandleProcessId
)
967 * We're locking an object that belongs to our process or it's a
968 * global object if HandleProcessId is 0 here.
971 if ( (Entry
->KernelData
!= NULL
) &&
972 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
974 Object
= (POBJ
)Entry
->KernelData
;
977 if (InterlockedIncrement((PLONG
)&Object
->ulShareCount
) == 1)
979 memset(GDIHandleLocker
[HandleIndex
], 0x00, GDI_STACK_LEVELS
* sizeof(ULONG
));
980 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS
, (PVOID
*)GDIHandleLocker
[HandleIndex
], NULL
);
983 InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
989 * Debugging code. Report attempts to lock deleted handles and
990 * locking type mismatches.
992 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
995 /* Unlock the handle table entry. */
996 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1003 * The handle is currently locked, wait some time and try again.
1011 KeLeaveCriticalRegion();
1018 GDIOBJ_ShareUnlockObjByPtr(POBJ Object
)
1020 if (InterlockedDecrement((PLONG
)&Object
->ulShareCount
) < 0)
1022 DPRINT1("Trying to unlock non-existant object\n");
1027 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
1029 PGDI_TABLE_ENTRY Entry
;
1033 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1035 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1037 ProcessId
= PsGetCurrentProcessId();
1039 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1040 Ret
= Entry
->KernelData
!= NULL
&&
1041 (Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0 &&
1042 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1051 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1054 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1055 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1057 PGDI_TABLE_ENTRY Entry
;
1058 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1062 GDIDBG_INITLOOPTRACE();
1067 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj
);
1069 Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
1071 if (!GDI_HANDLE_IS_STOCKOBJ(hObj
))
1073 ProcessId
= PsGetCurrentProcessId();
1074 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1076 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
1079 /* lock the object, we must not convert stock objects, so don't check!!! */
1080 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1081 if (PrevProcId
== ProcessId
)
1083 LONG NewType
, PrevType
, OldType
;
1085 /* we're locking an object that belongs to our process. First calculate
1086 the new object type including the stock object flag and then try to
1088 /* On Windows the higher 16 bit of the type field don't contain the
1089 full type from the handle, but the base type.
1090 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1091 OldType
= ((ULONG
)hObj
& GDI_HANDLE_BASETYPE_MASK
) | ((ULONG
)hObj
>> GDI_ENTRY_UPPER_SHIFT
);
1092 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1093 we copy them as we can't get them from the handle */
1094 OldType
|= Entry
->Type
& GDI_ENTRY_FLAGS_MASK
;
1096 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1097 NewType
= OldType
| GDI_ENTRY_STOCK_MASK
;
1099 /* Try to exchange the type field - but only if the old (previous type) matches! */
1100 PrevType
= InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1101 if (PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1103 PW32THREAD PrevThread
;
1106 /* We successfully set the stock object flag.
1107 KernelData should never be NULL here!!! */
1108 ASSERT(Entry
->KernelData
);
1110 Object
= Entry
->KernelData
;
1112 PrevThread
= Object
->Tid
;
1113 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1115 /* dereference the process' object counter */
1116 if (PrevProcId
!= GDI_GLOBAL_PROCESS
)
1118 PEPROCESS OldProcess
;
1119 PW32PROCESS W32Process
;
1123 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1124 if (NT_SUCCESS(Status
))
1126 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1127 if (W32Process
!= NULL
)
1129 InterlockedDecrement(&W32Process
->GDIObjects
);
1131 ObDereferenceObject(OldProcess
);
1135 hObj
= (HGDIOBJ
)((ULONG
)(hObj
) | GDI_HANDLE_STOCK_MASK
);
1137 Object
->hHmgr
= hObj
;
1139 /* remove the process id lock and make it global */
1140 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1142 /* we're done, successfully converted the object */
1147 GDIDBG_TRACELOOP(hObj
, PrevThread
, Thread
);
1149 /* WTF?! The object is already locked by a different thread!
1150 Release the lock, wait a bit and try again!
1151 FIXME - we should give up after some time unless we want to wait forever! */
1152 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1160 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1161 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType
, Entry
->Type
, NewType
, Entry
->KernelData
);
1164 else if (PrevProcId
== LockedProcessId
)
1166 GDIDBG_TRACELOOP(hObj
, PrevProcId
, ProcessId
);
1168 /* the object is currently locked, wait some time and try again.
1169 FIXME - we shouldn't loop forever! Give up after some time! */
1176 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1184 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1186 PGDI_TABLE_ENTRY Entry
;
1187 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1191 GDIDBG_INITLOOPTRACE();
1193 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1195 Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
1197 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1199 ProcessId
= PsGetCurrentProcessId();
1200 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1202 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1205 /* lock the object, we must not convert stock objects, so don't check!!! */
1206 PrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1207 if (PrevProcId
== ProcessId
)
1209 PW32THREAD PrevThread
;
1211 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1213 POBJ Object
= Entry
->KernelData
;
1215 PrevThread
= Object
->Tid
;
1216 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1218 PEPROCESS OldProcess
;
1219 PW32PROCESS W32Process
;
1222 /* dereference the process' object counter */
1224 if ((ULONG_PTR
)PrevProcId
& ~0x1)
1226 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1227 if (NT_SUCCESS(Status
))
1229 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1230 if (W32Process
!= NULL
)
1232 InterlockedDecrement(&W32Process
->GDIObjects
);
1234 ObDereferenceObject(OldProcess
);
1238 if (NewOwner
!= NULL
)
1240 ProcessId
= PsGetProcessId(NewOwner
);
1242 /* Increase the new process' object counter */
1243 W32Process
= (PW32PROCESS
)NewOwner
->Win32Process
;
1244 if (W32Process
!= NULL
)
1246 InterlockedIncrement(&W32Process
->GDIObjects
);
1252 /* remove the process id lock and change it to the new process id */
1253 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
);
1260 GDIDBG_TRACELOOP(ObjectHandle
, PrevThread
, Thread
);
1262 /* WTF?! The object is already locked by a different thread!
1263 Release the lock, wait a bit and try again! DO reset the pid lock
1264 so we make sure we don't access invalid memory in case the object is
1265 being deleted in the meantime (because we don't have aquired a reference
1267 FIXME - we should give up after some time unless we want to wait forever! */
1268 (void)InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1276 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1277 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry
->Type
, Entry
->KernelData
);
1281 else if (PrevProcId
== LockedProcessId
)
1283 GDIDBG_TRACELOOP(ObjectHandle
, PrevProcId
, ProcessId
);
1285 /* the object is currently locked, wait some time and try again.
1286 FIXME - we shouldn't loop forever! Give up after some time! */
1291 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1293 /* allow changing ownership of global objects */
1295 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1298 else if ((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1300 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1305 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1313 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1315 PGDI_TABLE_ENTRY FromEntry
;
1317 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1320 GDIDBG_INITLOOPTRACE();
1322 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1324 Thread
= (PW32THREAD
)PsGetCurrentThreadWin32Thread();
1326 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1328 FromEntry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, CopyFrom
);
1330 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1331 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1334 /* lock the object, we must not convert stock objects, so don't check!!! */
1335 FromPrevProcId
= InterlockedCompareExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1336 if (FromPrevProcId
== FromProcessId
)
1338 PW32THREAD PrevThread
;
1341 if ((FromEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
1343 Object
= FromEntry
->KernelData
;
1345 /* save the pointer to the calling thread so we know it was this thread
1346 that locked the object */
1347 PrevThread
= Object
->Tid
;
1348 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1350 /* now let's change the ownership of the target object */
1352 if (((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1354 PEPROCESS ProcessTo
;
1356 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1358 GDIOBJ_SetOwnership(CopyTo
, ProcessTo
);
1359 ObDereferenceObject(ProcessTo
);
1364 /* mark the object as global */
1365 GDIOBJ_SetOwnership(CopyTo
, NULL
);
1368 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1372 GDIDBG_TRACELOOP(CopyFrom
, PrevThread
, Thread
);
1374 /* WTF?! The object is already locked by a different thread!
1375 Release the lock, wait a bit and try again! DO reset the pid lock
1376 so we make sure we don't access invalid memory in case the object is
1377 being deleted in the meantime (because we don't have aquired a reference
1379 FIXME - we should give up after some time unless we want to wait forever! */
1380 (void)InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1383 goto LockHandleFrom
;
1388 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1392 else if (FromPrevProcId
== FromLockedProcessId
)
1394 GDIDBG_TRACELOOP(CopyFrom
, FromPrevProcId
, FromProcessId
);
1396 /* the object is currently locked, wait some time and try again.
1397 FIXME - we shouldn't loop forever! Give up after some time! */
1400 goto LockHandleFrom
;
1402 else if ((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1404 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1405 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1406 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1407 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1408 goto LockHandleFrom
;
1412 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1420 GDI_MapHandleTable(PSECTION_OBJECT SectionObject
, PEPROCESS Process
)
1422 PVOID MappedView
= NULL
;
1424 LARGE_INTEGER Offset
;
1425 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1427 Offset
.QuadPart
= 0;
1429 ASSERT(SectionObject
!= NULL
);
1430 ASSERT(Process
!= NULL
);
1432 Status
= MmMapViewOfSection(SectionObject
,
1443 if (!NT_SUCCESS(Status
))
1449 /** PUBLIC FUNCTIONS **********************************************************/
1452 Since Brush/Pen and Region objects are sharable,,, we can just use
1453 UserHeapAlloc to allocate the small attribute objects.
1457 // Save Kernel Space Pointer
1458 (PGDIBRUSHOBJ)->pBrushAttr = IntGdiAllocObjAttr(GDIObjType_BRUSH_TYPE);
1460 // Kernel Space to User Space Pointer
1461 (PGDI_TABLE_ENTRY)->UserData = pBrushAttr;
1462 // Gdi will adjust for heap delta.
1466 (PGDI_TABLE_ENTRY)->UserData = NULL; // Zero the user ptr.
1467 UserHeapFree((PGDIBRUSHOBJ)->pBrushAttr); // Free from kernel ptr.
1468 (PGDIBRUSHOBJ)->pBrushAttr = NULL;
1471 Testing with DC_ATTR works but has drawing difficulties.
1472 Base on observation, (Over looking the obvious) we need to supply heap delta
1473 to user space gdi. Now, with testing, looks all normal.
1478 IntGdiAllocObjAttr(GDIOBJTYPE Type
)
1480 PVOID pMemAttr
= NULL
;
1484 case GDIObjType_DC_TYPE
:
1485 pMemAttr
= UserHeapAlloc(sizeof(DC_ATTR
));
1486 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(DC_ATTR
));
1488 case GDIObjType_RGN_TYPE
:
1489 pMemAttr
= UserHeapAlloc(sizeof(RGN_ATTR
));
1490 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(RGN_ATTR
));
1492 case GDIObjType_BRUSH_TYPE
:
1493 pMemAttr
= UserHeapAlloc(sizeof(BRUSH_ATTR
));
1494 if (pMemAttr
) RtlZeroMemory(pMemAttr
, sizeof(BRUSH_ATTR
));
1505 IntGdiSetBrushOwner(PGDIBRUSHOBJ pbr
, DWORD OwnerMask
)
1508 PEPROCESS Owner
= NULL
;
1509 PGDI_TABLE_ENTRY pEntry
= NULL
;
1511 if (!pbr
) return FALSE
;
1513 hBR
= pbr
->BaseObject
.hHmgr
;
1515 if (!hBR
|| (GDI_HANDLE_GET_TYPE(hBR
) != GDI_OBJECT_TYPE_BRUSH
))
1519 INT Index
= GDI_HANDLE_GET_INDEX((HGDIOBJ
)hBR
);
1520 pEntry
= &GdiHandleTable
->Entries
[Index
];
1523 if (pbr
->flAttrs
& GDIBRUSH_IS_GLOBAL
)
1525 GDIOBJ_ShareUnlockObjByPtr((POBJ
)pbr
);
1529 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1531 // Set this Brush to inaccessible mode and to an Owner of NONE.
1532 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1534 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, Owner
))
1537 // Deny user access to User Data.
1538 pEntry
->UserData
= NULL
; // This hBR is inaccessible!
1541 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1543 if (!GDIOBJ_SetOwnership((HGDIOBJ
) hBR
, PsGetCurrentProcess() ))
1546 // Allow user access to User Data.
1547 pEntry
->UserData
= pbr
->pBrushAttr
;
1555 IntGdiSetDCOwnerEx( HDC hDC
, DWORD OwnerMask
, BOOL NoSetBrush
)
1560 if (!hDC
|| (GDI_HANDLE_GET_TYPE(hDC
) != GDI_OBJECT_TYPE_DC
)) return FALSE
;
1562 if ((OwnerMask
== GDI_OBJ_HMGR_PUBLIC
) || OwnerMask
== GDI_OBJ_HMGR_NONE
)
1564 pDC
= DC_LockDc ( hDC
);
1565 MmCopyFromCaller(&pDC
->Dc_Attr
, pDC
->pDc_Attr
, sizeof(DC_ATTR
));
1568 DC_FreeDcAttr( hDC
); // Free the dcattr!
1570 if (!DC_SetOwnership( hDC
, NULL
)) // This hDC is inaccessible!
1574 if (OwnerMask
== GDI_OBJ_HMGR_POWNED
)
1576 pDC
= DC_LockDc ( hDC
);
1577 if ( !pDC
->pDc_Attr
) Ret
= TRUE
; // Must be zero.
1579 if (!Ret
) return Ret
;
1581 if (!DC_SetOwnership( hDC
, PsGetCurrentProcess() )) return Ret
;
1583 DC_AllocateDcAttr( hDC
); // Allocate new dcattr
1585 DCU_SynchDcAttrtoUser( hDC
); // Copy data from dc to dcattr
1588 if ((OwnerMask
!= GDI_OBJ_HMGR_NONE
) && !NoSetBrush
)
1590 pDC
= DC_LockDc ( hDC
);
1591 if (IntGdiSetBrushOwner((PGDIBRUSHOBJ
)pDC
->DcLevel
.pbrFill
, OwnerMask
))
1592 IntGdiSetBrushOwner((PGDIBRUSHOBJ
)pDC
->DcLevel
.pbrLine
, OwnerMask
);
1601 NtGdiCreateClientObj(
1608 /* Mask out everything that would change the type in a wrong manner */
1609 ulType
&= (GDI_HANDLE_TYPE_MASK
& ~GDI_HANDLE_BASETYPE_MASK
);
1611 /* Allocate a new object */
1612 pObject
= GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ
| ulType
);
1618 /* get the handle */
1619 handle
= pObject
->hHmgr
;
1622 GDIOBJ_UnlockObjByPtr(pObject
);
1630 NtGdiDeleteClientObj(
1634 /* We first need to get the real type from the handle */
1635 ULONG type
= GDI_HANDLE_GET_TYPE(h
);
1637 /* Check if it's really a CLIENTOBJ */
1638 if ((type
& GDI_HANDLE_BASETYPE_MASK
) != GDILoObjType_LO_CLIENTOBJ_TYPE
)
1640 /* FIXME: SetLastError? */
1643 return GDIOBJ_FreeObjByHandle(h
, type
);
1648 IntGdiGetObject(IN HANDLE Handle
,
1656 pGdiObject
= GDIOBJ_LockObj(Handle
, GDI_OBJECT_TYPE_DONTCARE
);
1659 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1663 dwObjectType
= GDIOBJ_GetObjectType(Handle
);
1664 switch (dwObjectType
)
1666 case GDI_OBJECT_TYPE_PEN
:
1667 case GDI_OBJECT_TYPE_EXTPEN
:
1668 Result
= PEN_GetObject((PGDIBRUSHOBJ
) pGdiObject
, cbCount
, (PLOGPEN
) lpBuffer
); // IntGdiCreatePenIndirect
1671 case GDI_OBJECT_TYPE_BRUSH
:
1672 Result
= BRUSH_GetObject((PGDIBRUSHOBJ
) pGdiObject
, cbCount
, (LPLOGBRUSH
)lpBuffer
);
1675 case GDI_OBJECT_TYPE_BITMAP
:
1676 Result
= BITMAP_GetObject((SURFACE
*) pGdiObject
, cbCount
, lpBuffer
);
1678 case GDI_OBJECT_TYPE_FONT
:
1679 Result
= FontGetObject((PTEXTOBJ
) pGdiObject
, cbCount
, lpBuffer
);
1681 // Fix the LOGFONT structure for the stock fonts
1682 if (FIRST_STOCK_HANDLE
<= Handle
&& Handle
<= LAST_STOCK_HANDLE
)
1684 FixStockFontSizeW(Handle
, cbCount
, lpBuffer
);
1689 case GDI_OBJECT_TYPE_PALETTE
:
1690 Result
= PALETTE_GetObject((PPALGDI
) pGdiObject
, cbCount
, lpBuffer
);
1694 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType
);
1698 GDIOBJ_UnlockObjByPtr(pGdiObject
);
1708 NtGdiExtGetObjectW(IN HANDLE hGdiObj
,
1710 OUT LPVOID lpBuffer
)
1717 DIBSECTION dibsection
;
1721 EXTLOGFONTW extlogfontw
;
1722 ENUMLOGFONTEXDVW enumlogfontexdvw
;
1725 // Normalize to the largest supported object size
1726 cbCount
= min((UINT
)cbCount
, sizeof(Object
));
1728 // Now do the actual call
1729 iRetCount
= IntGdiGetObject(hGdiObj
, cbCount
, lpBuffer
? &Object
: NULL
);
1730 cbCopyCount
= min((UINT
)cbCount
, (UINT
)iRetCount
);
1732 // Make sure we have a buffer and a copy size
1733 if ((cbCopyCount
) && (lpBuffer
))
1735 // Enter SEH for buffer transfer
1738 // Probe the buffer and copy it
1739 ProbeForWrite(lpBuffer
, cbCopyCount
, sizeof(WORD
));
1740 RtlCopyMemory(lpBuffer
, &Object
, cbCopyCount
);
1742 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1744 // Clear the return value.
1745 // Do *NOT* set last error here!