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