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