[NTOSKRNL]
[reactos.git] / reactos / win32ss / gdi / ntgdi / gdiobj.c
1 /*
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
6 * PROGRAMMERS: Timo Kreuzer
7 */
8
9 /*
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.
31 *
32 */
33
34 /* INCLUDES ******************************************************************/
35
36 #include <win32k.h>
37 #define NDEBUG
38 #include <debug.h>
39
40 // Move to gdidbg.h
41 #if DBG
42 #define DBG_INCREASE_LOCK_COUNT(pti, hobj) \
43 if (pti) ((PTHREADINFO)pti)->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]++;
44 #define DBG_DECREASE_LOCK_COUNT(pti, hobj) \
45 if (pti) ((PTHREADINFO)pti)->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]--;
46 #define ASSERT_SHARED_OBJECT_TYPE(objt) \
47 ASSERT((objt) == GDIObjType_SURF_TYPE || \
48 (objt) == GDIObjType_PAL_TYPE || \
49 (objt) == GDIObjType_LFONT_TYPE || \
50 (objt) == GDIObjType_PATH_TYPE || \
51 (objt) == GDIObjType_BRUSH_TYPE)
52 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt) \
53 ASSERT((objt) == GDIObjType_DC_TYPE || \
54 (objt) == GDIObjType_RGN_TYPE || \
55 (objt) == GDIObjType_LFONT_TYPE)
56 #else
57 #define DBG_INCREASE_LOCK_COUNT(ppi, hobj)
58 #define DBG_DECREASE_LOCK_COUNT(x, y)
59 #define ASSERT_SHARED_OBJECT_TYPE(objt)
60 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt)
61 #endif
62
63 #if defined(_M_IX86) || defined(_M_AMD64)
64 #define InterlockedOr16 _InterlockedOr16
65 #endif
66
67 #define GDIOBJ_POOL_TAG(type) ('00hG' + (((type) & 0x1f) << 24))
68
69 enum
70 {
71 REF_MASK_REUSE = 0xff000000,
72 REF_INC_REUSE = 0x01000000,
73 REF_MASK_VALID = 0x00800000,
74 REF_MASK_COUNT = 0x007fffff,
75 REF_MASK_INUSE = 0x00ffffff,
76 };
77
78 /* GLOBALS *******************************************************************/
79
80 /* Per session handle table globals */
81 static PVOID gpvGdiHdlTblSection = NULL;
82 static PENTRY gpentHmgr;
83 static PULONG gpaulRefCount;
84 ULONG gulFirstFree;
85 ULONG gulFirstUnused;
86 static PPAGED_LOOKASIDE_LIST gpaLookasideList;
87
88 static BOOL NTAPI GDIOBJ_Cleanup(PVOID ObjectBody);
89
90 static const
91 GDICLEANUPPROC
92 apfnCleanup[] =
93 {
94 NULL, /* 00 GDIObjType_DEF_TYPE */
95 DC_Cleanup, /* 01 GDIObjType_DC_TYPE */
96 NULL, /* 02 GDIObjType_UNUSED1_TYPE */
97 NULL, /* 03 GDIObjType_UNUSED2_TYPE */
98 REGION_Cleanup, /* 04 GDIObjType_RGN_TYPE */
99 SURFACE_Cleanup, /* 05 GDIObjType_SURF_TYPE */
100 GDIOBJ_Cleanup, /* 06 GDIObjType_CLIENTOBJ_TYPE */
101 GDIOBJ_Cleanup, /* 07 GDIObjType_PATH_TYPE */
102 PALETTE_Cleanup, /* 08 GDIObjType_PAL_TYPE */
103 GDIOBJ_Cleanup, /* 09 GDIObjType_ICMLCS_TYPE */
104 GDIOBJ_Cleanup, /* 0a GDIObjType_LFONT_TYPE */
105 NULL, /* 0b GDIObjType_RFONT_TYPE, unused */
106 NULL, /* 0c GDIObjType_PFE_TYPE, unused */
107 NULL, /* 0d GDIObjType_PFT_TYPE, unused */
108 GDIOBJ_Cleanup, /* 0e GDIObjType_ICMCXF_TYPE */
109 NULL, /* 0f GDIObjType_SPRITE_TYPE, unused */
110 BRUSH_Cleanup, /* 10 GDIObjType_BRUSH_TYPE, BRUSH, PEN, EXTPEN */
111 NULL, /* 11 GDIObjType_UMPD_TYPE, unused */
112 NULL, /* 12 GDIObjType_UNUSED4_TYPE */
113 NULL, /* 13 GDIObjType_SPACE_TYPE, unused */
114 NULL, /* 14 GDIObjType_UNUSED5_TYPE */
115 NULL, /* 15 GDIObjType_META_TYPE, unused */
116 NULL, /* 16 GDIObjType_EFSTATE_TYPE, unused */
117 NULL, /* 17 GDIObjType_BMFD_TYPE, unused */
118 NULL, /* 18 GDIObjType_VTFD_TYPE, unused */
119 NULL, /* 19 GDIObjType_TTFD_TYPE, unused */
120 NULL, /* 1a GDIObjType_RC_TYPE, unused */
121 NULL, /* 1b GDIObjType_TEMP_TYPE, unused */
122 DRIVEROBJ_Cleanup,/* 1c GDIObjType_DRVOBJ_TYPE */
123 NULL, /* 1d GDIObjType_DCIOBJ_TYPE, unused */
124 NULL, /* 1e GDIObjType_SPOOL_TYPE, unused */
125 NULL, /* 1f reserved entry */
126 };
127
128 /* INTERNAL FUNCTIONS ********************************************************/
129
130 static
131 BOOL NTAPI
132 GDIOBJ_Cleanup(PVOID ObjectBody)
133 {
134 return TRUE;
135 }
136
137 static
138 VOID
139 InitLookasideList(UCHAR objt, ULONG cjSize)
140 {
141 ExInitializePagedLookasideList(&gpaLookasideList[objt],
142 NULL,
143 NULL,
144 0,
145 cjSize,
146 GDITAG_HMGR_LOOKASIDE_START + (objt << 24),
147 0);
148 }
149
150 INIT_FUNCTION
151 NTSTATUS
152 NTAPI
153 InitGdiHandleTable(void)
154 {
155 NTSTATUS status;
156 LARGE_INTEGER liSize;
157 PVOID pvSection;
158 SIZE_T cjViewSize = 0;
159
160 /* Create a section for the shared handle table */
161 liSize.QuadPart = sizeof(GDI_HANDLE_TABLE); // GDI_HANDLE_COUNT * sizeof(ENTRY);
162 status = MmCreateSection(&gpvGdiHdlTblSection,
163 SECTION_ALL_ACCESS,
164 NULL,
165 &liSize,
166 PAGE_READWRITE,
167 SEC_COMMIT | 0x1,
168 NULL,
169 NULL);
170 if (!NT_SUCCESS(status))
171 {
172 DPRINT1("INITGDI: Could not allocate a GDI handle table.\n");
173 return status;
174 }
175
176 /* Map the section in session space */
177 status = MmMapViewInSessionSpace(gpvGdiHdlTblSection,
178 (PVOID*)&gpentHmgr,
179 &cjViewSize);
180 if (!NT_SUCCESS(status))
181 {
182 DPRINT1("INITGDI: Failed to map handle table section\n");
183 ObDereferenceObject(gpvGdiHdlTblSection);
184 return status;
185 }
186
187 /* Allocate memory for the reference counter table */
188 gpaulRefCount = EngAllocSectionMem(&pvSection,
189 FL_ZERO_MEMORY,
190 GDI_HANDLE_COUNT * sizeof(ULONG),
191 'frHG');
192 if (!gpaulRefCount)
193 {
194 DPRINT1("INITGDI: Failed to allocate reference table.\n");
195 ObDereferenceObject(gpvGdiHdlTblSection);
196 return STATUS_INSUFFICIENT_RESOURCES;
197 }
198
199 gulFirstFree = 0;
200 gulFirstUnused = RESERVE_ENTRIES_COUNT;
201
202 GdiHandleTable = (PVOID)gpentHmgr;
203
204 /* Initialize the lookaside lists */
205 gpaLookasideList = ExAllocatePoolWithTag(NonPagedPool,
206 GDIObjTypeTotal * sizeof(PAGED_LOOKASIDE_LIST),
207 TAG_GDIHNDTBLE);
208 if(!gpaLookasideList)
209 return STATUS_NO_MEMORY;
210
211 InitLookasideList(GDIObjType_DC_TYPE, sizeof(DC));
212 InitLookasideList(GDIObjType_RGN_TYPE, sizeof(REGION));
213 InitLookasideList(GDIObjType_SURF_TYPE, sizeof(SURFACE));
214 InitLookasideList(GDIObjType_CLIENTOBJ_TYPE, sizeof(CLIENTOBJ));
215 InitLookasideList(GDIObjType_PATH_TYPE, sizeof(PATH));
216 InitLookasideList(GDIObjType_PAL_TYPE, sizeof(PALETTE));
217 InitLookasideList(GDIObjType_ICMLCS_TYPE, sizeof(COLORSPACE));
218 InitLookasideList(GDIObjType_LFONT_TYPE, sizeof(TEXTOBJ));
219 InitLookasideList(GDIObjType_BRUSH_TYPE, sizeof(BRUSH));
220
221 return STATUS_SUCCESS;
222 }
223
224 FORCEINLINE
225 VOID
226 IncrementGdiHandleCount(void)
227 {
228 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
229 if (ppi) InterlockedIncrement((LONG*)&ppi->GDIHandleCount);
230 }
231
232 FORCEINLINE
233 VOID
234 DecrementGdiHandleCount(void)
235 {
236 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
237 if (ppi) InterlockedDecrement((LONG*)&ppi->GDIHandleCount);
238 }
239
240 static
241 PENTRY
242 ENTRY_pentPopFreeEntry(VOID)
243 {
244 ULONG iFirst, iNext, iPrev;
245 PENTRY pentFree;
246
247 DPRINT("Enter InterLockedPopFreeEntry\n");
248
249 do
250 {
251 /* Get the index and sequence number of the first free entry */
252 iFirst = gulFirstFree;
253
254 /* Check if we have a free entry */
255 if (!(iFirst & GDI_HANDLE_INDEX_MASK))
256 {
257 /* Increment FirstUnused and get the new index */
258 iFirst = InterlockedIncrement((LONG*)&gulFirstUnused) - 1;
259
260 /* Check if we have unused entries left */
261 if (iFirst >= GDI_HANDLE_COUNT)
262 {
263 DPRINT1("No more GDI handles left!\n");
264 return 0;
265 }
266
267 /* Return the old entry */
268 return &gpentHmgr[iFirst];
269 }
270
271 /* Get a pointer to the first free entry */
272 pentFree = &gpentHmgr[iFirst & GDI_HANDLE_INDEX_MASK];
273
274 /* Create a new value with an increased sequence number */
275 iNext = (USHORT)(ULONG_PTR)pentFree->einfo.pobj;
276 iNext |= (iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000;
277
278 /* Try to exchange the FirstFree value */
279 iPrev = InterlockedCompareExchange((LONG*)&gulFirstFree,
280 iNext,
281 iFirst);
282 }
283 while (iPrev != iFirst);
284
285 /* Sanity check: is entry really free? */
286 ASSERT(((ULONG_PTR)pentFree->einfo.pobj & ~GDI_HANDLE_INDEX_MASK) == 0);
287
288 return pentFree;
289 }
290
291 /* Pushes an entry of the handle table to the free list,
292 The entry must not have any references left */
293 static
294 VOID
295 ENTRY_vPushFreeEntry(PENTRY pentFree)
296 {
297 ULONG iToFree, iFirst, iPrev, idxToFree;
298
299 DPRINT("Enter ENTRY_vPushFreeEntry\n");
300
301 idxToFree = pentFree - gpentHmgr;
302 ASSERT((gpaulRefCount[idxToFree] & REF_MASK_INUSE) == 0);
303
304 /* Initialize entry */
305 pentFree->Objt = GDIObjType_DEF_TYPE;
306 pentFree->ObjectOwner.ulObj = 0;
307 pentFree->pUser = NULL;
308
309 /* Increase reuse counter in entry and reference counter */
310 InterlockedExchangeAdd((LONG*)&gpaulRefCount[idxToFree], REF_INC_REUSE);
311 pentFree->FullUnique += 0x0100;
312
313 do
314 {
315 /* Get the current first free index and sequence number */
316 iFirst = gulFirstFree;
317
318 /* Set the einfo.pobj member to the index of the first free entry */
319 pentFree->einfo.pobj = UlongToPtr(iFirst & GDI_HANDLE_INDEX_MASK);
320
321 /* Combine new index and increased sequence number in iToFree */
322 iToFree = idxToFree | ((iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000);
323
324 /* Try to atomically update the first free entry */
325 iPrev = InterlockedCompareExchange((LONG*)&gulFirstFree,
326 iToFree,
327 iFirst);
328 }
329 while (iPrev != iFirst);
330 }
331
332 static
333 PENTRY
334 ENTRY_ReferenceEntryByHandle(HGDIOBJ hobj, FLONG fl)
335 {
336 ULONG ulIndex, cNewRefs, cOldRefs;
337 PENTRY pentry;
338
339 /* Get the handle index and check if its too big */
340 ulIndex = GDI_HANDLE_GET_INDEX(hobj);
341 if (ulIndex >= GDI_HANDLE_COUNT) return NULL;
342
343 /* Get pointer to the entry */
344 pentry = &gpentHmgr[ulIndex];
345
346 /* Get the current reference count */
347 cOldRefs = gpaulRefCount[ulIndex];
348
349 do
350 {
351 /* Check if the slot is deleted */
352 if ((cOldRefs & REF_MASK_VALID) == 0)
353 {
354 DPRINT("GDIOBJ: Slot is not valid: 0x%lx, hobh=%p\n", cOldRefs, hobj);
355 return NULL;
356 }
357
358 /* Check if the unique value matches */
359 if (pentry->FullUnique != (USHORT)((ULONG_PTR)hobj >> 16))
360 {
361 DPRINT("GDIOBJ: Wrong unique value. Handle: 0x%4x, entry: 0x%4x\n",
362 (USHORT)((ULONG_PTR)hobj >> 16), pentry->FullUnique);
363 return NULL;
364 }
365
366 /* Check if the object owner is this process or public */
367 if (!(fl & GDIOBJFLAG_IGNOREPID) &&
368 pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC &&
369 pentry->ObjectOwner.ulObj != PtrToUlong(PsGetCurrentProcessId()))
370 {
371 DPRINT("GDIOBJ: Cannot reference foreign handle %p, pentry=%p:%lx.\n",
372 hobj, pentry, pentry->ObjectOwner.ulObj);
373 return NULL;
374 }
375
376 /* Try to atomically increment the reference count */
377 cNewRefs = cOldRefs + 1;
378 cOldRefs = InterlockedCompareExchange((PLONG)&gpaulRefCount[ulIndex],
379 cNewRefs,
380 cOldRefs);
381 }
382 while (cNewRefs != cOldRefs + 1);
383
384 /* Integrity checks */
385 ASSERT((pentry->FullUnique & 0x1f) == pentry->Objt);
386 ASSERT(pentry->einfo.pobj && pentry->einfo.pobj->hHmgr == hobj);
387
388 return pentry;
389 }
390
391 static
392 HGDIOBJ
393 ENTRY_hInsertObject(PENTRY pentry, POBJ pobj, UCHAR objt, ULONG ulOwner)
394 {
395 ULONG ulIndex;
396
397 /* Calculate the handle index */
398 ulIndex = pentry - gpentHmgr;
399
400 /* Update the fields in the ENTRY */
401 pentry->einfo.pobj = pobj;
402 pentry->Objt = objt & 0x1f;
403 pentry->FullUnique = (pentry->FullUnique & 0xff00) | objt;
404 pentry->ObjectOwner.ulObj = ulOwner;
405
406 /* Make the handle valid with 1 reference */
407 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_INUSE) == 0);
408 InterlockedOr((LONG*)&gpaulRefCount[ulIndex], REF_MASK_VALID | 1);
409
410 /* Return the handle */
411 return (HGDIOBJ)(((ULONG_PTR)pentry->FullUnique << 16) | ulIndex);
412 }
413
414 POBJ
415 NTAPI
416 GDIOBJ_AllocateObject(UCHAR objt, ULONG cjSize, FLONG fl)
417 {
418 POBJ pobj;
419
420 if (fl & BASEFLAG_LOOKASIDE)
421 {
422 /* Allocate the object from a lookaside list */
423 pobj = ExAllocateFromPagedLookasideList(&gpaLookasideList[objt & 0x1f]);
424 }
425 else
426 {
427 /* Allocate the object from paged pool */
428 pobj = ExAllocatePoolWithTag(PagedPool, cjSize, GDIOBJ_POOL_TAG(objt));
429 }
430
431 if (!pobj) return NULL;
432
433 /* Initialize the object */
434 RtlZeroMemory(pobj, cjSize);
435 pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)objt << 16);
436 pobj->cExclusiveLock = 0;
437 pobj->ulShareCount = 1;
438 pobj->BaseFlags = fl & 0xffff;
439 DBG_INITLOG(&pobj->slhLog);
440 DBG_LOGEVENT(&pobj->slhLog, EVENT_ALLOCATE, 0);
441
442 return pobj;
443 }
444
445 VOID
446 NTAPI
447 GDIOBJ_vFreeObject(POBJ pobj)
448 {
449 UCHAR objt;
450
451 DBG_CLEANUP_EVENT_LIST(&pobj->slhLog);
452
453 /* Get the object type */
454 objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0x1f;
455
456 /* Call the cleanup procedure */
457 ASSERT(apfnCleanup[objt]);
458 apfnCleanup[objt](pobj);
459
460 /* Check if the object is allocated from a lookaside list */
461 if (pobj->BaseFlags & BASEFLAG_LOOKASIDE)
462 {
463 ExFreeToPagedLookasideList(&gpaLookasideList[objt], pobj);
464 }
465 else
466 {
467 ExFreePoolWithTag(pobj, GDIOBJ_POOL_TAG(objt));
468 }
469 }
470
471 VOID
472 NTAPI
473 GDIOBJ_vDereferenceObject(POBJ pobj)
474 {
475 ULONG cRefs, ulIndex;
476
477 /* Calculate the index */
478 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
479
480 /* Check if the object has a handle */
481 if (ulIndex)
482 {
483 /* Decrement reference count */
484 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
485 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]);
486 DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs);
487
488 /* Check if we reached 0 and handle bit is not set */
489 if ((cRefs & REF_MASK_INUSE) == 0)
490 {
491 /* Make sure it's ok to delete the object */
492 ASSERT(pobj->BaseFlags & BASEFLAG_READY_TO_DIE);
493
494 /* Check if the handle was process owned */
495 if (gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC &&
496 gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_NONE)
497 {
498 /* Decrement the process handle count */
499 ASSERT(gpentHmgr[ulIndex].ObjectOwner.ulObj ==
500 HandleToUlong(PsGetCurrentProcessId()));
501 DecrementGdiHandleCount();
502 }
503
504 /* Push entry to the free list */
505 ENTRY_vPushFreeEntry(&gpentHmgr[ulIndex]);
506
507 /* Free the object */
508 GDIOBJ_vFreeObject(pobj);
509 }
510 }
511 else
512 {
513 /* Decrement the objects reference count */
514 ASSERT(pobj->ulShareCount > 0);
515 cRefs = InterlockedDecrement((LONG*)&pobj->ulShareCount);
516 DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs);
517
518 /* Check if we reached 0 */
519 if (cRefs == 0)
520 {
521 /* Free the object */
522 GDIOBJ_vFreeObject(pobj);
523 }
524 }
525 }
526
527 POBJ
528 NTAPI
529 GDIOBJ_ReferenceObjectByHandle(
530 HGDIOBJ hobj,
531 UCHAR objt)
532 {
533 PENTRY pentry;
534 POBJ pobj;
535
536 /* Check if the handle type matches */
537 ASSERT_SHARED_OBJECT_TYPE(objt);
538 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt)
539 {
540 DPRINT("GDIOBJ: Wrong type. handle=%p, type=%x\n", hobj, objt);
541 return NULL;
542 }
543
544 /* Reference the handle entry */
545 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
546 if (!pentry)
547 {
548 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj);
549 return NULL;
550 }
551
552 /* Get the pointer to the BASEOBJECT */
553 pobj = pentry->einfo.pobj;
554
555 /* Check if the object is exclusively locked */
556 if (pobj->cExclusiveLock != 0)
557 {
558 DPRINT1("GDIOBJ: Cannot reference oject %p with exclusive lock.\n", hobj);
559 GDIOBJ_vDereferenceObject(pobj);
560 DBG_DUMP_EVENT_LIST(&pobj->slhLog);
561 return NULL;
562 }
563
564 DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, gpaulRefCount[pentry - gpentHmgr]);
565
566 /* All is well, return the object */
567 return pobj;
568 }
569
570 VOID
571 NTAPI
572 GDIOBJ_vReferenceObjectByPointer(POBJ pobj)
573 {
574 ULONG cRefs;
575
576 /* Check if the object has a handle */
577 if (GDI_HANDLE_GET_INDEX(pobj->hHmgr))
578 {
579 /* Increase the handle's reference count */
580 ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
581 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
582 cRefs = InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]);
583 }
584 else
585 {
586 /* Increase the object's reference count */
587 cRefs = InterlockedIncrement((LONG*)&pobj->ulShareCount);
588 }
589
590 DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, cRefs);
591 }
592
593 PGDIOBJ
594 NTAPI
595 GDIOBJ_LockObject(
596 HGDIOBJ hobj,
597 UCHAR objt)
598 {
599 PENTRY pentry;
600 POBJ pobj;
601 DWORD dwThreadId;
602
603 /* Check if the handle type matches */
604 ASSERT_EXCLUSIVE_OBJECT_TYPE(objt);
605 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt)
606 {
607 DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj, objt);
608 return NULL;
609 }
610
611 /* Reference the handle entry */
612 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
613 if (!pentry)
614 {
615 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj);
616 return NULL;
617 }
618
619 /* Get the pointer to the BASEOBJECT */
620 pobj = pentry->einfo.pobj;
621
622 /* Check if we already own the lock */
623 dwThreadId = PtrToUlong(PsGetCurrentThreadId());
624 if (pobj->dwThreadId != dwThreadId)
625 {
626 /* Disable APCs and acquire the push lock */
627 KeEnterCriticalRegion();
628 ExAcquirePushLockExclusive(&pobj->pushlock);
629
630 /* Set us as lock owner */
631 ASSERT(pobj->dwThreadId == 0);
632 pobj->dwThreadId = dwThreadId;
633 }
634
635 /* Increase lock count */
636 pobj->cExclusiveLock++;
637 DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), hobj);
638 DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0);
639
640 /* Return the object */
641 return pobj;
642 }
643
644 VOID
645 NTAPI
646 GDIOBJ_vUnlockObject(POBJ pobj)
647 {
648 ULONG cRefs, ulIndex;
649 ASSERT(pobj->cExclusiveLock > 0);
650
651 /* Decrease lock count */
652 pobj->cExclusiveLock--;
653 DBG_DECREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
654 DBG_LOGEVENT(&pobj->slhLog, EVENT_UNLOCK, 0);
655
656 /* Check if this was the last lock */
657 if (pobj->cExclusiveLock == 0)
658 {
659 /* Reset lock owner */
660 pobj->dwThreadId = 0;
661
662 /* Release the pushlock and reenable APCs */
663 ExReleasePushLockExclusive(&pobj->pushlock);
664 KeLeaveCriticalRegion();
665 }
666
667 /* Calculate the index */
668 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
669
670 /* Decrement reference count */
671 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
672 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]);
673 ASSERT(cRefs & REF_MASK_VALID);
674 }
675
676 HGDIOBJ
677 NTAPI
678 GDIOBJ_hInsertObject(
679 POBJ pobj,
680 ULONG ulOwner)
681 {
682 PENTRY pentry;
683 UCHAR objt;
684
685 /* Must have no handle and only one reference */
686 ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr) == 0);
687 ASSERT(pobj->cExclusiveLock == 0);
688 ASSERT(pobj->ulShareCount == 1);
689
690 /* Get a free handle entry */
691 pentry = ENTRY_pentPopFreeEntry();
692 if (!pentry)
693 {
694 DPRINT1("GDIOBJ: Could not get a free entry.\n");
695 return NULL;
696 }
697
698 /* Make the object exclusively locked */
699 ExInitializePushLock(&pobj->pushlock);
700 KeEnterCriticalRegion();
701 ExAcquirePushLockExclusive(&pobj->pushlock);
702 pobj->cExclusiveLock = 1;
703 pobj->dwThreadId = PtrToUlong(PsGetCurrentThreadId());
704 DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
705
706 /* Get object type from the hHmgr field */
707 objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0xff;
708 ASSERT(objt != GDIObjType_DEF_TYPE);
709
710 /* Check if current process is requested owner */
711 if (ulOwner == GDI_OBJ_HMGR_POWNED)
712 {
713 /* Increment the process handle count */
714 IncrementGdiHandleCount();
715
716 /* Use Process id */
717 ulOwner = HandleToUlong(PsGetCurrentProcessId());
718 }
719
720 /* Insert the object into the handle table */
721 pobj->hHmgr = ENTRY_hInsertObject(pentry, pobj, objt, ulOwner);
722
723 /* Return the handle */
724 DPRINT("GDIOBJ: Created handle: %p\n", pobj->hHmgr);
725 DBG_LOGEVENT(&pobj->slhLog, EVENT_CREATE_HANDLE, 0);
726 return pobj->hHmgr;
727 }
728
729 VOID
730 NTAPI
731 GDIOBJ_vSetObjectOwner(
732 POBJ pobj,
733 ULONG ulOwner)
734 {
735 PENTRY pentry;
736
737 /* This is a ugly HACK, needed to fix IntGdiSetDCOwnerEx */
738 if (GDI_HANDLE_IS_STOCKOBJ(pobj->hHmgr))
739 {
740 DPRINT("Trying to set ownership of stock object %p to %lx\n", pobj->hHmgr, ulOwner);
741 return;
742 }
743
744 /* Get the handle entry */
745 ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr));
746 pentry = &gpentHmgr[GDI_HANDLE_GET_INDEX(pobj->hHmgr)];
747
748 /* Is the current process requested? */
749 if (ulOwner == GDI_OBJ_HMGR_POWNED)
750 {
751 /* Use process id */
752 ulOwner = HandleToUlong(PsGetCurrentProcessId());
753 if (pentry->ObjectOwner.ulObj != ulOwner)
754 {
755 IncrementGdiHandleCount();
756 }
757 }
758
759 // HACK
760 if (ulOwner == GDI_OBJ_HMGR_NONE)
761 ulOwner = GDI_OBJ_HMGR_PUBLIC;
762
763 if (ulOwner == GDI_OBJ_HMGR_PUBLIC ||
764 ulOwner == GDI_OBJ_HMGR_NONE)
765 {
766 /* Make sure we don't leak user mode memory */
767 ASSERT(pentry->pUser == NULL);
768 if (pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC &&
769 pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_NONE)
770 {
771 DecrementGdiHandleCount();
772 }
773 }
774
775 /* Set new owner */
776 pentry->ObjectOwner.ulObj = ulOwner;
777 DBG_LOGEVENT(&pobj->slhLog, EVENT_SET_OWNER, 0);
778 }
779
780 /* Locks 2 or 3 objects at a time */
781 BOOL
782 NTAPI
783 GDIOBJ_bLockMultipleObjects(
784 IN ULONG ulCount,
785 IN HGDIOBJ* ahObj,
786 OUT PGDIOBJ* apObj,
787 IN UCHAR objt)
788 {
789 UINT auiIndices[3] = {0, 1, 2};
790 UINT i, j, tmp;
791
792 ASSERT(ulCount <= 3);
793
794 /* Sort the handles */
795 for (i = 0; i < ulCount - 1; i++)
796 {
797 for (j = i + 1; j < ulCount; j++)
798 {
799 if ((ULONG_PTR)ahObj[auiIndices[i]] <
800 (ULONG_PTR)ahObj[auiIndices[j]])
801 {
802 tmp = auiIndices[i];
803 auiIndices[i] = auiIndices[j];
804 auiIndices[j] = tmp;
805 }
806 }
807 }
808
809 /* Lock the objects in safe order */
810 for (i = 0; i < ulCount; i++)
811 {
812 /* Skip NULL handles */
813 if (ahObj[auiIndices[i]] == NULL)
814 {
815 apObj[auiIndices[i]] = NULL;
816 continue;
817 }
818
819 /* Lock the object */
820 apObj[auiIndices[i]] = GDIOBJ_LockObject(ahObj[auiIndices[i]], objt);
821
822 /* Check for failure */
823 if (apObj[auiIndices[i]] == NULL)
824 {
825 /* Cleanup */
826 while (i--)
827 {
828 if (apObj[auiIndices[i]])
829 GDIOBJ_vUnlockObject(apObj[auiIndices[i]]);
830 }
831 return FALSE;
832 }
833 }
834
835 return TRUE;
836 }
837
838 PVOID
839 NTAPI
840 GDIOBJ_pvGetObjectAttr(POBJ pobj)
841 {
842 ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
843 return gpentHmgr[ulIndex].pUser;
844 }
845
846 VOID
847 NTAPI
848 GDIOBJ_vSetObjectAttr(POBJ pobj, PVOID pvObjAttr)
849 {
850 ULONG ulIndex;
851
852 ASSERT(pobj->hHmgr);
853
854 /* Get the handle index */
855 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
856
857 /* Set pointer to the usermode attribute */
858 gpentHmgr[ulIndex].pUser = pvObjAttr;
859 }
860
861 VOID
862 NTAPI
863 GDIOBJ_vDeleteObject(POBJ pobj)
864 {
865 ULONG ulIndex;
866
867 /* Set the object's delete flag */
868 InterlockedOr16((SHORT*)&pobj->BaseFlags, BASEFLAG_READY_TO_DIE);
869 DBG_LOGEVENT(&pobj->slhLog, EVENT_DELETE, 0);
870
871 /* Get the handle index */
872 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
873 if (ulIndex)
874 {
875 /* Reset the handle valid bit */
876 InterlockedAnd((LONG*)&gpaulRefCount[ulIndex], ~REF_MASK_VALID);
877
878 /* Check if the object is exclusively locked */
879 if (pobj->cExclusiveLock != 0)
880 {
881 /* Reset lock owner and lock count */
882 pobj->dwThreadId = 0;
883 pobj->cExclusiveLock = 0;
884
885 /* Release the pushlock and reenable APCs */
886 ExReleasePushLockExclusive(&pobj->pushlock);
887 KeLeaveCriticalRegion();
888 DBG_DECREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
889 }
890 }
891
892 /* Dereference the object (will take care of deletion) */
893 GDIOBJ_vDereferenceObject(pobj);
894 }
895
896 BOOL
897 NTAPI
898 GreIsHandleValid(HGDIOBJ hobj)
899 {
900 PENTRY pentry;
901
902 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
903 if (!pentry) return FALSE;
904 GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
905 return TRUE;
906 }
907
908 BOOL
909 NTAPI
910 GreDeleteObject(HGDIOBJ hobj)
911 {
912 PENTRY pentry;
913
914 /* Check for stock objects */
915 if (GDI_HANDLE_IS_STOCKOBJ(hobj))
916 {
917 DPRINT1("GreDeleteObject: Cannot delete stock object %p.\n", hobj);
918 return FALSE;
919 }
920
921 /* Reference the handle entry */
922 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
923 if (!pentry)
924 {
925 DPRINT1("GreDeleteObject: Trying to delete invalid object %p\n", hobj);
926 return FALSE;
927 }
928
929 /* Check for public owner */
930 if (pentry->ObjectOwner.ulObj == GDI_OBJ_HMGR_PUBLIC)
931 {
932 DPRINT1("GreDeleteObject: Trying to delete global object %p\n", hobj);
933 GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
934 return FALSE;
935 }
936
937 /* Delete the object */
938 GDIOBJ_vDeleteObject(pentry->einfo.pobj);
939 return TRUE;
940 }
941
942 ULONG
943 NTAPI
944 GreGetObjectOwner(HGDIOBJ hobj)
945 {
946 ULONG ulIndex, ulOwner;
947
948 /* Get the handle index */
949 ulIndex = GDI_HANDLE_GET_INDEX(hobj);
950
951 /* Check if the handle is valid */
952 if (ulIndex >= GDI_HANDLE_COUNT ||
953 gpentHmgr[ulIndex].Objt == GDIObjType_DEF_TYPE ||
954 ((ULONG_PTR)hobj >> 16) != gpentHmgr[ulIndex].FullUnique)
955 {
956 DPRINT1("GreGetObjectOwner: invalid handle 0x%p.\n", hobj);
957 return GDI_OBJ_HMGR_RESTRICTED;
958 }
959
960 /* Get the object owner */
961 ulOwner = gpentHmgr[ulIndex].ObjectOwner.ulObj;
962
963 if (ulOwner == HandleToUlong(PsGetCurrentProcessId()))
964 return GDI_OBJ_HMGR_POWNED;
965
966 if (ulOwner == GDI_OBJ_HMGR_PUBLIC)
967 return GDI_OBJ_HMGR_PUBLIC;
968
969 return GDI_OBJ_HMGR_RESTRICTED;
970 }
971
972 BOOL
973 NTAPI
974 GreSetObjectOwner(
975 HGDIOBJ hobj,
976 ULONG ulOwner)
977 {
978 PENTRY pentry;
979
980 /* Check for stock objects */
981 if (GDI_HANDLE_IS_STOCKOBJ(hobj))
982 {
983 DPRINT("GreSetObjectOwner: Got stock object %p\n", hobj);
984 return FALSE;
985 }
986
987 /* Reference the handle entry */
988 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
989 if (!pentry)
990 {
991 DPRINT("GreSetObjectOwner: Invalid handle 0x%p.\n", hobj);
992 return FALSE;
993 }
994
995 /* Call internal function */
996 GDIOBJ_vSetObjectOwner(pentry->einfo.pobj, ulOwner);
997
998 /* Dereference the object */
999 GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
1000
1001 return TRUE;
1002 }
1003
1004 INT
1005 NTAPI
1006 GreGetObject(
1007 IN HGDIOBJ hobj,
1008 IN INT cbCount,
1009 IN PVOID pvBuffer)
1010 {
1011 PVOID pvObj;
1012 UCHAR objt;
1013 INT iResult = 0;
1014
1015 /* Verify object type */
1016 objt = ((ULONG_PTR)hobj >> 16) & 0x1f;
1017 if (objt != GDIObjType_BRUSH_TYPE &&
1018 objt != GDIObjType_SURF_TYPE &&
1019 objt != GDIObjType_LFONT_TYPE &&
1020 objt != GDIObjType_PAL_TYPE)
1021 {
1022 DPRINT1("GreGetObject: Invalid object type\n");
1023 return 0;
1024 }
1025
1026 pvObj = GDIOBJ_ReferenceObjectByHandle(hobj, objt);
1027 if (!pvObj)
1028 {
1029 DPRINT("GreGetObject: Could not lock object\n");
1030 return 0;
1031 }
1032
1033 switch (GDI_HANDLE_GET_TYPE(hobj))
1034 {
1035 case GDILoObjType_LO_PEN_TYPE:
1036 case GDILoObjType_LO_EXTPEN_TYPE:
1037 iResult = PEN_GetObject(pvObj, cbCount, pvBuffer);
1038 break;
1039
1040 case GDILoObjType_LO_BRUSH_TYPE:
1041 iResult = BRUSH_GetObject(pvObj, cbCount, pvBuffer);
1042 break;
1043
1044 case GDILoObjType_LO_BITMAP_TYPE:
1045 iResult = BITMAP_GetObject(pvObj, cbCount, pvBuffer);
1046 break;
1047
1048 case GDILoObjType_LO_FONT_TYPE:
1049 iResult = FontGetObject(pvObj, cbCount, pvBuffer);
1050 break;
1051
1052 case GDILoObjType_LO_PALETTE_TYPE:
1053 iResult = PALETTE_GetObject(pvObj, cbCount, pvBuffer);
1054 break;
1055
1056 default:
1057 DPRINT1("GDI object type of 0x%p not implemented\n", hobj);
1058 break;
1059 }
1060
1061 GDIOBJ_vDereferenceObject(pvObj);
1062 return iResult;
1063 }
1064
1065 W32KAPI
1066 INT
1067 APIENTRY
1068 NtGdiExtGetObjectW(
1069 IN HANDLE hobj,
1070 IN INT cbCount,
1071 OUT LPVOID lpBuffer)
1072 {
1073 INT iRetCount = 0;
1074 INT cbCopyCount;
1075 union
1076 {
1077 BITMAP bitmap;
1078 DIBSECTION dibsection;
1079 LOGPEN logpen;
1080 LOGBRUSH logbrush;
1081 LOGFONTW logfontw;
1082 EXTLOGFONTW extlogfontw;
1083 ENUMLOGFONTEXDVW enumlogfontexdvw;
1084 } object;
1085
1086 /* Normalize to the largest supported object size */
1087 cbCount = min((UINT)cbCount, sizeof(object));
1088
1089 /* Now do the actual call */
1090 iRetCount = GreGetObject(hobj, cbCount, lpBuffer ? &object : NULL);
1091 cbCopyCount = min((UINT)cbCount, (UINT)iRetCount);
1092
1093 /* Make sure we have a buffer and a copy size */
1094 if ((cbCopyCount) && (lpBuffer))
1095 {
1096 /* Enter SEH for buffer transfer */
1097 _SEH2_TRY
1098 {
1099 /* Probe the buffer and copy it */
1100 ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD));
1101 RtlCopyMemory(lpBuffer, &object, cbCopyCount);
1102 }
1103 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1104 {
1105 /* Clear the return value.
1106 * Do *NOT* set last error here! */
1107 iRetCount = 0;
1108 }
1109 _SEH2_END;
1110 }
1111
1112 /* Return the count */
1113 return iRetCount;
1114 }
1115
1116 W32KAPI
1117 HANDLE
1118 APIENTRY
1119 NtGdiCreateClientObj(
1120 IN ULONG ulType)
1121 {
1122 POBJ pObject;
1123 HANDLE handle;
1124
1125 /* Allocate a new object */
1126 pObject = GDIOBJ_AllocateObject(GDIObjType_CLIENTOBJ_TYPE,
1127 sizeof(CLIENTOBJ),
1128 BASEFLAG_LOOKASIDE);
1129 if (!pObject)
1130 {
1131 DPRINT1("NtGdiCreateClientObj: Could not allocate a clientobj.\n");
1132 return NULL;
1133 }
1134
1135 /* Mask out everything that would change the type in a wrong manner */
1136 ulType &= (GDI_HANDLE_TYPE_MASK & ~GDI_HANDLE_BASETYPE_MASK);
1137
1138 /* Set the real object type */
1139 pObject->hHmgr = UlongToHandle(ulType | GDILoObjType_LO_CLIENTOBJ_TYPE);
1140
1141 /* Create a handle */
1142 handle = GDIOBJ_hInsertObject(pObject, GDI_OBJ_HMGR_POWNED);
1143 if (!handle)
1144 {
1145 DPRINT1("NtGdiCreateClientObj: Could not create a handle.\n");
1146 GDIOBJ_vFreeObject(pObject);
1147 return NULL;
1148 }
1149
1150 /* Unlock it */
1151 GDIOBJ_vUnlockObject(pObject);
1152
1153 return handle;
1154 }
1155
1156 W32KAPI
1157 BOOL
1158 APIENTRY
1159 NtGdiDeleteClientObj(
1160 IN HANDLE hobj)
1161 {
1162 /* We first need to get the real type from the handle */
1163 ULONG ulType = GDI_HANDLE_GET_TYPE(hobj);
1164
1165 /* Check if it's really a CLIENTOBJ */
1166 if ((ulType & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE)
1167 {
1168 /* FIXME: SetLastError? */
1169 return FALSE;
1170 }
1171
1172 return GreDeleteObject(hobj);
1173 }
1174
1175
1176
1177 PGDI_HANDLE_TABLE GdiHandleTable = NULL;
1178
1179 PGDIOBJ NTAPI
1180 GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
1181 {
1182 if (ExpectedType == GDI_OBJECT_TYPE_DONTCARE)
1183 ExpectedType = GDI_HANDLE_GET_TYPE(hObj);
1184 return GDIOBJ_ReferenceObjectByHandle(hObj, (ExpectedType >> 16) & 0x1f);
1185 }
1186
1187 // This function is not safe to use with concurrent deleting attempts
1188 // That shouldn't be a problem, since we don't have any processes yet,
1189 // that could delete the handle
1190 BOOL
1191 NTAPI
1192 GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
1193 {
1194 PENTRY pentry;
1195 POBJ pobj;
1196
1197 /* Reference the handle entry */
1198 pentry = ENTRY_ReferenceEntryByHandle(*phObj, 0);
1199 if (!pentry)
1200 {
1201 DPRINT1("GDIOBJ: Requested handle 0x%p is not valid.\n", *phObj);
1202 return FALSE;
1203 }
1204
1205 /* Update the entry */
1206 pentry->FullUnique |= GDI_ENTRY_STOCK_MASK;
1207 pentry->ObjectOwner.ulObj = 0;
1208
1209 /* Get the pointer to the BASEOBJECT */
1210 pobj = pentry->einfo.pobj;
1211
1212 /* Calculate the new handle */
1213 pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)pobj->hHmgr | GDI_HANDLE_STOCK_MASK);
1214
1215 /* Return the new handle */
1216 *phObj = pobj->hHmgr;
1217
1218 /* Dereference the handle */
1219 GDIOBJ_vDereferenceObject(pobj);
1220
1221 return TRUE;
1222 }
1223
1224 POBJ NTAPI
1225 GDIOBJ_AllocObjWithHandle(ULONG ObjectType, ULONG cjSize)
1226 {
1227 POBJ pobj;
1228 FLONG fl = 0;
1229 UCHAR objt = (ObjectType >> 16) & 0xFF;
1230
1231 if ((objt == GDIObjType_DC_TYPE && cjSize == sizeof(DC)) ||
1232 (objt == GDIObjType_PAL_TYPE && cjSize == sizeof(PALETTE)) ||
1233 (objt == GDIObjType_RGN_TYPE && cjSize == sizeof(REGION)) ||
1234 (objt == GDIObjType_SURF_TYPE && cjSize == sizeof(SURFACE)) ||
1235 (objt == GDIObjType_PATH_TYPE && cjSize == sizeof(PATH)))
1236 {
1237 fl |= BASEFLAG_LOOKASIDE;
1238 }
1239
1240 pobj = GDIOBJ_AllocateObject(objt, cjSize, fl);
1241 if (!GDIOBJ_hInsertObject(pobj, GDI_OBJ_HMGR_POWNED))
1242 {
1243 GDIOBJ_vFreeObject(pobj);
1244 return NULL;
1245 }
1246 return pobj;
1247 }
1248
1249 PVOID NTAPI
1250 GDI_MapHandleTable(PEPROCESS pProcess)
1251 {
1252 PVOID pvMappedView = NULL;
1253 NTSTATUS Status;
1254 LARGE_INTEGER liOffset;
1255 ULONG cjViewSize = sizeof(GDI_HANDLE_TABLE);
1256
1257 liOffset.QuadPart = 0;
1258
1259 ASSERT(gpvGdiHdlTblSection != NULL);
1260 ASSERT(pProcess != NULL);
1261
1262 Status = MmMapViewOfSection(gpvGdiHdlTblSection,
1263 pProcess,
1264 &pvMappedView,
1265 0,
1266 0,
1267 &liOffset,
1268 &cjViewSize,
1269 ViewUnmap,
1270 SEC_NO_CHANGE,
1271 PAGE_READONLY);
1272
1273 if (!NT_SUCCESS(Status))
1274 return NULL;
1275
1276 return pvMappedView;
1277 }
1278
1279 BOOL NTAPI
1280 GDI_CleanupForProcess(struct _EPROCESS *Process)
1281 {
1282 PENTRY pentry;
1283 ULONG ulIndex;
1284 DWORD dwProcessId;
1285 PPROCESSINFO ppi;
1286
1287 DPRINT("CleanupForProcess prochandle %p Pid %p\n",
1288 Process, Process->UniqueProcessId);
1289
1290 ASSERT(Process == PsGetCurrentProcess());
1291
1292 /* Get the current process Id */
1293 dwProcessId = PtrToUlong(PsGetCurrentProcessId());
1294
1295 /* Loop all handles in the handle table */
1296 for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++)
1297 {
1298 pentry = &gpentHmgr[ulIndex];
1299
1300 /* Check if the object is owned by the process */
1301 if (pentry->ObjectOwner.ulObj == dwProcessId)
1302 {
1303 ASSERT(pentry->einfo.pobj->cExclusiveLock == 0);
1304
1305 /* Reference the object and delete it */
1306 InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]);
1307 GDIOBJ_vDeleteObject(pentry->einfo.pobj);
1308 }
1309 }
1310
1311 #if DBG
1312 //#ifdef GDI_DEBUG
1313 DbgGdiHTIntegrityCheck();
1314 //#endif
1315 #endif
1316
1317 ppi = PsGetCurrentProcessWin32Process();
1318 DPRINT("Completed cleanup for process %p\n", Process->UniqueProcessId);
1319 if (ppi->GDIHandleCount != 0)
1320 {
1321 DPRINT1("Leaking %d handles!\n", ppi->GDIHandleCount);
1322 ASSERT(FALSE);
1323 }
1324
1325 /* Loop all handles in the handle table */
1326 for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++)
1327 {
1328 pentry = &gpentHmgr[ulIndex];
1329
1330 /* Check if the object is owned by the process */
1331 if (pentry->ObjectOwner.ulObj == dwProcessId)
1332 {
1333 DPRINT1("Leaking object. Index=%lx, type=0x%x, refcount=%lx\n",
1334 ulIndex, pentry->Objt, gpaulRefCount[ulIndex]);
1335 DBG_DUMP_EVENT_LIST(&pentry->einfo.pobj->slhLog);
1336 //DBG_CLEANUP_EVENT_LIST(&pentry->einfo.pobj->slhLog);
1337 ASSERT(FALSE);
1338 }
1339 }
1340
1341 return TRUE;
1342 }
1343
1344 #if DBG && KDBG
1345 static const char * gpszObjectTypes[] =
1346 {
1347 "FREE", "DC", "UNUSED1", "UNUSED2", "RGN", "SURF", "CLIENTOBJ", "PATH",
1348 "PAL", "ICMLCS", "LFONT", "RFONT", "PFE", "PFT", "ICMCXF", "SPRITE",
1349 "BRUSH", "UMPD", "UNUSED4", "SPACE", "UNUSED5", "META", "EFSTATE",
1350 "BMFD", "VTFD", "TTFD", "RC", "TEMP", "DRVOBJ", "DCIOBJ", "SPOOL",
1351 "RESERVED", "ALL"
1352 };
1353
1354 extern PEPROCESS gpepCSRSS;;
1355
1356 VOID
1357 NTAPI
1358 DbgDumpGdiHandleTable(ULONG argc, char *argv[])
1359 {
1360 ULONG i;
1361 UCHAR Objt, jReqestedType;
1362 PENTRY pentry;
1363 POBJ pobj;
1364 KAPC_STATE ApcState;
1365
1366 /* No CSRSS, no handle table */
1367 if (!gpepCSRSS) return;
1368 KeStackAttachProcess(&gpepCSRSS->Pcb, &ApcState);
1369
1370 if (argc == 0)
1371 {
1372 USHORT Counts[GDIObjType_MAX_TYPE + 2] = {0};
1373
1374 /* Loop all possibly used entries in the handle table */
1375 for (i = RESERVE_ENTRIES_COUNT; i < gulFirstUnused; i++)
1376 {
1377 if (MmIsAddressValid(&gpentHmgr[i]))
1378 {
1379 Objt = gpentHmgr[i].Objt & 0x1F;
1380 Counts[Objt]++;
1381 }
1382 }
1383
1384 DbgPrint("Type Count\n");
1385 DbgPrint("-------------------\n");
1386 for (i = 0; i <= GDIObjType_MAX_TYPE; i++)
1387 {
1388 DbgPrint("%02x %-9s %d\n",
1389 i, gpszObjectTypes[i], Counts[i]);
1390 }
1391 DbgPrint("\n");
1392 }
1393 else
1394 {
1395 /* Loop all object types */
1396 for (i = 0; i <= GDIObjType_MAX_TYPE + 1; i++)
1397 {
1398 /* Check if this object type was requested */
1399 if (stricmp(argv[0], gpszObjectTypes[i]) == 0)
1400 {
1401 jReqestedType = i;
1402 break;
1403 }
1404 }
1405
1406 /* Check if we didn't find it yet */
1407 if (i > GDIObjType_MAX_TYPE)
1408 {
1409 /* Try if it's a number */
1410 i = atoi(argv[0]);
1411
1412 /* Check for "0" */
1413 if ((i > GDIObjType_MAX_TYPE) ||
1414 ((i == 0) && (stricmp(argv[0], "0") == 0)))
1415 {
1416 DbgPrint("Unknown object type: %s\n", argv[0]);
1417 goto leave;
1418 }
1419
1420 jReqestedType = i;
1421 }
1422
1423 /* Print header */
1424 DbgPrint("Index Handle Type ThreadId cLocks ulRefCount\n");
1425 DbgPrint("----------------------------------------------------\n");
1426
1427 /* Loop all possibly used entries in the handle table */
1428 for (i = RESERVE_ENTRIES_COUNT; i < gulFirstUnused; i++)
1429 {
1430 /* Get the entry and the object */
1431 pentry = &gpentHmgr[i];
1432
1433 if (!MmIsAddressValid(pentry)) continue;
1434
1435 pobj = pentry->einfo.pobj;
1436 Objt = pentry->Objt & 0x1F;
1437
1438 if ((jReqestedType == GDIObjType_MAX_TYPE + 1) ||
1439 (Objt == jReqestedType))
1440 {
1441 DbgPrint("%04lx %p %-9s 0x%06lx %-7ld ",
1442 i, pobj->hHmgr, gpszObjectTypes[Objt],
1443 pobj->dwThreadId, pobj->cExclusiveLock);
1444 if (MmIsAddressValid(&gpaulRefCount[i]))
1445 DbgPrint("0x%06lx\n", gpaulRefCount[i]);
1446 else
1447 DbgPrint("????????\n");
1448 }
1449 }
1450 }
1451
1452 leave:
1453 KeUnstackDetachProcess(&ApcState);
1454 }
1455
1456 VOID
1457 NTAPI
1458 DbgDumpHandleInfo(char *argv)
1459 {
1460 ULONG_PTR ulObject;
1461 BASEOBJECT *pobj;
1462 ENTRY *pentry;
1463 USHORT usIndex;
1464 char *endptr;
1465 KAPC_STATE ApcState;
1466
1467 /* Skip optional '0x' prefix */
1468 if ((argv[0] == '0') && ((argv[1] == 'x') || (argv[1] == 'X')))
1469 argv += 2;
1470
1471 /* Make a number from the string (hex) */
1472 ulObject = strtol(argv, &endptr, 16);
1473 if (*endptr != '\0')
1474 return;
1475
1476 /* No CSRSS, no handle table */
1477 if (!gpepCSRSS) return;
1478 KeStackAttachProcess(&gpepCSRSS->Pcb, &ApcState);
1479
1480 usIndex = ulObject & 0xFFFF;
1481 pentry = &gpentHmgr[usIndex];
1482
1483 if (MmIsAddressValid(pentry))
1484 {
1485 pobj = pentry->einfo.pobj;
1486
1487 DbgPrint("GDI handle=%p, type=%s, index=0x%lx, pentry=%p.\n",
1488 ulObject, gpszObjectTypes[(ulObject >> 16) & 0x1f],
1489 usIndex, pentry);
1490 DbgPrint(" ENTRY = {.pobj = %p, ObjectOwner = 0x%lx, FullUnique = 0x%04x,\n"
1491 " Objt=0x%02x, Flags = 0x%02x, pUser = 0x%p}\n",
1492 pentry->einfo.pobj, pentry->ObjectOwner.ulObj, pentry->FullUnique,
1493 pentry->Objt, pentry->Flags, pentry->pUser);
1494 DbgPrint(" BASEOBJECT = {hHmgr = %p, dwThreadId = 0x%lx,\n"
1495 " cExclusiveLock = %ld, BaseFlags = 0x%lx}\n",
1496 pobj->hHmgr, pobj->dwThreadId,
1497 pobj->cExclusiveLock, pobj->BaseFlags);
1498 if (MmIsAddressValid(&gpaulRefCount[usIndex]))
1499 DbgPrint(" gpaulRefCount[idx] = %ld\n", gpaulRefCount[usIndex]);
1500 }
1501 else
1502 {
1503 DbgPrint("Coudn't access ENTRY. Probably paged out.\n");
1504 }
1505
1506 KeUnstackDetachProcess(&ApcState);
1507 }
1508 #endif // DBG && KDBG
1509
1510 /* EOF */