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