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