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