2a5597ecf66902196b4d274c29bdd1e8e6b6b06d
[reactos.git] / reactos / subsystems / win32 / win32k / objects / gdiobj.c
1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/objects/gdiobj.c
5 * PURPOSE: General GDI object manipulation routines
6 * PROGRAMMERS: Timo Kreuzer
7 */
8
9 /*
10 * If you want to understand this code, you need to start thinking in portals.
11 * - gpaulRefCount is a global pointer to an allocated array of ULONG values,
12 * one for each handle. Bits 0 - 22 contain a reference count for the handle.
13 * It gets increased for each handle lock / reference. Bit 23 contains a valid
14 * bit. If this bit is 0, the handle got deleted and will be pushed to the free
15 * list, once all references are gone. Bits 24 - 31 contain the reuse value of
16 * the handle, which allows to check if the entry was changed before atomically
17 * exchanging the reference count.
18 * - Objects can exist with or without a handle
19 * - Objects with a handle can be locked either exclusively or shared.
20 * Both locks increase the handle reference count in gpaulRefCount.
21 * Exclusive locks also increase the BASEOBJECT's cExclusiveLock field
22 * and the first lock (can be acquired recursively) acquires a pushlock
23 * that is also stored in the BASEOBJECT.
24 * - Objects without a handle cannot have exclusive locks. Their reference
25 * count is tracked in the BASEOBJECT's ulShareCount field.
26 * - An object that is inserted in the handle table automatically has an
27 * exclusive lock. For objects that are "shared objects" (BRUSH, PALETTE, ...)
28 * this is the only way it can ever be exclusively locked. It prevents the
29 * object from being locked by another thread. A shared lock will simply fail,
30 * while an exclusive lock will succeed after the object was unlocked.
31 *
32 */
33
34 /* INCLUDES ******************************************************************/
35
36 #include <win32k.h>
37 #define NDEBUG
38 #include <debug.h>
39
40 // move to gdidbg.h
41 #if DBG
42 #define DBG_INCREASE_LOCK_COUNT(pti, hobj) \
43 if (pti) ((PTHREADINFO)pti)->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]++;
44 #define DBG_DECREASE_LOCK_COUNT(pti, hobj) \
45 if (pti) ((PTHREADINFO)pti)->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]--;
46 #define ASSERT_SHARED_OBJECT_TYPE(objt) \
47 ASSERT((objt) == GDIObjType_SURF_TYPE || \
48 (objt) == GDIObjType_PAL_TYPE || \
49 (objt) == GDIObjType_LFONT_TYPE || \
50 (objt) == GDIObjType_PATH_TYPE || \
51 (objt) == GDIObjType_BRUSH_TYPE)
52 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt) \
53 ASSERT((objt) == GDIObjType_DC_TYPE || \
54 (objt) == GDIObjType_RGN_TYPE || \
55 (objt) == GDIObjType_LFONT_TYPE)
56 #else
57 #define DBG_INCREASE_LOCK_COUNT(ppi, hobj)
58 #define DBG_DECREASE_LOCK_COUNT(x, y)
59 #define ASSERT_SHARED_OBJECT_TYPE(objt)
60 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt)
61 #endif
62
63 #define MmMapViewInSessionSpace MmMapViewInSystemSpace
64
65 #ifdef _M_IX86
66 #define InterlockedOr16 _InterlockedOr16
67 #endif
68
69 #define GDIOBJ_POOL_TAG(type) ('00hG' + ((objt & 0x1f) << 24))
70
71 enum
72 {
73 REF_MASK_REUSE = 0xff000000,
74 REF_INC_REUSE = 0x01000000,
75 REF_MASK_VALID = 0x00800000,
76 REF_MASK_COUNT = 0x007fffff,
77 REF_MASK_INUSE = 0x00ffffff,
78 };
79
80 /* GLOBALS *******************************************************************/
81
82 /* Per session handle table globals */
83 static PVOID gpvGdiHdlTblSection = NULL;
84 static PENTRY gpentHmgr;
85 static PULONG gpaulRefCount;
86 ULONG gulFirstFree;
87 ULONG gulFirstUnused;
88 static PPAGED_LOOKASIDE_LIST gpaLookasideList;
89
90 static BOOL INTERNAL_CALL GDIOBJ_Cleanup(PVOID ObjectBody);
91
92 static const
93 GDICLEANUPPROC
94 apfnCleanup[] =
95 {
96 NULL, /* 00 GDIObjType_DEF_TYPE */
97 DC_Cleanup, /* 01 GDIObjType_DC_TYPE */
98 NULL, /* 02 GDIObjType_UNUSED1_TYPE */
99 NULL, /* 03 GDIObjType_UNUSED2_TYPE */
100 REGION_Cleanup, /* 04 GDIObjType_RGN_TYPE */
101 SURFACE_Cleanup, /* 05 GDIObjType_SURF_TYPE */
102 GDIOBJ_Cleanup, /* 06 GDIObjType_CLIENTOBJ_TYPE */
103 GDIOBJ_Cleanup, /* 07 GDIObjType_PATH_TYPE */
104 PALETTE_Cleanup, /* 08 GDIObjType_PAL_TYPE */
105 GDIOBJ_Cleanup, /* 09 GDIObjType_ICMLCS_TYPE */
106 GDIOBJ_Cleanup, /* 0a GDIObjType_LFONT_TYPE */
107 NULL, /* 0b GDIObjType_RFONT_TYPE, unused */
108 NULL, /* 0c GDIObjType_PFE_TYPE, unused */
109 NULL, /* 0d GDIObjType_PFT_TYPE, unused */
110 GDIOBJ_Cleanup, /* 0e GDIObjType_ICMCXF_TYPE */
111 NULL, /* 0f GDIObjType_SPRITE_TYPE, unused */
112 BRUSH_Cleanup, /* 10 GDIObjType_BRUSH_TYPE, BRUSH, PEN, EXTPEN */
113 NULL, /* 11 GDIObjType_UMPD_TYPE, unused */
114 NULL, /* 12 GDIObjType_UNUSED4_TYPE */
115 NULL, /* 13 GDIObjType_SPACE_TYPE, unused */
116 NULL, /* 14 GDIObjType_UNUSED5_TYPE */
117 NULL, /* 15 GDIObjType_META_TYPE, unused */
118 NULL, /* 16 GDIObjType_EFSTATE_TYPE, unused */
119 NULL, /* 17 GDIObjType_BMFD_TYPE, unused */
120 NULL, /* 18 GDIObjType_VTFD_TYPE, unused */
121 NULL, /* 19 GDIObjType_TTFD_TYPE, unused */
122 NULL, /* 1a GDIObjType_RC_TYPE, unused */
123 NULL, /* 1b GDIObjType_TEMP_TYPE, unused */
124 DRIVEROBJ_Cleanup,/* 1c GDIObjType_DRVOBJ_TYPE */
125 NULL, /* 1d GDIObjType_DCIOBJ_TYPE, unused */
126 NULL, /* 1e GDIObjType_SPOOL_TYPE, unused */
127 NULL, /* 1f reserved entry */
128 };
129
130 /* INTERNAL FUNCTIONS ********************************************************/
131
132 static
133 BOOL INTERNAL_CALL
134 GDIOBJ_Cleanup(PVOID ObjectBody)
135 {
136 return TRUE;
137 }
138
139 static
140 VOID
141 InitLookasideList(UCHAR objt, ULONG cjSize)
142 {
143 ExInitializePagedLookasideList(&gpaLookasideList[objt],
144 NULL,
145 NULL,
146 0,
147 cjSize,
148 GDITAG_HMGR_LOOKASIDE_START + (objt << 24),
149 0);
150 }
151
152 INIT_FUNCTION
153 NTSTATUS
154 NTAPI
155 InitGdiHandleTable(void)
156 {
157 NTSTATUS status;
158 LARGE_INTEGER liSize;
159 PVOID pvSection;
160 SIZE_T cjViewSize = 0;
161
162 /* Create a section for the shared handle table */
163 liSize.QuadPart = sizeof(GDI_HANDLE_TABLE);//GDI_HANDLE_COUNT * sizeof(ENTRY);
164 status = MmCreateSection(&gpvGdiHdlTblSection,
165 SECTION_ALL_ACCESS,
166 NULL,
167 &liSize,
168 PAGE_READWRITE,
169 SEC_COMMIT,
170 NULL,
171 NULL);
172 if (!NT_SUCCESS(status))
173 {
174 DPRINT1("INITGDI: Could not allocate a GDI handle table.\n");
175 return status;
176 }
177
178 /* Map the section in session space */
179 status = MmMapViewInSessionSpace(gpvGdiHdlTblSection,
180 (PVOID*)&gpentHmgr,
181 &cjViewSize);
182 if (!NT_SUCCESS(status))
183 {
184 DPRINT1("INITGDI: Failed to map handle table section\n");
185 ObDereferenceObject(gpvGdiHdlTblSection);
186 return status;
187 }
188
189 /* Allocate memory for the reference counter table */
190 gpaulRefCount = EngAllocSectionMem(&pvSection,
191 FL_ZERO_MEMORY,
192 GDI_HANDLE_COUNT * sizeof(ULONG),
193 'frHG');
194 if (!gpaulRefCount)
195 {
196 DPRINT1("INITGDI: Failed to allocate reference table.\n");
197 ObDereferenceObject(gpvGdiHdlTblSection);
198 return STATUS_INSUFFICIENT_RESOURCES;
199 }
200
201 gulFirstFree = 0;
202 gulFirstUnused = RESERVE_ENTRIES_COUNT;
203
204 GdiHandleTable = (PVOID)gpentHmgr;
205
206 /* Initialize the lookaside lists */
207 gpaLookasideList = ExAllocatePoolWithTag(NonPagedPool,
208 GDIObjTypeTotal * sizeof(PAGED_LOOKASIDE_LIST),
209 TAG_GDIHNDTBLE);
210
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 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 /* Check if the object has a handle */
478 if (GDI_HANDLE_GET_INDEX(pobj->hHmgr))
479 {
480 /* Calculate the index */
481 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
482
483 /* Decrement reference count */
484 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
485 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]) & REF_MASK_INUSE;
486
487 /* Check if we reached 0 and handle bit is not set */
488 if (cRefs == 0)
489 {
490 /* Check if the handle was process owned */
491 if (gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC &&
492 gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_NONE)
493 {
494 /* Decrement the process handle count */
495 ASSERT(gpentHmgr[ulIndex].ObjectOwner.ulObj ==
496 HandleToUlong(PsGetCurrentProcessId()));
497 DecrementGdiHandleCount();
498 }
499
500 /* Push entry to the free list */
501 ENTRY_vPushFreeEntry(&gpentHmgr[ulIndex]);
502 }
503 }
504 else
505 {
506 /* Decrement the objects reference count */
507 ASSERT(pobj->ulShareCount > 0);
508 cRefs = InterlockedDecrement((LONG*)&pobj->ulShareCount);
509 }
510
511 DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs);
512
513 /* Check if we reached 0 */
514 if (cRefs == 0)
515 {
516 /* Make sure it's ok to delete the object */
517 ASSERT(pobj->BaseFlags & BASEFLAG_READY_TO_DIE);
518
519 /* Free the object */
520 GDIOBJ_vFreeObject(pobj);
521 }
522 }
523
524 POBJ
525 NTAPI
526 GDIOBJ_ReferenceObjectByHandle(
527 HGDIOBJ hobj,
528 UCHAR objt)
529 {
530 PENTRY pentry;
531 POBJ pobj;
532
533 /* Check if the handle type matches */
534 ASSERT_SHARED_OBJECT_TYPE(objt);
535 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt)
536 {
537 DPRINT("GDIOBJ: wrong type. handle=%p, type=%x\n", hobj, objt);
538 return NULL;
539 }
540
541 /* Reference the handle entry */
542 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
543 if (!pentry)
544 {
545 DPRINT("GDIOBJ: requested handle 0x%p is not valid.\n", hobj);
546 return NULL;
547 }
548
549 /* Get the pointer to the BASEOBJECT */
550 pobj = pentry->einfo.pobj;
551
552 /* Check if the object is exclusively locked */
553 if (pobj->cExclusiveLock != 0)
554 {
555 DPRINT1("GDIOBJ: Cannot reference oject %p with exclusive lock.\n", hobj);
556 GDIOBJ_vDereferenceObject(pobj);
557 DBG_DUMP_EVENT_LIST(&pobj->slhLog);
558 return NULL;
559 }
560
561 DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, gpaulRefCount[pentry - gpentHmgr]);
562
563 /* All is well, return the object */
564 return pobj;
565 }
566
567 VOID
568 NTAPI
569 GDIOBJ_vReferenceObjectByPointer(POBJ pobj)
570 {
571 ULONG cRefs;
572
573 /* Must not be exclusively locked */
574 ASSERT(pobj->cExclusiveLock == 0);
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 ASSERT(pobj->cExclusiveLock > 0);
649
650 /* Decrease lock count */
651 pobj->cExclusiveLock--;
652 DBG_DECREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
653
654 /* Check if this was the last lock */
655 if (pobj->cExclusiveLock == 0)
656 {
657 /* Reset lock owner */
658 pobj->dwThreadId = 0;
659
660 /* Release the pushlock and reenable APCs */
661 ExReleasePushLockExclusive(&pobj->pushlock);
662 KeLeaveCriticalRegion();
663 }
664
665 /* Dereference the object */
666 DBG_LOGEVENT(&pobj->slhLog, EVENT_UNLOCK, 0);
667 GDIOBJ_vDereferenceObject(pobj);
668 }
669
670 HGDIOBJ
671 NTAPI
672 GDIOBJ_hInsertObject(
673 POBJ pobj,
674 ULONG ulOwner)
675 {
676 PENTRY pentry;
677 UCHAR objt;
678
679 /* Must have no handle and only one reference */
680 ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr) == 0);
681 ASSERT(pobj->cExclusiveLock == 0);
682 ASSERT(pobj->ulShareCount == 1);
683
684 /* Get a free handle entry */
685 pentry = ENTRY_pentPopFreeEntry();
686 if (!pentry)
687 {
688 DPRINT1("GDIOBJ: could not get a free entry.\n");
689 return NULL;
690 }
691
692 /* Make the object exclusively locked */
693 ExInitializePushLock(&pobj->pushlock);
694 KeEnterCriticalRegion();
695 ExAcquirePushLockExclusive(&pobj->pushlock);
696 pobj->cExclusiveLock = 1;
697 pobj->dwThreadId = PtrToUlong(PsGetCurrentThreadId());
698 DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
699
700 /* Get object type from the hHmgr field */
701 objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0xff;
702 ASSERT(objt != GDIObjType_DEF_TYPE);
703
704 /* Check if current process is requested owner */
705 if (ulOwner == GDI_OBJ_HMGR_POWNED)
706 {
707 /* Increment the process handle count */
708 IncrementGdiHandleCount();
709
710 /* Use Process id */
711 ulOwner = HandleToUlong(PsGetCurrentProcessId());
712 }
713
714 /* Insert the object into the handle table */
715 pobj->hHmgr = ENTRY_hInsertObject(pentry, pobj, objt, ulOwner);
716
717 /* Return the handle */
718 DPRINT("GDIOBJ: Created handle: %p\n", pobj->hHmgr);
719 DBG_LOGEVENT(&pobj->slhLog, EVENT_CREATE_HANDLE, 0);
720 return pobj->hHmgr;
721 }
722
723 VOID
724 NTAPI
725 GDIOBJ_vSetObjectOwner(
726 POBJ pobj,
727 ULONG ulOwner)
728 {
729 PENTRY pentry;
730
731 /* This is a ugly hack, need to fix IntGdiSetDCOwnerEx */
732 if (GDI_HANDLE_IS_STOCKOBJ(pobj->hHmgr))
733 {
734 DPRINT("Trying to set ownership of stock object %p to %lx\n", pobj->hHmgr, ulOwner);
735 return;
736 }
737
738 /* Get the handle entry */
739 ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr));
740 pentry = &gpentHmgr[GDI_HANDLE_GET_INDEX(pobj->hHmgr)];
741
742 /* Is the current process requested? */
743 if (ulOwner == GDI_OBJ_HMGR_POWNED)
744 {
745 /* Use process id */
746 ulOwner = HandleToUlong(PsGetCurrentProcessId());
747 if (pentry->ObjectOwner.ulObj != ulOwner)
748 {
749 IncrementGdiHandleCount();
750 }
751 }
752
753 // HACK
754 if (ulOwner == GDI_OBJ_HMGR_NONE)
755 ulOwner = GDI_OBJ_HMGR_PUBLIC;
756
757 if (ulOwner == GDI_OBJ_HMGR_PUBLIC ||
758 ulOwner == GDI_OBJ_HMGR_NONE)
759 {
760 /* Make sure we don't leak user mode memory */
761 ASSERT(pentry->pUser == NULL);
762 if (pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC &&
763 pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_NONE)
764 {
765 DecrementGdiHandleCount();
766 }
767 }
768
769 /* Set new owner */
770 pentry->ObjectOwner.ulObj = ulOwner;
771 }
772
773 /* Locks 2 or 3 objects at a time */
774 BOOL
775 NTAPI
776 GDIOBJ_bLockMultipleObjects(
777 IN ULONG ulCount,
778 IN HGDIOBJ* ahObj,
779 OUT PGDIOBJ* apObj,
780 IN UCHAR objt)
781 {
782 UINT auiIndices[3] = {0, 1, 2};
783 UINT i, j, tmp;
784
785 ASSERT(ulCount <= 3);
786
787 /* Sort the handles */
788 for (i = 0; i < ulCount - 1; i++)
789 {
790 for (j = i + 1; j < ulCount; j++)
791 {
792 if ((ULONG_PTR)ahObj[auiIndices[i]] <
793 (ULONG_PTR)ahObj[auiIndices[j]])
794 {
795 tmp = auiIndices[i];
796 auiIndices[i] = auiIndices[j];
797 auiIndices[j] = tmp;
798 }
799 }
800 }
801
802 /* Lock the objects in safe order */
803 for (i = 0; i < ulCount; i++)
804 {
805 /* Skip NULL handles */
806 if (ahObj[auiIndices[i]] == NULL)
807 {
808 apObj[auiIndices[i]] = NULL;
809 continue;
810 }
811
812 /* Lock the object */
813 apObj[auiIndices[i]] = GDIOBJ_LockObject(ahObj[auiIndices[i]], objt);
814
815 /* Check for failure */
816 if (apObj[auiIndices[i]] == NULL)
817 {
818 /* Cleanup */
819 while (i--)
820 {
821 if (apObj[auiIndices[i]])
822 GDIOBJ_vUnlockObject(apObj[auiIndices[i]]);
823 }
824 return FALSE;
825 }
826 }
827
828 return TRUE;
829 }
830
831 PVOID
832 NTAPI
833 GDIOBJ_pvGetObjectAttr(POBJ pobj)
834 {
835 ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
836 return gpentHmgr[ulIndex].pUser;
837 }
838
839 VOID
840 NTAPI
841 GDIOBJ_vSetObjectAttr(POBJ pobj, PVOID pvObjAttr)
842 {
843 ULONG ulIndex;
844
845 ASSERT(pobj->hHmgr);
846
847 /* Get the handle index */
848 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
849
850 /* Set pointer to the usermode attribute */
851 gpentHmgr[ulIndex].pUser = pvObjAttr;
852 }
853
854 VOID
855 NTAPI
856 GDIOBJ_vDeleteObject(POBJ pobj)
857 {
858 ULONG ulIndex;
859
860 /* Set the object's delete flag */
861 InterlockedOr16((SHORT*)&pobj->BaseFlags, BASEFLAG_READY_TO_DIE);
862 DBG_LOGEVENT(&pobj->slhLog, EVENT_DELETE, 0);
863
864 /* Get the handle index */
865 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
866 if (ulIndex)
867 {
868 /* Reset the handle valid bit */
869 InterlockedAnd((LONG*)&gpaulRefCount[ulIndex], ~REF_MASK_VALID);
870
871 /* Check if the object is exclusively locked */
872 if (pobj->cExclusiveLock != 0)
873 {
874 /* Reset lock owner and lock count */
875 pobj->dwThreadId = 0;
876 pobj->cExclusiveLock = 0;
877
878 /* Release the pushlock and reenable APCs */
879 ExReleasePushLockExclusive(&pobj->pushlock);
880 KeLeaveCriticalRegion();
881 }
882 }
883
884 /* Dereference the object (will take care of deletion) */
885 GDIOBJ_vDereferenceObject(pobj);
886 }
887
888 BOOL
889 NTAPI
890 GreIsHandleValid(HGDIOBJ hobj)
891 {
892 PENTRY pentry;
893
894 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
895 if (!pentry) return FALSE;
896 GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
897 return TRUE;
898 }
899
900 BOOL
901 NTAPI
902 GreDeleteObject(HGDIOBJ hobj)
903 {
904 PENTRY pentry;
905
906 /* Check for stock objects */
907 if (GDI_HANDLE_IS_STOCKOBJ(hobj))
908 {
909 DPRINT1("GreDeleteObject: Cannot delete stock object %p.\n", hobj);
910 return FALSE;
911 }
912
913 /* Reference the handle entry */
914 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
915 if (!pentry)
916 {
917 DPRINT1("GreDeleteObject: Trying to delete invalid object %p\n", hobj);
918 return FALSE;
919 }
920
921 /* Check for public owner */
922 if (pentry->ObjectOwner.ulObj == GDI_OBJ_HMGR_PUBLIC)
923 {
924 DPRINT1("GreDeleteObject: Trying to delete global object %p\n", hobj);
925 GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
926 return FALSE;
927 }
928
929 /* Delete the object */
930 GDIOBJ_vDeleteObject(pentry->einfo.pobj);
931 return TRUE;
932 }
933
934 ULONG
935 NTAPI
936 GreGetObjectOwner(HGDIOBJ hobj)
937 {
938 ULONG ulIndex, ulOwner;
939
940 /* Get the handle index */
941 ulIndex = GDI_HANDLE_GET_INDEX(hobj);
942
943 /* Check if the handle is valid */
944 if (ulIndex >= GDI_HANDLE_COUNT ||
945 gpentHmgr[ulIndex].Objt == GDIObjType_DEF_TYPE ||
946 ((ULONG_PTR)hobj >> 16) != gpentHmgr[ulIndex].FullUnique)
947 {
948 DPRINT1("GreGetObjectOwner: invalid handle 0x%p.\n", hobj);
949 return GDI_OBJ_HMGR_RESTRICTED;
950 }
951
952 /* Get the object owner */
953 ulOwner = gpentHmgr[ulIndex].ObjectOwner.ulObj;
954
955 if (ulOwner == HandleToUlong(PsGetCurrentProcessId()))
956 return GDI_OBJ_HMGR_POWNED;
957
958 if (ulOwner == GDI_OBJ_HMGR_PUBLIC)
959 return GDI_OBJ_HMGR_PUBLIC;
960
961 return GDI_OBJ_HMGR_RESTRICTED;
962 }
963
964 BOOL
965 NTAPI
966 GreSetObjectOwner(
967 HGDIOBJ hobj,
968 ULONG ulOwner)
969 {
970 PENTRY pentry;
971
972 /* Check for stock objects */
973 if (GDI_HANDLE_IS_STOCKOBJ(hobj))
974 {
975 DPRINT("GreSetObjectOwner: got stock object %p\n", hobj);
976 return FALSE;
977 }
978
979 /* Reference the handle entry */
980 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
981 if (!pentry)
982 {
983 DPRINT("GreSetObjectOwner: invalid handle 0x%p.\n", hobj);
984 return FALSE;
985 }
986
987 /* Call internal function */
988 GDIOBJ_vSetObjectOwner(pentry->einfo.pobj, ulOwner);
989
990 /* Dereference the object */
991 GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
992
993 return TRUE;
994 }
995
996 INT
997 NTAPI
998 GreGetObject(
999 IN HGDIOBJ hobj,
1000 IN INT cbCount,
1001 IN PVOID pvBuffer)
1002 {
1003 PVOID pvObj;
1004 UCHAR objt;
1005 INT iResult = 0;
1006
1007 /* Verify object type */
1008 objt = ((ULONG_PTR)hobj >> 16) & 0x1f;
1009 if (objt != GDIObjType_BRUSH_TYPE &&
1010 objt != GDIObjType_SURF_TYPE &&
1011 objt != GDIObjType_LFONT_TYPE &&
1012 objt != GDIObjType_PAL_TYPE)
1013 {
1014 DPRINT1("GreGetObject: invalid object type\n");
1015 return 0;
1016 }
1017
1018 pvObj = GDIOBJ_ReferenceObjectByHandle(hobj, objt);
1019 if (!pvObj)
1020 {
1021 DPRINT("GreGetObject: Could not lock object\n");
1022 EngSetLastError(ERROR_INVALID_HANDLE);
1023 return 0;
1024 }
1025
1026 switch (GDI_HANDLE_GET_TYPE(hobj))
1027 {
1028 case GDILoObjType_LO_PEN_TYPE:
1029 case GDILoObjType_LO_EXTPEN_TYPE:
1030 iResult = PEN_GetObject(pvObj, cbCount, pvBuffer);
1031 break;
1032
1033 case GDILoObjType_LO_BRUSH_TYPE:
1034 iResult = BRUSH_GetObject(pvObj, cbCount, pvBuffer);
1035 break;
1036
1037 case GDILoObjType_LO_BITMAP_TYPE:
1038 iResult = BITMAP_GetObject(pvObj, cbCount, pvBuffer);
1039 break;
1040 case GDILoObjType_LO_FONT_TYPE:
1041 iResult = FontGetObject(pvObj, cbCount, pvBuffer);
1042 #if 0
1043 // Fix the LOGFONT structure for the stock fonts
1044 if (FIRST_STOCK_HANDLE <= hobj && hobj <= LAST_STOCK_HANDLE)
1045 {
1046 FixStockFontSizeW(hobj, cbCount, pvBuffer);
1047 }
1048 #endif
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 INTERNAL_CALL
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 INTERNAL_CALL
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 INTERNAL_CALL
1224 GDIOBJ_AllocObjWithHandle(ULONG ObjectType, ULONG cjSize)
1225 {
1226 POBJ pobj;
1227 FLONG fl = 0;
1228 UCHAR objt = ObjectType >> 16;
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 INTERNAL_CALL
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 INTERNAL_CALL
1279 GDI_CleanupForProcess(struct _EPROCESS *Process)
1280 {
1281 PENTRY pentry;
1282 ULONG ulIndex;
1283 DWORD dwProcessId;
1284 PPROCESSINFO ppi;
1285
1286 DPRINT("CleanupForProcess prochandle %x Pid %d\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 //#ifdef GDI_DEBUG
1311 DbgGdiHTIntegrityCheck();
1312 //#endif
1313
1314 ppi = PsGetCurrentProcessWin32Process();
1315 DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);
1316 if (ppi->GDIHandleCount != 0)
1317 {
1318 DPRINT1("Leaking %d handles!\n", ppi->GDIHandleCount);
1319 ASSERT(FALSE);
1320 }
1321
1322 /* Loop all handles in the handle table */
1323 for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++)
1324 {
1325 pentry = &gpentHmgr[ulIndex];
1326
1327 /* Check if the object is owned by the process */
1328 if (pentry->ObjectOwner.ulObj == dwProcessId)
1329 {
1330 DPRINT1("Leaking object. Index=%lx, type=0x%x, refcount=%lx\n",
1331 ulIndex, pentry->Objt, gpaulRefCount[ulIndex]);
1332 DBG_DUMP_EVENT_LIST(&pentry->einfo.pobj->slhLog);
1333 //DBG_CLEANUP_EVENT_LIST(&pentry->einfo.pobj->slhLog);
1334 ASSERT(FALSE);
1335 }
1336 }
1337
1338 return TRUE;
1339 }
1340