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