Synchronize with trunk's revision r57599.
[reactos.git] / 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 ULONG cRefs;
574
575 /* Check if the object has a handle */
576 if (GDI_HANDLE_GET_INDEX(pobj->hHmgr))
577 {
578 /* Increase the handle's reference count */
579 ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
580 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
581 cRefs = InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]);
582 }
583 else
584 {
585 /* Increase the object's reference count */
586 cRefs = InterlockedIncrement((LONG*)&pobj->ulShareCount);
587 }
588
589 DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, cRefs);
590 }
591
592 PGDIOBJ
593 NTAPI
594 GDIOBJ_LockObject(
595 HGDIOBJ hobj,
596 UCHAR objt)
597 {
598 PENTRY pentry;
599 POBJ pobj;
600 DWORD dwThreadId;
601
602 /* Check if the handle type matches */
603 ASSERT_EXCLUSIVE_OBJECT_TYPE(objt);
604 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt)
605 {
606 DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj, objt);
607 return NULL;
608 }
609
610 /* Reference the handle entry */
611 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
612 if (!pentry)
613 {
614 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj);
615 return NULL;
616 }
617
618 /* Get the pointer to the BASEOBJECT */
619 pobj = pentry->einfo.pobj;
620
621 /* Check if we already own the lock */
622 dwThreadId = PtrToUlong(PsGetCurrentThreadId());
623 if (pobj->dwThreadId != dwThreadId)
624 {
625 /* Disable APCs and acquire the push lock */
626 KeEnterCriticalRegion();
627 ExAcquirePushLockExclusive(&pobj->pushlock);
628
629 /* Set us as lock owner */
630 ASSERT(pobj->dwThreadId == 0);
631 pobj->dwThreadId = dwThreadId;
632 }
633
634 /* Increase lock count */
635 pobj->cExclusiveLock++;
636 DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), hobj);
637 DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0);
638
639 /* Return the object */
640 return pobj;
641 }
642
643 VOID
644 NTAPI
645 GDIOBJ_vUnlockObject(POBJ pobj)
646 {
647 ULONG cRefs, ulIndex;
648 ASSERT(pobj->cExclusiveLock > 0);
649
650 /* Decrease lock count */
651 pobj->cExclusiveLock--;
652 DBG_DECREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
653 DBG_LOGEVENT(&pobj->slhLog, EVENT_UNLOCK, 0);
654
655 /* Check if this was the last lock */
656 if (pobj->cExclusiveLock == 0)
657 {
658 /* Reset lock owner */
659 pobj->dwThreadId = 0;
660
661 /* Release the pushlock and reenable APCs */
662 ExReleasePushLockExclusive(&pobj->pushlock);
663 KeLeaveCriticalRegion();
664 }
665
666 /* Calculate the index */
667 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
668
669 /* Decrement reference count */
670 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
671 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]);
672 ASSERT(cRefs & REF_MASK_VALID);
673 }
674
675 HGDIOBJ
676 NTAPI
677 GDIOBJ_hInsertObject(
678 POBJ pobj,
679 ULONG ulOwner)
680 {
681 PENTRY pentry;
682 UCHAR objt;
683
684 /* Must have no handle and only one reference */
685 ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr) == 0);
686 ASSERT(pobj->cExclusiveLock == 0);
687 ASSERT(pobj->ulShareCount == 1);
688
689 /* Get a free handle entry */
690 pentry = ENTRY_pentPopFreeEntry();
691 if (!pentry)
692 {
693 DPRINT1("GDIOBJ: Could not get a free entry.\n");
694 return NULL;
695 }
696
697 /* Make the object exclusively locked */
698 ExInitializePushLock(&pobj->pushlock);
699 KeEnterCriticalRegion();
700 ExAcquirePushLockExclusive(&pobj->pushlock);
701 pobj->cExclusiveLock = 1;
702 pobj->dwThreadId = PtrToUlong(PsGetCurrentThreadId());
703 DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
704
705 /* Get object type from the hHmgr field */
706 objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0xff;
707 ASSERT(objt != GDIObjType_DEF_TYPE);
708
709 /* Check if current process is requested owner */
710 if (ulOwner == GDI_OBJ_HMGR_POWNED)
711 {
712 /* Increment the process handle count */
713 IncrementGdiHandleCount();
714
715 /* Use Process id */
716 ulOwner = HandleToUlong(PsGetCurrentProcessId());
717 }
718
719 /* Insert the object into the handle table */
720 pobj->hHmgr = ENTRY_hInsertObject(pentry, pobj, objt, ulOwner);
721
722 /* Return the handle */
723 DPRINT("GDIOBJ: Created handle: %p\n", pobj->hHmgr);
724 DBG_LOGEVENT(&pobj->slhLog, EVENT_CREATE_HANDLE, 0);
725 return pobj->hHmgr;
726 }
727
728 VOID
729 NTAPI
730 GDIOBJ_vSetObjectOwner(
731 POBJ pobj,
732 ULONG ulOwner)
733 {
734 PENTRY pentry;
735
736 /* This is a ugly HACK, needed to fix IntGdiSetDCOwnerEx */
737 if (GDI_HANDLE_IS_STOCKOBJ(pobj->hHmgr))
738 {
739 DPRINT("Trying to set ownership of stock object %p to %lx\n", pobj->hHmgr, ulOwner);
740 return;
741 }
742
743 /* Get the handle entry */
744 ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr));
745 pentry = &gpentHmgr[GDI_HANDLE_GET_INDEX(pobj->hHmgr)];
746
747 /* Is the current process requested? */
748 if (ulOwner == GDI_OBJ_HMGR_POWNED)
749 {
750 /* Use process id */
751 ulOwner = HandleToUlong(PsGetCurrentProcessId());
752 if (pentry->ObjectOwner.ulObj != ulOwner)
753 {
754 IncrementGdiHandleCount();
755 }
756 }
757
758 // HACK
759 if (ulOwner == GDI_OBJ_HMGR_NONE)
760 ulOwner = GDI_OBJ_HMGR_PUBLIC;
761
762 if (ulOwner == GDI_OBJ_HMGR_PUBLIC ||
763 ulOwner == GDI_OBJ_HMGR_NONE)
764 {
765 /* Make sure we don't leak user mode memory */
766 ASSERT(pentry->pUser == NULL);
767 if (pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC &&
768 pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_NONE)
769 {
770 DecrementGdiHandleCount();
771 }
772 }
773
774 /* Set new owner */
775 pentry->ObjectOwner.ulObj = ulOwner;
776 DBG_LOGEVENT(&pobj->slhLog, EVENT_SET_OWNER, 0);
777 }
778
779 /* Locks 2 or 3 objects at a time */
780 BOOL
781 NTAPI
782 GDIOBJ_bLockMultipleObjects(
783 IN ULONG ulCount,
784 IN HGDIOBJ* ahObj,
785 OUT PGDIOBJ* apObj,
786 IN UCHAR objt)
787 {
788 UINT auiIndices[3] = {0, 1, 2};
789 UINT i, j, tmp;
790
791 ASSERT(ulCount <= 3);
792
793 /* Sort the handles */
794 for (i = 0; i < ulCount - 1; i++)
795 {
796 for (j = i + 1; j < ulCount; j++)
797 {
798 if ((ULONG_PTR)ahObj[auiIndices[i]] <
799 (ULONG_PTR)ahObj[auiIndices[j]])
800 {
801 tmp = auiIndices[i];
802 auiIndices[i] = auiIndices[j];
803 auiIndices[j] = tmp;
804 }
805 }
806 }
807
808 /* Lock the objects in safe order */
809 for (i = 0; i < ulCount; i++)
810 {
811 /* Skip NULL handles */
812 if (ahObj[auiIndices[i]] == NULL)
813 {
814 apObj[auiIndices[i]] = NULL;
815 continue;
816 }
817
818 /* Lock the object */
819 apObj[auiIndices[i]] = GDIOBJ_LockObject(ahObj[auiIndices[i]], objt);
820
821 /* Check for failure */
822 if (apObj[auiIndices[i]] == NULL)
823 {
824 /* Cleanup */
825 while (i--)
826 {
827 if (apObj[auiIndices[i]])
828 GDIOBJ_vUnlockObject(apObj[auiIndices[i]]);
829 }
830 return FALSE;
831 }
832 }
833
834 return TRUE;
835 }
836
837 PVOID
838 NTAPI
839 GDIOBJ_pvGetObjectAttr(POBJ pobj)
840 {
841 ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
842 return gpentHmgr[ulIndex].pUser;
843 }
844
845 VOID
846 NTAPI
847 GDIOBJ_vSetObjectAttr(POBJ pobj, PVOID pvObjAttr)
848 {
849 ULONG ulIndex;
850
851 ASSERT(pobj->hHmgr);
852
853 /* Get the handle index */
854 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
855
856 /* Set pointer to the usermode attribute */
857 gpentHmgr[ulIndex].pUser = pvObjAttr;
858 }
859
860 VOID
861 NTAPI
862 GDIOBJ_vDeleteObject(POBJ pobj)
863 {
864 ULONG ulIndex;
865
866 /* Set the object's delete flag */
867 InterlockedOr16((SHORT*)&pobj->BaseFlags, BASEFLAG_READY_TO_DIE);
868 DBG_LOGEVENT(&pobj->slhLog, EVENT_DELETE, 0);
869
870 /* Get the handle index */
871 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
872 if (ulIndex)
873 {
874 /* Reset the handle valid bit */
875 InterlockedAnd((LONG*)&gpaulRefCount[ulIndex], ~REF_MASK_VALID);
876
877 /* Check if the object is exclusively locked */
878 if (pobj->cExclusiveLock != 0)
879 {
880 /* Reset lock owner and lock count */
881 pobj->dwThreadId = 0;
882 pobj->cExclusiveLock = 0;
883
884 /* Release the pushlock and reenable APCs */
885 ExReleasePushLockExclusive(&pobj->pushlock);
886 KeLeaveCriticalRegion();
887 DBG_DECREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
888 }
889 }
890
891 /* Dereference the object (will take care of deletion) */
892 GDIOBJ_vDereferenceObject(pobj);
893 }
894
895 BOOL
896 NTAPI
897 GreIsHandleValid(HGDIOBJ hobj)
898 {
899 PENTRY pentry;
900
901 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
902 if (!pentry) return FALSE;
903 GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
904 return TRUE;
905 }
906
907 BOOL
908 NTAPI
909 GreDeleteObject(HGDIOBJ hobj)
910 {
911 PENTRY pentry;
912
913 /* Check for stock objects */
914 if (GDI_HANDLE_IS_STOCKOBJ(hobj))
915 {
916 DPRINT1("GreDeleteObject: Cannot delete stock object %p.\n", hobj);
917 return FALSE;
918 }
919
920 /* Reference the handle entry */
921 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
922 if (!pentry)
923 {
924 DPRINT1("GreDeleteObject: Trying to delete invalid object %p\n", hobj);
925 return FALSE;
926 }
927
928 /* Check for public owner */
929 if (pentry->ObjectOwner.ulObj == GDI_OBJ_HMGR_PUBLIC)
930 {
931 DPRINT1("GreDeleteObject: Trying to delete global object %p\n", hobj);
932 GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
933 return FALSE;
934 }
935
936 /* Delete the object */
937 GDIOBJ_vDeleteObject(pentry->einfo.pobj);
938 return TRUE;
939 }
940
941 ULONG
942 NTAPI
943 GreGetObjectOwner(HGDIOBJ hobj)
944 {
945 ULONG ulIndex, ulOwner;
946
947 /* Get the handle index */
948 ulIndex = GDI_HANDLE_GET_INDEX(hobj);
949
950 /* Check if the handle is valid */
951 if (ulIndex >= GDI_HANDLE_COUNT ||
952 gpentHmgr[ulIndex].Objt == GDIObjType_DEF_TYPE ||
953 ((ULONG_PTR)hobj >> 16) != gpentHmgr[ulIndex].FullUnique)
954 {
955 DPRINT1("GreGetObjectOwner: invalid handle 0x%p.\n", hobj);
956 return GDI_OBJ_HMGR_RESTRICTED;
957 }
958
959 /* Get the object owner */
960 ulOwner = gpentHmgr[ulIndex].ObjectOwner.ulObj;
961
962 if (ulOwner == HandleToUlong(PsGetCurrentProcessId()))
963 return GDI_OBJ_HMGR_POWNED;
964
965 if (ulOwner == GDI_OBJ_HMGR_PUBLIC)
966 return GDI_OBJ_HMGR_PUBLIC;
967
968 return GDI_OBJ_HMGR_RESTRICTED;
969 }
970
971 BOOL
972 NTAPI
973 GreSetObjectOwner(
974 HGDIOBJ hobj,
975 ULONG ulOwner)
976 {
977 PENTRY pentry;
978
979 /* Check for stock objects */
980 if (GDI_HANDLE_IS_STOCKOBJ(hobj))
981 {
982 DPRINT("GreSetObjectOwner: Got stock object %p\n", hobj);
983 return FALSE;
984 }
985
986 /* Reference the handle entry */
987 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
988 if (!pentry)
989 {
990 DPRINT("GreSetObjectOwner: Invalid handle 0x%p.\n", hobj);
991 return FALSE;
992 }
993
994 /* Call internal function */
995 GDIOBJ_vSetObjectOwner(pentry->einfo.pobj, ulOwner);
996
997 /* Dereference the object */
998 GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
999
1000 return TRUE;
1001 }
1002
1003 INT
1004 NTAPI
1005 GreGetObject(
1006 IN HGDIOBJ hobj,
1007 IN INT cbCount,
1008 IN PVOID pvBuffer)
1009 {
1010 PVOID pvObj;
1011 UCHAR objt;
1012 INT iResult = 0;
1013
1014 /* Verify object type */
1015 objt = ((ULONG_PTR)hobj >> 16) & 0x1f;
1016 if (objt != GDIObjType_BRUSH_TYPE &&
1017 objt != GDIObjType_SURF_TYPE &&
1018 objt != GDIObjType_LFONT_TYPE &&
1019 objt != GDIObjType_PAL_TYPE)
1020 {
1021 DPRINT1("GreGetObject: Invalid object type\n");
1022 return 0;
1023 }
1024
1025 pvObj = GDIOBJ_ReferenceObjectByHandle(hobj, objt);
1026 if (!pvObj)
1027 {
1028 DPRINT("GreGetObject: Could not lock object\n");
1029 return 0;
1030 }
1031
1032 switch (GDI_HANDLE_GET_TYPE(hobj))
1033 {
1034 case GDILoObjType_LO_PEN_TYPE:
1035 case GDILoObjType_LO_EXTPEN_TYPE:
1036 iResult = PEN_GetObject(pvObj, cbCount, pvBuffer);
1037 break;
1038
1039 case GDILoObjType_LO_BRUSH_TYPE:
1040 iResult = BRUSH_GetObject(pvObj, cbCount, pvBuffer);
1041 break;
1042
1043 case GDILoObjType_LO_BITMAP_TYPE:
1044 iResult = BITMAP_GetObject(pvObj, cbCount, pvBuffer);
1045 break;
1046
1047 case GDILoObjType_LO_FONT_TYPE:
1048 iResult = FontGetObject(pvObj, cbCount, pvBuffer);
1049 break;
1050
1051 case GDILoObjType_LO_PALETTE_TYPE:
1052 iResult = PALETTE_GetObject(pvObj, cbCount, pvBuffer);
1053 break;
1054
1055 default:
1056 DPRINT1("GDI object type of 0x%p not implemented\n", hobj);
1057 break;
1058 }
1059
1060 GDIOBJ_vDereferenceObject(pvObj);
1061 return iResult;
1062 }
1063
1064 W32KAPI
1065 INT
1066 APIENTRY
1067 NtGdiExtGetObjectW(
1068 IN HANDLE hobj,
1069 IN INT cbCount,
1070 OUT LPVOID lpBuffer)
1071 {
1072 INT iRetCount = 0;
1073 INT cbCopyCount;
1074 union
1075 {
1076 BITMAP bitmap;
1077 DIBSECTION dibsection;
1078 LOGPEN logpen;
1079 LOGBRUSH logbrush;
1080 LOGFONTW logfontw;
1081 EXTLOGFONTW extlogfontw;
1082 ENUMLOGFONTEXDVW enumlogfontexdvw;
1083 } object;
1084
1085 /* Normalize to the largest supported object size */
1086 cbCount = min((UINT)cbCount, sizeof(object));
1087
1088 /* Now do the actual call */
1089 iRetCount = GreGetObject(hobj, cbCount, lpBuffer ? &object : NULL);
1090 cbCopyCount = min((UINT)cbCount, (UINT)iRetCount);
1091
1092 /* Make sure we have a buffer and a copy size */
1093 if ((cbCopyCount) && (lpBuffer))
1094 {
1095 /* Enter SEH for buffer transfer */
1096 _SEH2_TRY
1097 {
1098 /* Probe the buffer and copy it */
1099 ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD));
1100 RtlCopyMemory(lpBuffer, &object, cbCopyCount);
1101 }
1102 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1103 {
1104 /* Clear the return value.
1105 * Do *NOT* set last error here! */
1106 iRetCount = 0;
1107 }
1108 _SEH2_END;
1109 }
1110
1111 /* Return the count */
1112 return iRetCount;
1113 }
1114
1115 W32KAPI
1116 HANDLE
1117 APIENTRY
1118 NtGdiCreateClientObj(
1119 IN ULONG ulType)
1120 {
1121 POBJ pObject;
1122 HANDLE handle;
1123
1124 /* Allocate a new object */
1125 pObject = GDIOBJ_AllocateObject(GDIObjType_CLIENTOBJ_TYPE,
1126 sizeof(CLIENTOBJ),
1127 BASEFLAG_LOOKASIDE);
1128 if (!pObject)
1129 {
1130 DPRINT1("NtGdiCreateClientObj: Could not allocate a clientobj.\n");
1131 return NULL;
1132 }
1133
1134 /* Mask out everything that would change the type in a wrong manner */
1135 ulType &= (GDI_HANDLE_TYPE_MASK & ~GDI_HANDLE_BASETYPE_MASK);
1136
1137 /* Set the real object type */
1138 pObject->hHmgr = UlongToHandle(ulType | GDILoObjType_LO_CLIENTOBJ_TYPE);
1139
1140 /* Create a handle */
1141 handle = GDIOBJ_hInsertObject(pObject, GDI_OBJ_HMGR_POWNED);
1142 if (!handle)
1143 {
1144 DPRINT1("NtGdiCreateClientObj: Could not create a handle.\n");
1145 GDIOBJ_vFreeObject(pObject);
1146 return NULL;
1147 }
1148
1149 /* Unlock it */
1150 GDIOBJ_vUnlockObject(pObject);
1151
1152 return handle;
1153 }
1154
1155 W32KAPI
1156 BOOL
1157 APIENTRY
1158 NtGdiDeleteClientObj(
1159 IN HANDLE hobj)
1160 {
1161 /* We first need to get the real type from the handle */
1162 ULONG ulType = GDI_HANDLE_GET_TYPE(hobj);
1163
1164 /* Check if it's really a CLIENTOBJ */
1165 if ((ulType & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE)
1166 {
1167 /* FIXME: SetLastError? */
1168 return FALSE;
1169 }
1170
1171 return GreDeleteObject(hobj);
1172 }
1173
1174
1175
1176 PGDI_HANDLE_TABLE GdiHandleTable = NULL;
1177
1178 PGDIOBJ NTAPI
1179 GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
1180 {
1181 if (ExpectedType == GDI_OBJECT_TYPE_DONTCARE)
1182 ExpectedType = GDI_HANDLE_GET_TYPE(hObj);
1183 return GDIOBJ_ReferenceObjectByHandle(hObj, (ExpectedType >> 16) & 0x1f);
1184 }
1185
1186 // This function is not safe to use with concurrent deleting attempts
1187 // That shouldn't be a problem, since we don't have any processes yet,
1188 // that could delete the handle
1189 BOOL
1190 NTAPI
1191 GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
1192 {
1193 PENTRY pentry;
1194 POBJ pobj;
1195
1196 /* Reference the handle entry */
1197 pentry = ENTRY_ReferenceEntryByHandle(*phObj, 0);
1198 if (!pentry)
1199 {
1200 DPRINT1("GDIOBJ: Requested handle 0x%p is not valid.\n", *phObj);
1201 return FALSE;
1202 }
1203
1204 /* Update the entry */
1205 pentry->FullUnique |= GDI_ENTRY_STOCK_MASK;
1206 pentry->ObjectOwner.ulObj = 0;
1207
1208 /* Get the pointer to the BASEOBJECT */
1209 pobj = pentry->einfo.pobj;
1210
1211 /* Calculate the new handle */
1212 pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)pobj->hHmgr | GDI_HANDLE_STOCK_MASK);
1213
1214 /* Return the new handle */
1215 *phObj = pobj->hHmgr;
1216
1217 /* Dereference the handle */
1218 GDIOBJ_vDereferenceObject(pobj);
1219
1220 return TRUE;
1221 }
1222
1223 POBJ NTAPI
1224 GDIOBJ_AllocObjWithHandle(ULONG ObjectType, ULONG cjSize)
1225 {
1226 POBJ pobj;
1227 FLONG fl = 0;
1228 UCHAR objt = (ObjectType >> 16) & 0xFF;
1229
1230 if ((objt == GDIObjType_DC_TYPE && cjSize == sizeof(DC)) ||
1231 (objt == GDIObjType_PAL_TYPE && cjSize == sizeof(PALETTE)) ||
1232 (objt == GDIObjType_RGN_TYPE && cjSize == sizeof(REGION)) ||
1233 (objt == GDIObjType_SURF_TYPE && cjSize == sizeof(SURFACE)) ||
1234 (objt == GDIObjType_PATH_TYPE && cjSize == sizeof(PATH)))
1235 {
1236 fl |= BASEFLAG_LOOKASIDE;
1237 }
1238
1239 pobj = GDIOBJ_AllocateObject(objt, cjSize, fl);
1240 if (!GDIOBJ_hInsertObject(pobj, GDI_OBJ_HMGR_POWNED))
1241 {
1242 GDIOBJ_vFreeObject(pobj);
1243 return NULL;
1244 }
1245 return pobj;
1246 }
1247
1248 PVOID NTAPI
1249 GDI_MapHandleTable(PEPROCESS pProcess)
1250 {
1251 PVOID pvMappedView = NULL;
1252 NTSTATUS Status;
1253 LARGE_INTEGER liOffset;
1254 ULONG cjViewSize = sizeof(GDI_HANDLE_TABLE);
1255
1256 liOffset.QuadPart = 0;
1257
1258 ASSERT(gpvGdiHdlTblSection != NULL);
1259 ASSERT(pProcess != NULL);
1260
1261 Status = MmMapViewOfSection(gpvGdiHdlTblSection,
1262 pProcess,
1263 &pvMappedView,
1264 0,
1265 0,
1266 &liOffset,
1267 &cjViewSize,
1268 ViewUnmap,
1269 SEC_NO_CHANGE,
1270 PAGE_READONLY);
1271
1272 if (!NT_SUCCESS(Status))
1273 return NULL;
1274
1275 return pvMappedView;
1276 }
1277
1278 BOOL NTAPI
1279 GDI_CleanupForProcess(struct _EPROCESS *Process)
1280 {
1281 PENTRY pentry;
1282 ULONG ulIndex;
1283 DWORD dwProcessId;
1284 PPROCESSINFO ppi;
1285
1286 DPRINT("CleanupForProcess prochandle %p Pid %p\n",
1287 Process, Process->UniqueProcessId);
1288
1289 ASSERT(Process == PsGetCurrentProcess());
1290
1291 /* Get the current process Id */
1292 dwProcessId = PtrToUlong(PsGetCurrentProcessId());
1293
1294 /* Loop all handles in the handle table */
1295 for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++)
1296 {
1297 pentry = &gpentHmgr[ulIndex];
1298
1299 /* Check if the object is owned by the process */
1300 if (pentry->ObjectOwner.ulObj == dwProcessId)
1301 {
1302 ASSERT(pentry->einfo.pobj->cExclusiveLock == 0);
1303
1304 /* Reference the object and delete it */
1305 InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]);
1306 GDIOBJ_vDeleteObject(pentry->einfo.pobj);
1307 }
1308 }
1309
1310 #if DBG
1311 //#ifdef GDI_DEBUG
1312 DbgGdiHTIntegrityCheck();
1313 //#endif
1314 #endif
1315
1316 ppi = PsGetCurrentProcessWin32Process();
1317 DPRINT("Completed cleanup for process %p\n", Process->UniqueProcessId);
1318 if (ppi->GDIHandleCount != 0)
1319 {
1320 DPRINT1("Leaking %d handles!\n", ppi->GDIHandleCount);
1321 ASSERT(FALSE);
1322 }
1323
1324 /* Loop all handles in the handle table */
1325 for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++)
1326 {
1327 pentry = &gpentHmgr[ulIndex];
1328
1329 /* Check if the object is owned by the process */
1330 if (pentry->ObjectOwner.ulObj == dwProcessId)
1331 {
1332 DPRINT1("Leaking object. Index=%lx, type=0x%x, refcount=%lx\n",
1333 ulIndex, pentry->Objt, gpaulRefCount[ulIndex]);
1334 DBG_DUMP_EVENT_LIST(&pentry->einfo.pobj->slhLog);
1335 //DBG_CLEANUP_EVENT_LIST(&pentry->einfo.pobj->slhLog);
1336 ASSERT(FALSE);
1337 }
1338 }
1339
1340 return TRUE;
1341 }
1342
1343
1344 /* EOF */