2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/gdiobj.c
5 * PURPOSE: General GDI object manipulation routines
6 * PROGRAMMERS: Timo Kreuzer
10 * If you want to understand this code, you need to start thinking in portals.
11 * - gpaulRefCount is a global pointer to an allocated array of ULONG values,
12 * one for each handle. Bits 0 - 22 contain a reference count for the handle.
13 * It gets increased for each handle lock / reference. Bit 23 contains a valid
14 * bit. If this bit is 0, the handle got deleted and will be pushed to the free
15 * list, once all references are gone. Bits 24 - 31 contain the reuse value of
16 * the handle, which allows to check if the entry was changed before atomically
17 * exchanging the reference count.
18 * - Objects can exist with or without a handle
19 * - Objects with a handle can be locked either exclusively or shared.
20 * Both locks increase the handle reference count in gpaulRefCount.
21 * Exclusive locks also increase the BASEOBJECT's cExclusiveLock field
22 * and the first lock (can be acquired recursively) acquires a pushlock
23 * that is also stored in the BASEOBJECT.
24 * - Objects without a handle cannot have exclusive locks. Their reference
25 * count is tracked in the BASEOBJECT's ulShareCount field.
26 * - An object that is inserted in the handle table automatically has an
27 * exclusive lock. For objects that are "shared objects" (BRUSH, PALETTE, ...)
28 * this is the only way it can ever be exclusively locked. It prevents the
29 * object from being locked by another thread. A shared lock will simply fail,
30 * while an exclusive lock will succeed after the object was unlocked.
34 * Owner: POWNED PUBLIC NONE spec
35 * ---------------------------------------------------
36 * LockForRead + + - PUBLIC
37 * LockForWrite + - - POWNED
39 * NtGdiDeleteObjectApp + - - PUBLIC
40 * GreDeleteObject + + + NONE
41 * GreSetOwner(POWNED) - - + -
42 * GreSetOwner(PUBLIC) + - + -
43 * GreSetOwner(NONE) + - - -
47 /* INCLUDES ******************************************************************/
56 _In_ _Interlocked_operand_ ULONG
volatile *Source
)
63 INCREASE_THREAD_LOCK_COUNT(
66 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
67 DBG_UNREFERENCED_PARAMETER(hobj
);
71 pti
->acExclusiveLockCount
[((ULONG_PTR
)hobj
>> 16) & 0x1f]++;
73 pti
->cExclusiveLocks
++;
79 DECREASE_THREAD_LOCK_COUNT(
82 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
83 DBG_UNREFERENCED_PARAMETER(hobj
);
87 pti
->acExclusiveLockCount
[((ULONG_PTR
)hobj
>> 16) & 0x1f]--;
89 pti
->cExclusiveLocks
--;
98 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
103 /* Ensure correct locking order! */
104 for (i
= objt
+ 1; i
< GDIObjTypeTotal
; i
++)
106 NT_ASSERT(pti
->acExclusiveLockCount
[i
] == 0);
110 #define ASSERT_SHARED_OBJECT_TYPE(objt) \
111 ASSERT((objt) == GDIObjType_SURF_TYPE || \
112 (objt) == GDIObjType_PAL_TYPE || \
113 (objt) == GDIObjType_LFONT_TYPE || \
114 (objt) == GDIObjType_PATH_TYPE || \
115 (objt) == GDIObjType_BRUSH_TYPE)
116 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt) \
117 ASSERT((objt) == GDIObjType_DC_TYPE || \
118 (objt) == GDIObjType_RGN_TYPE || \
119 (objt) == GDIObjType_UMPD_TYPE || \
120 (objt) == GDIObjType_META_TYPE)
121 #define ASSERT_TRYLOCK_OBJECT_TYPE(objt) \
122 ASSERT((objt) == GDIObjType_DRVOBJ_TYPE)
124 #define ASSERT_LOCK_ORDER(hobj)
125 #define ASSERT_SHARED_OBJECT_TYPE(objt)
126 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt)
127 #define ASSERT_TRYLOCK_OBJECT_TYPE(objt)
130 #if defined(_M_IX86) || defined(_M_AMD64)
131 #define InterlockedOr16 _InterlockedOr16
134 #define GDIOBJ_POOL_TAG(type) ('00hG' + (((type) & 0x1f) << 24))
138 REF_MASK_REUSE
= 0xff000000,
139 REF_INC_REUSE
= 0x01000000,
140 REF_MASK_VALID
= 0x00800000,
141 REF_MASK_COUNT
= 0x007fffff,
142 REF_MASK_INUSE
= 0x00ffffff,
145 /* GLOBALS *******************************************************************/
147 /* Per session handle table globals */
148 static PVOID gpvGdiHdlTblSection
= NULL
;
150 PULONG gpaulRefCount
;
151 volatile ULONG gulFirstFree
;
152 volatile ULONG gulFirstUnused
;
153 static PPAGED_LOOKASIDE_LIST gpaLookasideList
;
155 static VOID NTAPI
GDIOBJ_vCleanup(PVOID ObjectBody
);
161 NULL
, /* 00 GDIObjType_DEF_TYPE */
162 DC_vCleanup
, /* 01 GDIObjType_DC_TYPE */
163 NULL
, /* 02 GDIObjType_UNUSED1_TYPE */
164 NULL
, /* 03 GDIObjType_UNUSED2_TYPE */
165 REGION_vCleanup
, /* 04 GDIObjType_RGN_TYPE */
166 SURFACE_vCleanup
, /* 05 GDIObjType_SURF_TYPE */
167 GDIOBJ_vCleanup
, /* 06 GDIObjType_CLIENTOBJ_TYPE */
168 GDIOBJ_vCleanup
, /* 07 GDIObjType_PATH_TYPE */
169 PALETTE_vCleanup
, /* 08 GDIObjType_PAL_TYPE */
170 GDIOBJ_vCleanup
, /* 09 GDIObjType_ICMLCS_TYPE */
171 GDIOBJ_vCleanup
, /* 0a GDIObjType_LFONT_TYPE */
172 NULL
, /* 0b GDIObjType_RFONT_TYPE, unused */
173 NULL
, /* 0c GDIObjType_PFE_TYPE, unused */
174 NULL
, /* 0d GDIObjType_PFT_TYPE, unused */
175 GDIOBJ_vCleanup
, /* 0e GDIObjType_ICMCXF_TYPE */
176 NULL
, /* 0f GDIObjType_SPRITE_TYPE, unused */
177 NULL
, /* 10 GDIObjType_BRUSH_TYPE, BRUSH, PEN, EXTPEN */
178 NULL
, /* 11 GDIObjType_UMPD_TYPE, unused */
179 NULL
, /* 12 GDIObjType_UNUSED4_TYPE */
180 NULL
, /* 13 GDIObjType_SPACE_TYPE, unused */
181 NULL
, /* 14 GDIObjType_UNUSED5_TYPE */
182 GDIOBJ_vCleanup
, /* 15 GDIObjType_META_TYPE */
183 NULL
, /* 16 GDIObjType_EFSTATE_TYPE, unused */
184 NULL
, /* 17 GDIObjType_BMFD_TYPE, unused */
185 NULL
, /* 18 GDIObjType_VTFD_TYPE, unused */
186 NULL
, /* 19 GDIObjType_TTFD_TYPE, unused */
187 NULL
, /* 1a GDIObjType_RC_TYPE, unused */
188 NULL
, /* 1b GDIObjType_TEMP_TYPE, unused */
189 DRIVEROBJ_vCleanup
,/* 1c GDIObjType_DRVOBJ_TYPE */
190 NULL
, /* 1d GDIObjType_DCIOBJ_TYPE, unused */
191 NULL
, /* 1e GDIObjType_SPOOL_TYPE, unused */
192 NULL
, /* 1f reserved entry */
199 NULL
, /* 00 GDIObjType_DEF_TYPE */
200 NULL
, /* 01 GDIObjType_DC_TYPE */
201 NULL
, /* 02 GDIObjType_UNUSED1_TYPE */
202 NULL
, /* 03 GDIObjType_UNUSED2_TYPE */
203 NULL
, /* 04 GDIObjType_RGN_TYPE */
204 NULL
, /* 05 GDIObjType_SURF_TYPE */
205 NULL
, /* 06 GDIObjType_CLIENTOBJ_TYPE */
206 NULL
, /* 07 GDIObjType_PATH_TYPE */
207 NULL
, /* 08 GDIObjType_PAL_TYPE */
208 NULL
, /* 09 GDIObjType_ICMLCS_TYPE */
209 NULL
, /* 0a GDIObjType_LFONT_TYPE */
210 NULL
, /* 0b GDIObjType_RFONT_TYPE, unused */
211 NULL
, /* 0c GDIObjType_PFE_TYPE, unused */
212 NULL
, /* 0d GDIObjType_PFT_TYPE, unused */
213 NULL
, /* 0e GDIObjType_ICMCXF_TYPE */
214 NULL
, /* 0f GDIObjType_SPRITE_TYPE, unused */
215 BRUSH_vDeleteObject
, /* 10 GDIObjType_BRUSH_TYPE, BRUSH, PEN, EXTPEN */
216 NULL
, /* 11 GDIObjType_UMPD_TYPE, unused */
217 NULL
, /* 12 GDIObjType_UNUSED4_TYPE */
218 NULL
, /* 13 GDIObjType_SPACE_TYPE, unused */
219 NULL
, /* 14 GDIObjType_UNUSED5_TYPE */
220 NULL
, /* 15 GDIObjType_META_TYPE, unused */
221 NULL
, /* 16 GDIObjType_EFSTATE_TYPE, unused */
222 NULL
, /* 17 GDIObjType_BMFD_TYPE, unused */
223 NULL
, /* 18 GDIObjType_VTFD_TYPE, unused */
224 NULL
, /* 19 GDIObjType_TTFD_TYPE, unused */
225 NULL
, /* 1a GDIObjType_RC_TYPE, unused */
226 NULL
, /* 1b GDIObjType_TEMP_TYPE, unused */
227 NULL
, /* 1c GDIObjType_DRVOBJ_TYPE */
228 NULL
, /* 1d GDIObjType_DCIOBJ_TYPE, unused */
229 NULL
, /* 1e GDIObjType_SPOOL_TYPE, unused */
230 NULL
, /* 1f reserved entry */
233 /* INTERNAL FUNCTIONS ********************************************************/
238 GDIOBJ_vCleanup(PVOID ObjectBody
)
245 InitLookasideList(UCHAR objt
, ULONG cjSize
)
247 ExInitializePagedLookasideList(&gpaLookasideList
[objt
],
252 GDITAG_HMGR_LOOKASIDE_START
+ (objt
<< 24),
259 InitGdiHandleTable(void)
262 LARGE_INTEGER liSize
;
264 SIZE_T cjViewSize
= 0;
266 /* Create a section for the shared handle table */
267 liSize
.QuadPart
= sizeof(GDI_HANDLE_TABLE
); // GDI_HANDLE_COUNT * sizeof(ENTRY);
268 status
= MmCreateSection(&gpvGdiHdlTblSection
,
276 if (!NT_SUCCESS(status
))
278 DPRINT1("INITGDI: Could not allocate a GDI handle table.\n");
282 /* Map the section in session space */
283 status
= MmMapViewInSessionSpace(gpvGdiHdlTblSection
,
286 if (!NT_SUCCESS(status
))
288 DPRINT1("INITGDI: Failed to map handle table section\n");
289 ObDereferenceObject(gpvGdiHdlTblSection
);
293 /* Allocate memory for the reference counter table */
294 gpaulRefCount
= EngAllocSectionMem(&pvSection
,
296 GDI_HANDLE_COUNT
* sizeof(ULONG
),
300 DPRINT1("INITGDI: Failed to allocate reference table.\n");
301 ObDereferenceObject(gpvGdiHdlTblSection
);
302 return STATUS_INSUFFICIENT_RESOURCES
;
306 gulFirstUnused
= RESERVE_ENTRIES_COUNT
;
308 GdiHandleTable
= (PVOID
)gpentHmgr
;
310 /* Initialize the lookaside lists */
311 gpaLookasideList
= ExAllocatePoolWithTag(NonPagedPool
,
312 GDIObjTypeTotal
* sizeof(PAGED_LOOKASIDE_LIST
),
314 if(!gpaLookasideList
)
315 return STATUS_NO_MEMORY
;
317 InitLookasideList(GDIObjType_DC_TYPE
, sizeof(DC
));
318 InitLookasideList(GDIObjType_RGN_TYPE
, sizeof(REGION
));
319 InitLookasideList(GDIObjType_SURF_TYPE
, sizeof(SURFACE
));
320 InitLookasideList(GDIObjType_CLIENTOBJ_TYPE
, sizeof(CLIENTOBJ
));
321 InitLookasideList(GDIObjType_PATH_TYPE
, sizeof(PATH
));
322 InitLookasideList(GDIObjType_PAL_TYPE
, sizeof(PALETTE
));
323 InitLookasideList(GDIObjType_ICMLCS_TYPE
, sizeof(COLORSPACE
));
324 InitLookasideList(GDIObjType_LFONT_TYPE
, sizeof(TEXTOBJ
));
325 InitLookasideList(GDIObjType_BRUSH_TYPE
, sizeof(BRUSH
));
327 return STATUS_SUCCESS
;
332 IncrementCurrentProcessGdiHandleCount(void)
334 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
335 if (ppi
) InterlockedIncrement((LONG
*)&ppi
->GDIHandleCount
);
340 DecrementCurrentProcessGdiHandleCount(void)
342 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
343 if (ppi
) InterlockedDecrement((LONG
*)&ppi
->GDIHandleCount
);
348 IncrementGdiHandleCount(ULONG ulProcessId
)
354 Status
= PsLookupProcessByProcessId(ULongToHandle(ulProcessId
), &pep
);
355 NT_ASSERT(NT_SUCCESS(Status
));
356 __analysis_assume(NT_SUCCESS(Status
));
358 ppi
= PsGetProcessWin32Process(pep
);
359 if (ppi
) InterlockedIncrement((LONG
*)&ppi
->GDIHandleCount
);
360 if (NT_SUCCESS(Status
)) ObDereferenceObject(pep
);
365 DecrementGdiHandleCount(ULONG ulProcessId
)
371 Status
= PsLookupProcessByProcessId(ULongToHandle(ulProcessId
), &pep
);
372 NT_ASSERT(NT_SUCCESS(Status
));
373 __analysis_assume(NT_SUCCESS(Status
));
375 ppi
= PsGetProcessWin32Process(pep
);
376 if (ppi
) InterlockedDecrement((LONG
*)&ppi
->GDIHandleCount
);
377 if (NT_SUCCESS(Status
)) ObDereferenceObject(pep
);
382 ENTRY_pentPopFreeEntry(VOID
)
384 ULONG iFirst
, iNext
, iPrev
;
387 DPRINT("Enter InterLockedPopFreeEntry\n");
391 /* Get the index and sequence number of the first free entry */
392 iFirst
= InterlockedReadUlong(&gulFirstFree
);
394 /* Check if we have a free entry */
395 if (!(iFirst
& GDI_HANDLE_INDEX_MASK
))
397 /* Increment FirstUnused and get the new index */
398 iFirst
= InterlockedIncrement((LONG
*)&gulFirstUnused
) - 1;
400 /* Check if we have unused entries left */
401 if (iFirst
>= GDI_HANDLE_COUNT
)
403 DPRINT1("No more GDI handles left!\n");
404 #if DBG_ENABLE_GDIOBJ_BACKTRACES
405 DbgDumpGdiHandleTableWithBT();
407 InterlockedDecrement((LONG
*)&gulFirstUnused
);
411 /* Return the old entry */
412 return &gpentHmgr
[iFirst
];
415 /* Get a pointer to the first free entry */
416 pentFree
= &gpentHmgr
[iFirst
& GDI_HANDLE_INDEX_MASK
];
418 /* Create a new value with an increased sequence number */
419 iNext
= GDI_HANDLE_GET_INDEX(pentFree
->einfo
.hFree
);
420 iNext
|= (iFirst
& ~GDI_HANDLE_INDEX_MASK
) + 0x10000;
422 /* Try to exchange the FirstFree value */
423 iPrev
= InterlockedCompareExchange((LONG
*)&gulFirstFree
,
427 while (iPrev
!= iFirst
);
429 /* Sanity check: is entry really free? */
430 ASSERT(((ULONG_PTR
)pentFree
->einfo
.pobj
& ~GDI_HANDLE_INDEX_MASK
) == 0);
435 /* Pushes an entry of the handle table to the free list,
436 The entry must not have any references left */
439 ENTRY_vPushFreeEntry(PENTRY pentFree
)
441 ULONG iToFree
, iFirst
, iPrev
, idxToFree
;
443 DPRINT("Enter ENTRY_vPushFreeEntry\n");
445 idxToFree
= pentFree
- gpentHmgr
;
446 ASSERT((gpaulRefCount
[idxToFree
] & REF_MASK_INUSE
) == 0);
448 /* Initialize entry */
449 pentFree
->Objt
= GDIObjType_DEF_TYPE
;
450 pentFree
->ObjectOwner
.ulObj
= 0;
451 pentFree
->pUser
= NULL
;
453 /* Increase reuse counter in entry and reference counter */
454 InterlockedExchangeAdd((LONG
*)&gpaulRefCount
[idxToFree
], REF_INC_REUSE
);
455 pentFree
->FullUnique
+= 0x0100;
459 /* Get the current first free index and sequence number */
460 iFirst
= InterlockedReadUlong(&gulFirstFree
);
462 /* Set the einfo.pobj member to the index of the first free entry */
463 pentFree
->einfo
.pobj
= UlongToPtr(iFirst
& GDI_HANDLE_INDEX_MASK
);
465 /* Combine new index and increased sequence number in iToFree */
466 iToFree
= idxToFree
| ((iFirst
& ~GDI_HANDLE_INDEX_MASK
) + 0x10000);
468 /* Try to atomically update the first free entry */
469 iPrev
= InterlockedCompareExchange((LONG
*)&gulFirstFree
,
473 while (iPrev
!= iFirst
);
478 ENTRY_ReferenceEntryByHandle(HGDIOBJ hobj
, FLONG fl
)
480 ULONG ulIndex
, cNewRefs
, cOldRefs
;
483 /* Get the handle index and check if its too big */
484 ulIndex
= GDI_HANDLE_GET_INDEX(hobj
);
486 /* Get pointer to the entry */
487 pentry
= &gpentHmgr
[ulIndex
];
489 /* Get the current reference count */
490 cOldRefs
= gpaulRefCount
[ulIndex
];
494 /* Check if the slot is deleted */
495 if ((cOldRefs
& REF_MASK_VALID
) == 0)
497 DPRINT("GDIOBJ: Slot is not valid: 0x%lx, hobh=%p\n", cOldRefs
, hobj
);
501 /* Check if the unique value matches */
502 if (pentry
->FullUnique
!= (USHORT
)((ULONG_PTR
)hobj
>> 16))
504 DPRINT("GDIOBJ: Wrong unique value. Handle: 0x%4x, entry: 0x%4x\n",
505 (USHORT
)((ULONG_PTR
)hobj
>> 16), pentry
->FullUnique
);
509 /* Check if the object owner is this process or public */
510 if (!(fl
& GDIOBJFLAG_IGNOREPID
) &&
511 pentry
->ObjectOwner
.ulObj
!= GDI_OBJ_HMGR_PUBLIC
&&
512 pentry
->ObjectOwner
.ulObj
!= PtrToUlong(PsGetCurrentProcessId()))
514 DPRINT("GDIOBJ: Cannot reference foreign handle %p, pentry=%p:%lx.\n",
515 hobj
, pentry
, pentry
->ObjectOwner
.ulObj
);
519 /* Try to atomically increment the reference count */
520 cNewRefs
= cOldRefs
+ 1;
521 cOldRefs
= InterlockedCompareExchange((PLONG
)&gpaulRefCount
[ulIndex
],
525 while (cNewRefs
!= cOldRefs
+ 1);
527 /* Integrity checks */
528 ASSERT((pentry
->FullUnique
& 0x1f) == pentry
->Objt
);
529 ASSERT(pentry
->einfo
.pobj
&& pentry
->einfo
.pobj
->hHmgr
== hobj
);
536 ENTRY_hInsertObject(PENTRY pentry
, POBJ pobj
, UCHAR objt
, ULONG ulOwner
)
540 /* Calculate the handle index */
541 ulIndex
= pentry
- gpentHmgr
;
543 /* Update the fields in the ENTRY */
544 pentry
->einfo
.pobj
= pobj
;
545 pentry
->Objt
= objt
& 0x1f;
546 pentry
->FullUnique
= (pentry
->FullUnique
& 0xff00) | objt
;
547 pentry
->ObjectOwner
.ulObj
= ulOwner
;
549 /* Make the handle valid with 1 reference */
550 ASSERT((gpaulRefCount
[ulIndex
] & REF_MASK_INUSE
) == 0);
551 InterlockedOr((LONG
*)&gpaulRefCount
[ulIndex
], REF_MASK_VALID
| 1);
553 /* Return the handle */
554 return (HGDIOBJ
)(((ULONG_PTR
)pentry
->FullUnique
<< 16) | ulIndex
);
559 GDIOBJ_AllocateObject(UCHAR objt
, ULONG cjSize
, FLONG fl
)
563 if (fl
& BASEFLAG_LOOKASIDE
)
565 /* Allocate the object from a lookaside list */
566 pobj
= ExAllocateFromPagedLookasideList(&gpaLookasideList
[objt
& 0x1f]);
570 /* Allocate the object from paged pool */
571 pobj
= ExAllocatePoolWithTag(PagedPool
, cjSize
, GDIOBJ_POOL_TAG(objt
));
574 if (!pobj
) return NULL
;
576 /* Initialize the object */
577 RtlZeroMemory(pobj
, cjSize
);
578 pobj
->hHmgr
= (HGDIOBJ
)((ULONG_PTR
)objt
<< 16);
579 pobj
->cExclusiveLock
= 0;
580 pobj
->ulShareCount
= 1;
581 pobj
->BaseFlags
= fl
& 0xffff;
582 DBG_INITLOG(&pobj
->slhLog
);
583 DBG_LOGEVENT(&pobj
->slhLog
, EVENT_ALLOCATE
, 0);
584 #if DBG_ENABLE_GDIOBJ_BACKTRACES
585 DbgCaptureStackBackTace(pobj
->apvBackTrace
, 1, GDI_OBJECT_STACK_LEVELS
);
586 #endif /* GDI_DEBUG */
593 GDIOBJ_vFreeObject(POBJ pobj
)
597 DBG_CLEANUP_EVENT_LIST(&pobj
->slhLog
);
599 /* Get the object type */
600 objt
= ((ULONG_PTR
)pobj
->hHmgr
>> 16) & 0x1f;
602 /* Check if we have a delete procedure (for C++ based objects) */
603 if (apfnDelete
[objt
] != NULL
)
605 /* Invoke the delete procedure */
606 apfnDelete
[objt
](pobj
);
610 /* Call the cleanup procedure */
611 NT_ASSERT(apfnCleanup
[objt
]);
612 apfnCleanup
[objt
](pobj
);
614 /* Check if the object is allocated from a lookaside list */
615 if (pobj
->BaseFlags
& BASEFLAG_LOOKASIDE
)
617 ExFreeToPagedLookasideList(&gpaLookasideList
[objt
], pobj
);
621 ExFreePoolWithTag(pobj
, GDIOBJ_POOL_TAG(objt
));
628 GDIOBJ_vDereferenceObject(POBJ pobj
)
630 ULONG cRefs
, ulIndex
;
632 /* Calculate the index */
633 ulIndex
= GDI_HANDLE_GET_INDEX(pobj
->hHmgr
);
635 /* Check if the object has a handle */
638 /* Decrement reference count */
639 if ((gpaulRefCount
[ulIndex
] & REF_MASK_COUNT
) == 0)
641 DBG_DUMP_EVENT_LIST(&pobj
->slhLog
);
643 ASSERT((gpaulRefCount
[ulIndex
] & REF_MASK_COUNT
) > 0);
644 cRefs
= InterlockedDecrement((LONG
*)&gpaulRefCount
[ulIndex
]);
645 DBG_LOGEVENT(&pobj
->slhLog
, EVENT_DEREFERENCE
, cRefs
);
647 /* Check if we reached 0 and handle bit is not set */
648 if ((cRefs
& REF_MASK_INUSE
) == 0)
650 /* Make sure it's ok to delete the object */
651 ASSERT(pobj
->BaseFlags
& BASEFLAG_READY_TO_DIE
);
653 /* Check if the handle was process owned */
654 if (gpentHmgr
[ulIndex
].ObjectOwner
.ulObj
!= GDI_OBJ_HMGR_PUBLIC
&&
655 gpentHmgr
[ulIndex
].ObjectOwner
.ulObj
!= GDI_OBJ_HMGR_NONE
)
657 /* Decrement the process handle count */
658 ASSERT(gpentHmgr
[ulIndex
].ObjectOwner
.ulObj
==
659 HandleToUlong(PsGetCurrentProcessId()));
660 DecrementCurrentProcessGdiHandleCount();
663 /* Push entry to the free list */
664 ENTRY_vPushFreeEntry(&gpentHmgr
[ulIndex
]);
666 /* Free the object */
667 GDIOBJ_vFreeObject(pobj
);
672 /* Decrement the objects reference count */
673 ASSERT(pobj
->ulShareCount
> 0);
674 cRefs
= InterlockedDecrement((LONG
*)&pobj
->ulShareCount
);
675 DBG_LOGEVENT(&pobj
->slhLog
, EVENT_DEREFERENCE
, cRefs
);
677 /* Check if we reached 0 */
680 /* Free the object */
681 GDIOBJ_vFreeObject(pobj
);
688 GDIOBJ_ReferenceObjectByHandle(
695 /* Check if the handle type matches */
696 ASSERT_SHARED_OBJECT_TYPE(objt
);
697 if ((((ULONG_PTR
)hobj
>> 16) & 0x1f) != objt
)
699 DPRINT("GDIOBJ: Wrong type. handle=%p, type=%x\n", hobj
, objt
);
703 /* Reference the handle entry */
704 pentry
= ENTRY_ReferenceEntryByHandle(hobj
, 0);
707 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj
);
711 /* Get the pointer to the BASEOBJECT */
712 pobj
= pentry
->einfo
.pobj
;
714 /* Check if the object is exclusively locked */
715 if (pobj
->cExclusiveLock
!= 0)
717 DPRINT1("GDIOBJ: Cannot reference object %p with exclusive lock.\n", hobj
);
718 GDIOBJ_vDereferenceObject(pobj
);
719 DBG_DUMP_EVENT_LIST(&pobj
->slhLog
);
723 DBG_LOGEVENT(&pobj
->slhLog
, EVENT_REFERENCE
, gpaulRefCount
[pentry
- gpentHmgr
]);
725 /* All is well, return the object */
731 GDIOBJ_vReferenceObjectByPointer(POBJ pobj
)
735 /* Check if the object has a handle */
736 if (GDI_HANDLE_GET_INDEX(pobj
->hHmgr
))
738 /* Increase the handle's reference count */
739 ULONG ulIndex
= GDI_HANDLE_GET_INDEX(pobj
->hHmgr
);
740 ASSERT((gpaulRefCount
[ulIndex
] & REF_MASK_COUNT
) > 0);
741 cRefs
= InterlockedIncrement((LONG
*)&gpaulRefCount
[ulIndex
]);
745 /* Increase the object's reference count */
746 cRefs
= InterlockedIncrement((LONG
*)&pobj
->ulShareCount
);
749 DBG_LOGEVENT(&pobj
->slhLog
, EVENT_REFERENCE
, cRefs
);
754 GDIOBJ_TryLockObject(
762 /* Check if the handle type matches */
763 ASSERT_TRYLOCK_OBJECT_TYPE(objt
);
764 if ((((ULONG_PTR
)hobj
>> 16) & 0x1f) != objt
)
766 DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj
, objt
);
770 /* Make sure lock order is correct */
771 ASSERT_LOCK_ORDER(objt
);
773 /* Reference the handle entry */
774 pentry
= ENTRY_ReferenceEntryByHandle(hobj
, 0);
777 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj
);
781 /* Get the pointer to the BASEOBJECT */
782 pobj
= pentry
->einfo
.pobj
;
784 /* Check if we already own the lock */
785 dwThreadId
= PtrToUlong(PsGetCurrentThreadId());
786 if (pobj
->dwThreadId
!= dwThreadId
)
788 /* Disable APCs and try acquiring the push lock */
789 KeEnterCriticalRegion();
790 if(!ExTryAcquirePushLockExclusive(&pobj
->pushlock
))
792 ULONG cRefs
, ulIndex
;
793 /* Already owned. Clean up and leave. */
794 KeLeaveCriticalRegion();
796 /* Calculate the index */
797 ulIndex
= GDI_HANDLE_GET_INDEX(pobj
->hHmgr
);
799 /* Decrement reference count */
800 ASSERT((gpaulRefCount
[ulIndex
] & REF_MASK_COUNT
) > 0);
801 cRefs
= InterlockedDecrement((LONG
*)&gpaulRefCount
[ulIndex
]);
802 ASSERT(cRefs
& REF_MASK_VALID
);
807 /* Set us as lock owner */
808 ASSERT(pobj
->dwThreadId
== 0);
809 pobj
->dwThreadId
= dwThreadId
;
812 /* Increase lock count */
813 pobj
->cExclusiveLock
++;
814 INCREASE_THREAD_LOCK_COUNT(hobj
);
815 DBG_LOGEVENT(&pobj
->slhLog
, EVENT_LOCK
, 0);
817 /* Return the object */
831 /* Check if the handle type matches */
832 ASSERT_EXCLUSIVE_OBJECT_TYPE(objt
);
833 if ((((ULONG_PTR
)hobj
>> 16) & 0x1f) != objt
)
835 DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj
, objt
);
839 /* Make sure lock order is correct */
840 ASSERT_LOCK_ORDER(objt
);
842 /* Reference the handle entry */
843 pentry
= ENTRY_ReferenceEntryByHandle(hobj
, 0);
846 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj
);
850 /* Get the pointer to the BASEOBJECT */
851 pobj
= pentry
->einfo
.pobj
;
853 /* Check if we already own the lock */
854 dwThreadId
= PtrToUlong(PsGetCurrentThreadId());
855 if (pobj
->dwThreadId
!= dwThreadId
)
857 /* Disable APCs and acquire the push lock */
858 KeEnterCriticalRegion();
859 ExAcquirePushLockExclusive(&pobj
->pushlock
);
861 /* Set us as lock owner */
862 ASSERT(pobj
->dwThreadId
== 0);
863 pobj
->dwThreadId
= dwThreadId
;
866 /* Increase lock count */
867 pobj
->cExclusiveLock
++;
868 INCREASE_THREAD_LOCK_COUNT(hobj
);
869 DBG_LOGEVENT(&pobj
->slhLog
, EVENT_LOCK
, 0);
871 /* Return the object */
877 GDIOBJ_vUnlockObject(POBJ pobj
)
879 ULONG cRefs
, ulIndex
;
880 ASSERT(pobj
->cExclusiveLock
> 0);
882 /* Decrease lock count */
883 pobj
->cExclusiveLock
--;
884 DECREASE_THREAD_LOCK_COUNT(pobj
->hHmgr
);
885 DBG_LOGEVENT(&pobj
->slhLog
, EVENT_UNLOCK
, 0);
887 /* Check if this was the last lock */
888 if (pobj
->cExclusiveLock
== 0)
890 /* Reset lock owner */
891 pobj
->dwThreadId
= 0;
893 /* Release the pushlock and reenable APCs */
894 ExReleasePushLockExclusive(&pobj
->pushlock
);
895 KeLeaveCriticalRegion();
898 /* Calculate the index */
899 ulIndex
= GDI_HANDLE_GET_INDEX(pobj
->hHmgr
);
901 /* Decrement reference count */
902 ASSERT((gpaulRefCount
[ulIndex
] & REF_MASK_COUNT
) > 0);
903 cRefs
= InterlockedDecrement((LONG
*)&gpaulRefCount
[ulIndex
]);
904 ASSERT(cRefs
& REF_MASK_VALID
);
909 GDIOBJ_hInsertObject(
916 /* Must have no handle and only one reference */
917 ASSERT(GDI_HANDLE_GET_INDEX(pobj
->hHmgr
) == 0);
918 ASSERT(pobj
->cExclusiveLock
== 0);
919 ASSERT(pobj
->ulShareCount
== 1);
921 /* Get a free handle entry */
922 pentry
= ENTRY_pentPopFreeEntry();
925 DPRINT1("GDIOBJ: Could not get a free entry.\n");
929 /* Make the object exclusively locked */
930 ExInitializePushLock(&pobj
->pushlock
);
931 KeEnterCriticalRegion();
932 ExAcquirePushLockExclusive(&pobj
->pushlock
);
933 pobj
->cExclusiveLock
= 1;
934 pobj
->dwThreadId
= PtrToUlong(PsGetCurrentThreadId());
935 INCREASE_THREAD_LOCK_COUNT(pobj
->hHmgr
);
937 /* Get object type from the hHmgr field */
938 objt
= ((ULONG_PTR
)pobj
->hHmgr
>> 16) & 0xff;
939 ASSERT(objt
!= GDIObjType_DEF_TYPE
);
941 /* Check if current process is requested owner */
942 if (ulOwner
== GDI_OBJ_HMGR_POWNED
)
944 /* Increment the process handle count */
945 IncrementCurrentProcessGdiHandleCount();
948 ulOwner
= HandleToUlong(PsGetCurrentProcessId());
951 /* Insert the object into the handle table */
952 pobj
->hHmgr
= ENTRY_hInsertObject(pentry
, pobj
, objt
, ulOwner
);
954 /* Return the handle */
955 DPRINT("GDIOBJ: Created handle: %p\n", pobj
->hHmgr
);
956 DBG_LOGEVENT(&pobj
->slhLog
, EVENT_CREATE_HANDLE
, 0);
962 GDIOBJ_vSetObjectOwner(
969 /* This is a ugly HACK, needed to fix IntGdiSetDCOwnerEx */
970 if (GDI_HANDLE_IS_STOCKOBJ(pobj
->hHmgr
))
972 DPRINT("Trying to set ownership of stock object %p to %lx\n", pobj
->hHmgr
, ulNewOwner
);
976 /* Get the handle entry */
977 NT_ASSERT(GDI_HANDLE_GET_INDEX(pobj
->hHmgr
));
978 pentry
= &gpentHmgr
[GDI_HANDLE_GET_INDEX(pobj
->hHmgr
)];
980 /* Check if the new owner is the same as the old one */
981 ulOldOwner
= pentry
->ObjectOwner
.ulObj
;
982 if (ulOldOwner
== ulNewOwner
)
988 /* Is the current process requested? */
989 if (ulNewOwner
== GDI_OBJ_HMGR_POWNED
)
992 ulNewOwner
= HandleToUlong(PsGetCurrentProcessId());
996 if (ulNewOwner
== GDI_OBJ_HMGR_NONE
)
997 ulNewOwner
= GDI_OBJ_HMGR_PUBLIC
;
999 /* Was the object process owned? */
1000 if ((ulOldOwner
!= GDI_OBJ_HMGR_PUBLIC
) &&
1001 (ulOldOwner
!= GDI_OBJ_HMGR_NONE
))
1003 /* Decrement the previous owners handle count */
1004 DecrementGdiHandleCount(ulOldOwner
);
1007 /* Is the new owner a process? */
1008 if ((ulNewOwner
!= GDI_OBJ_HMGR_PUBLIC
) &&
1009 (ulNewOwner
!= GDI_OBJ_HMGR_NONE
))
1011 /* Increment the new owners handle count */
1012 IncrementGdiHandleCount(ulNewOwner
);
1016 /* Make sure we don't leak user mode memory */
1017 NT_ASSERT(pentry
->pUser
== NULL
);
1021 pentry
->ObjectOwner
.ulObj
= ulNewOwner
;
1022 DBG_LOGEVENT(&pobj
->slhLog
, EVENT_SET_OWNER
, 0);
1025 /* Locks 2 or 3 objects at a time */
1028 GDIOBJ_bLockMultipleObjects(
1034 UINT auiIndices
[3] = {0, 1, 2};
1037 ASSERT(ulCount
<= 3);
1039 /* Sort the handles */
1040 for (i
= 0; i
< ulCount
- 1; i
++)
1042 for (j
= i
+ 1; j
< ulCount
; j
++)
1044 if ((ULONG_PTR
)ahObj
[auiIndices
[i
]] <
1045 (ULONG_PTR
)ahObj
[auiIndices
[j
]])
1047 tmp
= auiIndices
[i
];
1048 auiIndices
[i
] = auiIndices
[j
];
1049 auiIndices
[j
] = tmp
;
1054 /* Lock the objects in safe order */
1055 for (i
= 0; i
< ulCount
; i
++)
1057 /* Skip NULL handles */
1058 if (ahObj
[auiIndices
[i
]] == NULL
)
1060 apObj
[auiIndices
[i
]] = NULL
;
1064 /* Lock the object */
1065 apObj
[auiIndices
[i
]] = GDIOBJ_LockObject(ahObj
[auiIndices
[i
]], objt
);
1067 /* Check for failure */
1068 if (apObj
[auiIndices
[i
]] == NULL
)
1073 if (apObj
[auiIndices
[i
]])
1074 GDIOBJ_vUnlockObject(apObj
[auiIndices
[i
]]);
1085 GDIOBJ_pvGetObjectAttr(POBJ pobj
)
1087 ULONG ulIndex
= GDI_HANDLE_GET_INDEX(pobj
->hHmgr
);
1088 return gpentHmgr
[ulIndex
].pUser
;
1093 GDIOBJ_vSetObjectAttr(POBJ pobj
, PVOID pvObjAttr
)
1097 ASSERT(pobj
->hHmgr
);
1099 /* Get the handle index */
1100 ulIndex
= GDI_HANDLE_GET_INDEX(pobj
->hHmgr
);
1102 /* Set pointer to the usermode attribute */
1103 gpentHmgr
[ulIndex
].pUser
= pvObjAttr
;
1108 GDIOBJ_vDeleteObject(POBJ pobj
)
1112 /* Set the object's delete flag */
1113 InterlockedOr16((SHORT
*)&pobj
->BaseFlags
, BASEFLAG_READY_TO_DIE
);
1114 DBG_LOGEVENT(&pobj
->slhLog
, EVENT_DELETE
, 0);
1116 /* Get the handle index */
1117 ulIndex
= GDI_HANDLE_GET_INDEX(pobj
->hHmgr
);
1120 /* Reset the handle valid bit */
1121 InterlockedAnd((LONG
*)&gpaulRefCount
[ulIndex
], ~REF_MASK_VALID
);
1123 /* Check if the object is exclusively locked */
1124 if (pobj
->cExclusiveLock
!= 0)
1126 /* Reset lock owner and lock count */
1127 pobj
->dwThreadId
= 0;
1128 pobj
->cExclusiveLock
= 0;
1130 /* Release the pushlock and reenable APCs */
1131 ExReleasePushLockExclusive(&pobj
->pushlock
);
1132 KeLeaveCriticalRegion();
1133 DECREASE_THREAD_LOCK_COUNT(pobj
->hHmgr
);
1137 /* Dereference the object (will take care of deletion) */
1138 GDIOBJ_vDereferenceObject(pobj
);
1143 GreIsHandleValid(HGDIOBJ hobj
)
1147 pentry
= ENTRY_ReferenceEntryByHandle(hobj
, 0);
1148 if (!pentry
) return FALSE
;
1149 GDIOBJ_vDereferenceObject(pentry
->einfo
.pobj
);
1155 GreDeleteObject(HGDIOBJ hobj
)
1159 /* Check for stock objects */
1160 if (GDI_HANDLE_IS_STOCKOBJ(hobj
))
1162 DPRINT1("GreDeleteObject: Cannot delete stock object %p.\n", hobj
);
1166 /* Reference the handle entry */
1167 pentry
= ENTRY_ReferenceEntryByHandle(hobj
, 0);
1170 DPRINT1("GreDeleteObject: Trying to delete invalid object %p\n", hobj
);
1174 /* Check for public owner */
1175 if (pentry
->ObjectOwner
.ulObj
== GDI_OBJ_HMGR_PUBLIC
)
1177 DPRINT1("GreDeleteObject: Trying to delete global object %p\n", hobj
);
1178 GDIOBJ_vDereferenceObject(pentry
->einfo
.pobj
);
1182 /* Delete the object */
1183 GDIOBJ_vDeleteObject(pentry
->einfo
.pobj
);
1189 GreGetObjectOwner(HGDIOBJ hobj
)
1191 ULONG ulIndex
, ulOwner
;
1193 /* Get the handle index */
1194 ulIndex
= GDI_HANDLE_GET_INDEX(hobj
);
1196 /* Check if the handle is valid */
1197 if (ulIndex
>= GDI_HANDLE_COUNT
||
1198 gpentHmgr
[ulIndex
].Objt
== GDIObjType_DEF_TYPE
||
1199 ((ULONG_PTR
)hobj
>> 16) != gpentHmgr
[ulIndex
].FullUnique
)
1201 DPRINT1("GreGetObjectOwner: invalid handle 0x%p.\n", hobj
);
1202 return GDI_OBJ_HMGR_RESTRICTED
;
1205 /* Get the object owner */
1206 ulOwner
= gpentHmgr
[ulIndex
].ObjectOwner
.ulObj
;
1208 if (ulOwner
== HandleToUlong(PsGetCurrentProcessId()))
1209 return GDI_OBJ_HMGR_POWNED
;
1211 if (ulOwner
== GDI_OBJ_HMGR_PUBLIC
)
1212 return GDI_OBJ_HMGR_PUBLIC
;
1214 return GDI_OBJ_HMGR_RESTRICTED
;
1219 GreSetObjectOwnerEx(
1226 /* Check for stock objects */
1227 if (GDI_HANDLE_IS_STOCKOBJ(hobj
))
1229 DPRINT("GreSetObjectOwner: Got stock object %p\n", hobj
);
1233 /* Reference the handle entry */
1234 pentry
= ENTRY_ReferenceEntryByHandle(hobj
, Flags
);
1237 DPRINT("GreSetObjectOwner: Invalid handle 0x%p.\n", hobj
);
1241 /* Call internal function */
1242 GDIOBJ_vSetObjectOwner(pentry
->einfo
.pobj
, ulOwner
);
1244 /* Dereference the object */
1245 GDIOBJ_vDereferenceObject(pentry
->einfo
.pobj
);
1256 return GreSetObjectOwnerEx(hobj
, ulOwner
, 0);
1270 /* Verify object type */
1271 objt
= ((ULONG_PTR
)hobj
>> 16) & 0x1f;
1272 if (objt
!= GDIObjType_BRUSH_TYPE
&&
1273 objt
!= GDIObjType_SURF_TYPE
&&
1274 objt
!= GDIObjType_LFONT_TYPE
&&
1275 objt
!= GDIObjType_PAL_TYPE
)
1277 DPRINT1("GreGetObject: Invalid object type\n");
1281 pvObj
= GDIOBJ_ReferenceObjectByHandle(hobj
, objt
);
1284 DPRINT("GreGetObject: Could not lock object\n");
1288 switch (GDI_HANDLE_GET_TYPE(hobj
))
1290 case GDILoObjType_LO_PEN_TYPE
:
1291 case GDILoObjType_LO_EXTPEN_TYPE
:
1292 iResult
= PEN_GetObject(pvObj
, cbCount
, pvBuffer
);
1295 case GDILoObjType_LO_BRUSH_TYPE
:
1296 iResult
= BRUSH_GetObject(pvObj
, cbCount
, pvBuffer
);
1299 case GDILoObjType_LO_BITMAP_TYPE
:
1300 iResult
= BITMAP_GetObject(pvObj
, cbCount
, pvBuffer
);
1303 case GDILoObjType_LO_FONT_TYPE
:
1304 iResult
= FontGetObject(pvObj
, cbCount
, pvBuffer
);
1307 case GDILoObjType_LO_PALETTE_TYPE
:
1308 iResult
= PALETTE_GetObject(pvObj
, cbCount
, pvBuffer
);
1312 DPRINT1("GDI object type of 0x%p not implemented\n", hobj
);
1316 GDIOBJ_vDereferenceObject(pvObj
);
1325 IN INT cjBufferSize
,
1326 OUT LPVOID lpBuffer
)
1328 UINT iResult
, cjMaxSize
;
1332 DIBSECTION dibsection
;
1336 EXTLOGFONTW extlogfontw
;
1337 ENUMLOGFONTEXDVW enumlogfontexdvw
;
1340 /* Normalize to the largest supported object size */
1341 cjMaxSize
= min((UINT
)cjBufferSize
, sizeof(object
));
1343 /* Now do the actual call */
1344 iResult
= GreGetObject(hobj
, cjMaxSize
, lpBuffer
? &object
: NULL
);
1346 /* Check if we have a buffer and data */
1347 if ((lpBuffer
!= NULL
) && (iResult
!= 0))
1349 /* Enter SEH for buffer transfer */
1352 /* Probe the buffer and copy it */
1353 cjMaxSize
= min(cjMaxSize
, iResult
);
1354 ProbeForWrite(lpBuffer
, cjMaxSize
, sizeof(WORD
));
1355 RtlCopyMemory(lpBuffer
, &object
, cjMaxSize
);
1357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1359 /* Clear the return value.
1360 * Do *NOT* set last error here! */
1366 /* Return the count */
1373 NtGdiCreateClientObj(
1379 /* Check if ulType is valid */
1380 if ((ulType
!= GDILoObjType_LO_METAFILE16_TYPE
) &&
1381 (ulType
!= GDILoObjType_LO_METAFILE_TYPE
) &&
1382 (ulType
!= GDILoObjType_LO_METADC16_TYPE
))
1384 DPRINT1("NtGdiCreateClientObj: Invalid object type 0x%lx.\n", ulType
);
1388 /* Allocate a new object */
1389 pObject
= GDIOBJ_AllocateObject(GDIObjType_CLIENTOBJ_TYPE
,
1391 BASEFLAG_LOOKASIDE
);
1394 DPRINT1("NtGdiCreateClientObj: Could not allocate a clientobj.\n");
1398 /* Set the real object type */
1399 pObject
->hHmgr
= UlongToHandle(ulType
| GDILoObjType_LO_CLIENTOBJ_TYPE
);
1401 /* Create a handle */
1402 handle
= GDIOBJ_hInsertObject(pObject
, GDI_OBJ_HMGR_POWNED
);
1405 DPRINT1("NtGdiCreateClientObj: Could not create a handle.\n");
1406 GDIOBJ_vFreeObject(pObject
);
1411 GDIOBJ_vUnlockObject(pObject
);
1419 NtGdiDeleteClientObj(
1422 /* We first need to get the real type from the handle */
1423 ULONG ulType
= GDI_HANDLE_GET_TYPE(hobj
);
1425 /* Check if it's really a CLIENTOBJ */
1426 if ((ulType
& GDI_HANDLE_BASETYPE_MASK
) != GDILoObjType_LO_CLIENTOBJ_TYPE
)
1428 /* FIXME: SetLastError? */
1432 return GreDeleteObject(hobj
);
1437 PGDI_HANDLE_TABLE GdiHandleTable
= NULL
;
1440 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
1442 if (ExpectedType
== GDI_OBJECT_TYPE_DONTCARE
)
1443 ExpectedType
= GDI_HANDLE_GET_TYPE(hObj
);
1444 return GDIOBJ_ReferenceObjectByHandle(hObj
, (ExpectedType
>> 16) & 0x1f);
1447 // This function is not safe to use with concurrent deleting attempts
1448 // That shouldn't be a problem, since we don't have any processes yet,
1449 // that could delete the handle
1452 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1457 /* Reference the handle entry */
1458 pentry
= ENTRY_ReferenceEntryByHandle(*phObj
, 0);
1461 DPRINT1("GDIOBJ: Requested handle 0x%p is not valid.\n", *phObj
);
1465 /* Update the entry */
1466 pentry
->FullUnique
|= GDI_ENTRY_STOCK_MASK
;
1467 pentry
->ObjectOwner
.ulObj
= 0;
1469 /* Get the pointer to the BASEOBJECT */
1470 pobj
= pentry
->einfo
.pobj
;
1472 /* Calculate the new handle */
1473 pobj
->hHmgr
= (HGDIOBJ
)((ULONG_PTR
)pobj
->hHmgr
| GDI_HANDLE_STOCK_MASK
);
1475 /* Return the new handle */
1476 *phObj
= pobj
->hHmgr
;
1478 /* Dereference the handle */
1479 GDIOBJ_vDereferenceObject(pobj
);
1485 GDIOBJ_AllocObjWithHandle(ULONG ObjectType
, ULONG cjSize
)
1489 UCHAR objt
= (ObjectType
>> 16) & 0xFF;
1491 if ((objt
== GDIObjType_DC_TYPE
&& cjSize
== sizeof(DC
)) ||
1492 (objt
== GDIObjType_PAL_TYPE
&& cjSize
== sizeof(PALETTE
)) ||
1493 (objt
== GDIObjType_RGN_TYPE
&& cjSize
== sizeof(REGION
)) ||
1494 (objt
== GDIObjType_SURF_TYPE
&& cjSize
== sizeof(SURFACE
)) ||
1495 (objt
== GDIObjType_PATH_TYPE
&& cjSize
== sizeof(PATH
)))
1497 fl
|= BASEFLAG_LOOKASIDE
;
1500 pobj
= GDIOBJ_AllocateObject(objt
, cjSize
, fl
);
1506 if (!GDIOBJ_hInsertObject(pobj
, GDI_OBJ_HMGR_POWNED
))
1508 GDIOBJ_vFreeObject(pobj
);
1515 GDI_MapHandleTable(PEPROCESS pProcess
)
1517 PVOID pvMappedView
= NULL
;
1519 LARGE_INTEGER liOffset
;
1520 SIZE_T cjViewSize
= sizeof(GDI_HANDLE_TABLE
);
1522 liOffset
.QuadPart
= 0;
1524 ASSERT(gpvGdiHdlTblSection
!= NULL
);
1525 ASSERT(pProcess
!= NULL
);
1527 Status
= MmMapViewOfSection(gpvGdiHdlTblSection
,
1538 if (!NT_SUCCESS(Status
))
1541 return pvMappedView
;
1545 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
1552 DPRINT("CleanupForProcess prochandle %p Pid %p\n",
1553 Process
, Process
->UniqueProcessId
);
1555 ASSERT(Process
== PsGetCurrentProcess());
1557 /* Get the current process Id */
1558 dwProcessId
= PtrToUlong(PsGetCurrentProcessId());
1560 /* Loop all handles in the handle table */
1561 for (ulIndex
= RESERVE_ENTRIES_COUNT
; ulIndex
< gulFirstUnused
; ulIndex
++)
1563 pentry
= &gpentHmgr
[ulIndex
];
1565 /* Check if the object is owned by the process */
1566 if (pentry
->ObjectOwner
.ulObj
== dwProcessId
)
1568 ASSERT(pentry
->einfo
.pobj
->cExclusiveLock
== 0);
1570 /* Reference the object and delete it */
1571 InterlockedIncrement((LONG
*)&gpaulRefCount
[ulIndex
]);
1572 GDIOBJ_vDeleteObject(pentry
->einfo
.pobj
);
1577 DbgGdiHTIntegrityCheck();
1580 ppi
= PsGetCurrentProcessWin32Process();
1581 DPRINT("Completed cleanup for process %p\n", Process
->UniqueProcessId
);
1582 if (ppi
->GDIHandleCount
!= 0)
1584 DPRINT1("Leaking %d handles!\n", ppi
->GDIHandleCount
);
1588 /* Loop all handles in the handle table */
1589 for (ulIndex
= RESERVE_ENTRIES_COUNT
; ulIndex
< gulFirstUnused
; ulIndex
++)
1591 pentry
= &gpentHmgr
[ulIndex
];
1593 /* Check if the object is owned by the process */
1594 if (pentry
->ObjectOwner
.ulObj
== dwProcessId
)
1596 DPRINT1("Leaking object. Index=%lx, type=0x%x, refcount=%lx\n",
1597 ulIndex
, pentry
->Objt
, gpaulRefCount
[ulIndex
]);
1598 DBG_DUMP_EVENT_LIST(&pentry
->einfo
.pobj
->slhLog
);
1599 //DBG_CLEANUP_EVENT_LIST(&pentry->einfo.pobj->slhLog);
1609 GetBrushAttrPool(VOID
)
1613 ppi
= PsGetCurrentProcessWin32Process();
1614 NT_ASSERT(ppi
!= NULL
);
1616 return ppi
->pPoolBrushAttr
;