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