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