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