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
InterlockedReadUlong(_In_ _Interlocked_operand_ ULONG volatile * Source)55 InterlockedReadUlong(
56 _In_ _Interlocked_operand_ ULONG volatile *Source)
57 {
58 return *Source;
59 }
60
61 FORCEINLINE
62 void
INCREASE_THREAD_LOCK_COUNT(_In_ HANDLE hobj)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
DECREASE_THREAD_LOCK_COUNT(_In_ HANDLE hobj)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
ASSERT_LOCK_ORDER(_In_ UCHAR objt)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
GDIOBJ_vCleanup(PVOID ObjectBody)238 GDIOBJ_vCleanup(PVOID ObjectBody)
239 {
240 /* Nothing to do */
241 }
242
243 static
244 VOID
InitLookasideList(UCHAR objt,ULONG cjSize)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 CODE_SEG("INIT")
257 NTSTATUS
258 NTAPI
InitGdiHandleTable(void)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
IncrementCurrentProcessGdiHandleCount(void)332 IncrementCurrentProcessGdiHandleCount(void)
333 {
334 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
335 if (ppi) InterlockedIncrement((LONG*)&ppi->GDIHandleCount);
336 }
337
338 FORCEINLINE
339 VOID
DecrementCurrentProcessGdiHandleCount(void)340 DecrementCurrentProcessGdiHandleCount(void)
341 {
342 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
343 if (ppi) InterlockedDecrement((LONG*)&ppi->GDIHandleCount);
344 }
345
346 static inline
347 VOID
IncrementGdiHandleCount(ULONG ulProcessId)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 static inline
364 VOID
DecrementGdiHandleCount(ULONG ulProcessId)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
ENTRY_pentPopFreeEntry(VOID)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
ENTRY_vPushFreeEntry(PENTRY pentFree)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
ENTRY_ReferenceEntryByHandle(HGDIOBJ hobj,FLONG fl)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 != NULL);
530
531 /* Check if lower 32 bits match, the upper 32 bits are ignored */
532 ASSERT(pentry->einfo.pobj->hHmgr == UlongToPtr(PtrToUlong(hobj)));
533
534 return pentry;
535 }
536
537 static
538 HGDIOBJ
ENTRY_hInsertObject(PENTRY pentry,POBJ pobj,UCHAR objt,ULONG ulOwner)539 ENTRY_hInsertObject(PENTRY pentry, POBJ pobj, UCHAR objt, ULONG ulOwner)
540 {
541 ULONG ulIndex;
542
543 /* Calculate the handle index */
544 ulIndex = pentry - gpentHmgr;
545
546 /* Update the fields in the ENTRY */
547 pentry->einfo.pobj = pobj;
548 pentry->Objt = objt & 0x1f;
549 pentry->FullUnique = (pentry->FullUnique & 0xff00) | objt;
550 pentry->ObjectOwner.ulObj = ulOwner;
551
552 /* Make the handle valid with 1 reference */
553 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_INUSE) == 0);
554 InterlockedOr((LONG*)&gpaulRefCount[ulIndex], REF_MASK_VALID | 1);
555
556 /* Return the handle */
557 return (HGDIOBJ)(((ULONG_PTR)pentry->FullUnique << 16) | ulIndex);
558 }
559
560 POBJ
561 NTAPI
GDIOBJ_AllocateObject(UCHAR objt,ULONG cjSize,FLONG fl)562 GDIOBJ_AllocateObject(UCHAR objt, ULONG cjSize, FLONG fl)
563 {
564 POBJ pobj;
565
566 if (fl & BASEFLAG_LOOKASIDE)
567 {
568 /* Allocate the object from a lookaside list */
569 pobj = ExAllocateFromPagedLookasideList(&gpaLookasideList[objt & 0x1f]);
570 }
571 else
572 {
573 /* Allocate the object from paged pool */
574 pobj = ExAllocatePoolWithTag(PagedPool, cjSize, GDIOBJ_POOL_TAG(objt));
575 }
576
577 if (!pobj) return NULL;
578
579 /* Initialize the object */
580 RtlZeroMemory(pobj, cjSize);
581 pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)objt << 16);
582 pobj->cExclusiveLock = 0;
583 pobj->ulShareCount = 1;
584 pobj->BaseFlags = fl & 0xffff;
585 DBG_INITLOG(&pobj->slhLog);
586 DBG_LOGEVENT(&pobj->slhLog, EVENT_ALLOCATE, 0);
587 #if DBG_ENABLE_GDIOBJ_BACKTRACES
588 DbgCaptureStackBackTace(pobj->apvBackTrace, 1, GDI_OBJECT_STACK_LEVELS);
589 #endif /* GDI_DEBUG */
590
591 return pobj;
592 }
593
594 VOID
595 NTAPI
GDIOBJ_vFreeObject(POBJ pobj)596 GDIOBJ_vFreeObject(POBJ pobj)
597 {
598 UCHAR objt;
599
600 DBG_CLEANUP_EVENT_LIST(&pobj->slhLog);
601
602 /* Get the object type */
603 objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0x1f;
604
605 /* Check if we have a delete procedure (for C++ based objects) */
606 if (apfnDelete[objt] != NULL)
607 {
608 /* Invoke the delete procedure */
609 apfnDelete[objt](pobj);
610 }
611 else
612 {
613 /* Call the cleanup procedure */
614 NT_ASSERT(apfnCleanup[objt]);
615 apfnCleanup[objt](pobj);
616
617 /* Check if the object is allocated from a lookaside list */
618 if (pobj->BaseFlags & BASEFLAG_LOOKASIDE)
619 {
620 ExFreeToPagedLookasideList(&gpaLookasideList[objt], pobj);
621 }
622 else
623 {
624 ExFreePoolWithTag(pobj, GDIOBJ_POOL_TAG(objt));
625 }
626 }
627 }
628
629 VOID
630 NTAPI
GDIOBJ_vDereferenceObject(POBJ pobj)631 GDIOBJ_vDereferenceObject(POBJ pobj)
632 {
633 ULONG cRefs, ulIndex;
634
635 /* Calculate the index */
636 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
637
638 /* Check if the object has a handle */
639 if (ulIndex)
640 {
641 /* Decrement reference count */
642 if ((gpaulRefCount[ulIndex] & REF_MASK_COUNT) == 0)
643 {
644 DBG_DUMP_EVENT_LIST(&pobj->slhLog);
645 }
646 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
647 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]);
648 DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs);
649
650 /* Check if we reached 0 and handle bit is not set */
651 if ((cRefs & REF_MASK_INUSE) == 0)
652 {
653 /* Make sure it's ok to delete the object */
654 ASSERT(pobj->BaseFlags & BASEFLAG_READY_TO_DIE);
655
656 /* Check if the handle was process owned */
657 if (gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC &&
658 gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_NONE)
659 {
660 /* Decrement the process handle count */
661 ASSERT(gpentHmgr[ulIndex].ObjectOwner.ulObj ==
662 HandleToUlong(PsGetCurrentProcessId()));
663 DecrementCurrentProcessGdiHandleCount();
664 }
665
666 /* Push entry to the free list */
667 ENTRY_vPushFreeEntry(&gpentHmgr[ulIndex]);
668
669 /* Free the object */
670 GDIOBJ_vFreeObject(pobj);
671 }
672 }
673 else
674 {
675 /* Decrement the objects reference count */
676 ASSERT(pobj->ulShareCount > 0);
677 cRefs = InterlockedDecrement((LONG*)&pobj->ulShareCount);
678 DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs);
679
680 /* Check if we reached 0 */
681 if (cRefs == 0)
682 {
683 /* Free the object */
684 GDIOBJ_vFreeObject(pobj);
685 }
686 }
687 }
688
689 POBJ
690 NTAPI
GDIOBJ_ReferenceObjectByHandle(HGDIOBJ hobj,UCHAR objt)691 GDIOBJ_ReferenceObjectByHandle(
692 HGDIOBJ hobj,
693 UCHAR objt)
694 {
695 PENTRY pentry;
696 POBJ pobj;
697
698 /* Check if the handle type matches */
699 ASSERT_SHARED_OBJECT_TYPE(objt);
700 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt)
701 {
702 DPRINT("GDIOBJ: Wrong type. handle=%p, type=%x\n", hobj, objt);
703 return NULL;
704 }
705
706 /* Reference the handle entry */
707 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
708 if (!pentry)
709 {
710 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj);
711 return NULL;
712 }
713
714 /* Get the pointer to the BASEOBJECT */
715 pobj = pentry->einfo.pobj;
716
717 /* Check if the object is exclusively locked */
718 if (pobj->cExclusiveLock != 0)
719 {
720 DPRINT1("GDIOBJ: Cannot reference object %p with exclusive lock.\n", hobj);
721 GDIOBJ_vDereferenceObject(pobj);
722 DBG_DUMP_EVENT_LIST(&pobj->slhLog);
723 return NULL;
724 }
725
726 DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, gpaulRefCount[pentry - gpentHmgr]);
727
728 /* All is well, return the object */
729 return pobj;
730 }
731
732 VOID
733 NTAPI
GDIOBJ_vReferenceObjectByPointer(POBJ pobj)734 GDIOBJ_vReferenceObjectByPointer(POBJ pobj)
735 {
736 ULONG cRefs;
737
738 /* Check if the object has a handle */
739 if (GDI_HANDLE_GET_INDEX(pobj->hHmgr))
740 {
741 /* Increase the handle's reference count */
742 ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
743 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
744 cRefs = InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]);
745 }
746 else
747 {
748 /* Increase the object's reference count */
749 cRefs = InterlockedIncrement((LONG*)&pobj->ulShareCount);
750 }
751
752 DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, cRefs);
753 }
754
755 PGDIOBJ
756 NTAPI
GDIOBJ_TryLockObject(HGDIOBJ hobj,UCHAR objt)757 GDIOBJ_TryLockObject(
758 HGDIOBJ hobj,
759 UCHAR objt)
760 {
761 PENTRY pentry;
762 POBJ pobj;
763 DWORD dwThreadId;
764
765 /* Check if the handle type matches */
766 ASSERT_TRYLOCK_OBJECT_TYPE(objt);
767 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt)
768 {
769 DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj, objt);
770 return NULL;
771 }
772
773 /* Make sure lock order is correct */
774 ASSERT_LOCK_ORDER(objt);
775
776 /* Reference the handle entry */
777 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
778 if (!pentry)
779 {
780 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj);
781 return NULL;
782 }
783
784 /* Get the pointer to the BASEOBJECT */
785 pobj = pentry->einfo.pobj;
786
787 /* Check if we already own the lock */
788 dwThreadId = PtrToUlong(PsGetCurrentThreadId());
789 if (pobj->dwThreadId != dwThreadId)
790 {
791 /* Disable APCs and try acquiring the push lock */
792 KeEnterCriticalRegion();
793 if(!ExTryAcquirePushLockExclusive(&pobj->pushlock))
794 {
795 ULONG cRefs, ulIndex;
796 /* Already owned. Clean up and leave. */
797 KeLeaveCriticalRegion();
798
799 /* Calculate the index */
800 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
801
802 /* Decrement reference count */
803 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
804 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]);
805 ASSERT(cRefs & REF_MASK_VALID);
806
807 return NULL;
808 }
809
810 /* Set us as lock owner */
811 ASSERT(pobj->dwThreadId == 0);
812 pobj->dwThreadId = dwThreadId;
813 }
814
815 /* Increase lock count */
816 pobj->cExclusiveLock++;
817 INCREASE_THREAD_LOCK_COUNT(hobj);
818 DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0);
819
820 /* Return the object */
821 return pobj;
822 }
823
824 PGDIOBJ
825 NTAPI
GDIOBJ_LockObject(HGDIOBJ hobj,UCHAR objt)826 GDIOBJ_LockObject(
827 HGDIOBJ hobj,
828 UCHAR objt)
829 {
830 PENTRY pentry;
831 POBJ pobj;
832 DWORD dwThreadId;
833
834 /* Check if the handle type matches */
835 ASSERT_EXCLUSIVE_OBJECT_TYPE(objt);
836 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt)
837 {
838 DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj, objt);
839 return NULL;
840 }
841
842 /* Make sure lock order is correct */
843 ASSERT_LOCK_ORDER(objt);
844
845 /* Reference the handle entry */
846 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
847 if (!pentry)
848 {
849 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj);
850 return NULL;
851 }
852
853 /* Get the pointer to the BASEOBJECT */
854 pobj = pentry->einfo.pobj;
855
856 /* Check if we already own the lock */
857 dwThreadId = PtrToUlong(PsGetCurrentThreadId());
858 if (pobj->dwThreadId != dwThreadId)
859 {
860 /* Disable APCs and acquire the push lock */
861 KeEnterCriticalRegion();
862 ExAcquirePushLockExclusive(&pobj->pushlock);
863
864 /* Set us as lock owner */
865 ASSERT(pobj->dwThreadId == 0);
866 pobj->dwThreadId = dwThreadId;
867 }
868
869 /* Increase lock count */
870 pobj->cExclusiveLock++;
871 INCREASE_THREAD_LOCK_COUNT(hobj);
872 DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0);
873
874 /* Return the object */
875 return pobj;
876 }
877
878 VOID
879 NTAPI
GDIOBJ_vUnlockObject(POBJ pobj)880 GDIOBJ_vUnlockObject(POBJ pobj)
881 {
882 ULONG cRefs, ulIndex;
883 ASSERT(pobj->cExclusiveLock > 0);
884
885 /* Decrease lock count */
886 pobj->cExclusiveLock--;
887 DECREASE_THREAD_LOCK_COUNT(pobj->hHmgr);
888 DBG_LOGEVENT(&pobj->slhLog, EVENT_UNLOCK, 0);
889
890 /* Check if this was the last lock */
891 if (pobj->cExclusiveLock == 0)
892 {
893 /* Reset lock owner */
894 pobj->dwThreadId = 0;
895
896 /* Release the pushlock and reenable APCs */
897 ExReleasePushLockExclusive(&pobj->pushlock);
898 KeLeaveCriticalRegion();
899 }
900
901 /* Calculate the index */
902 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
903
904 /* Decrement reference count */
905 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
906 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]);
907 ASSERT(cRefs & REF_MASK_VALID);
908 }
909
910 HGDIOBJ
911 NTAPI
GDIOBJ_hInsertObject(POBJ pobj,ULONG ulOwner)912 GDIOBJ_hInsertObject(
913 POBJ pobj,
914 ULONG ulOwner)
915 {
916 PENTRY pentry;
917 UCHAR objt;
918
919 /* Must have no handle and only one reference */
920 ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr) == 0);
921 ASSERT(pobj->cExclusiveLock == 0);
922 ASSERT(pobj->ulShareCount == 1);
923
924 /* Get a free handle entry */
925 pentry = ENTRY_pentPopFreeEntry();
926 if (!pentry)
927 {
928 DPRINT1("GDIOBJ: Could not get a free entry.\n");
929 return NULL;
930 }
931
932 /* Make the object exclusively locked */
933 ExInitializePushLock(&pobj->pushlock);
934 KeEnterCriticalRegion();
935 ExAcquirePushLockExclusive(&pobj->pushlock);
936 pobj->cExclusiveLock = 1;
937 pobj->dwThreadId = PtrToUlong(PsGetCurrentThreadId());
938 INCREASE_THREAD_LOCK_COUNT(pobj->hHmgr);
939
940 /* Get object type from the hHmgr field */
941 objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0xff;
942 ASSERT(objt != GDIObjType_DEF_TYPE);
943
944 /* Check if current process is requested owner */
945 if (ulOwner == GDI_OBJ_HMGR_POWNED)
946 {
947 /* Increment the process handle count */
948 IncrementCurrentProcessGdiHandleCount();
949
950 /* Use Process id */
951 ulOwner = HandleToUlong(PsGetCurrentProcessId());
952 }
953
954 /* Insert the object into the handle table */
955 pobj->hHmgr = ENTRY_hInsertObject(pentry, pobj, objt, ulOwner);
956
957 /* Return the handle */
958 DPRINT("GDIOBJ: Created handle: %p\n", pobj->hHmgr);
959 DBG_LOGEVENT(&pobj->slhLog, EVENT_CREATE_HANDLE, 0);
960 return pobj->hHmgr;
961 }
962
963 VOID
964 NTAPI
GDIOBJ_vSetObjectOwner(POBJ pobj,ULONG ulNewOwner)965 GDIOBJ_vSetObjectOwner(
966 POBJ pobj,
967 ULONG ulNewOwner)
968 {
969 PENTRY pentry;
970 ULONG ulOldOwner;
971
972 /* This is a ugly HACK, needed to fix IntGdiSetDCOwnerEx */
973 if (GDI_HANDLE_IS_STOCKOBJ(pobj->hHmgr))
974 {
975 DPRINT("Trying to set ownership of stock object %p to %lx\n", pobj->hHmgr, ulNewOwner);
976 return;
977 }
978
979 /* Get the handle entry */
980 NT_ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr));
981 pentry = &gpentHmgr[GDI_HANDLE_GET_INDEX(pobj->hHmgr)];
982
983 /* Check if the new owner is the same as the old one */
984 ulOldOwner = pentry->ObjectOwner.ulObj;
985 if (ulOldOwner == ulNewOwner)
986 {
987 /* Nothing to do */
988 return;
989 }
990
991 /* Is the current process requested? */
992 if (ulNewOwner == GDI_OBJ_HMGR_POWNED)
993 {
994 /* Use process id */
995 ulNewOwner = HandleToUlong(PsGetCurrentProcessId());
996 }
997
998 // HACK
999 if (ulNewOwner == GDI_OBJ_HMGR_NONE)
1000 ulNewOwner = GDI_OBJ_HMGR_PUBLIC;
1001
1002 /* Was the object process owned? */
1003 if ((ulOldOwner != GDI_OBJ_HMGR_PUBLIC) &&
1004 (ulOldOwner != GDI_OBJ_HMGR_NONE))
1005 {
1006 /* Decrement the previous owners handle count */
1007 DecrementGdiHandleCount(ulOldOwner);
1008 }
1009
1010 /* Is the new owner a process? */
1011 if ((ulNewOwner != GDI_OBJ_HMGR_PUBLIC) &&
1012 (ulNewOwner != GDI_OBJ_HMGR_NONE))
1013 {
1014 /* Increment the new owners handle count */
1015 IncrementGdiHandleCount(ulNewOwner);
1016 }
1017 else
1018 {
1019 /* Make sure we don't leak user mode memory */
1020 NT_ASSERT(pentry->pUser == NULL);
1021 }
1022
1023 /* Set new owner */
1024 pentry->ObjectOwner.ulObj = ulNewOwner;
1025 DBG_LOGEVENT(&pobj->slhLog, EVENT_SET_OWNER, 0);
1026 }
1027
1028 /* Locks 2 or 3 objects at a time */
1029 BOOL
1030 NTAPI
GDIOBJ_bLockMultipleObjects(IN ULONG ulCount,IN HGDIOBJ * ahObj,OUT PGDIOBJ * apObj,IN UCHAR objt)1031 GDIOBJ_bLockMultipleObjects(
1032 IN ULONG ulCount,
1033 IN HGDIOBJ* ahObj,
1034 OUT PGDIOBJ* apObj,
1035 IN UCHAR objt)
1036 {
1037 UINT auiIndices[3] = {0, 1, 2};
1038 UINT i, j, tmp;
1039
1040 ASSERT(ulCount <= 3);
1041
1042 /* Sort the handles */
1043 for (i = 0; i < ulCount - 1; i++)
1044 {
1045 for (j = i + 1; j < ulCount; j++)
1046 {
1047 if ((ULONG_PTR)ahObj[auiIndices[i]] <
1048 (ULONG_PTR)ahObj[auiIndices[j]])
1049 {
1050 tmp = auiIndices[i];
1051 auiIndices[i] = auiIndices[j];
1052 auiIndices[j] = tmp;
1053 }
1054 }
1055 }
1056
1057 /* Lock the objects in safe order */
1058 for (i = 0; i < ulCount; i++)
1059 {
1060 /* Skip NULL handles */
1061 if (ahObj[auiIndices[i]] == NULL)
1062 {
1063 apObj[auiIndices[i]] = NULL;
1064 continue;
1065 }
1066
1067 /* Lock the object */
1068 apObj[auiIndices[i]] = GDIOBJ_LockObject(ahObj[auiIndices[i]], objt);
1069
1070 /* Check for failure */
1071 if (apObj[auiIndices[i]] == NULL)
1072 {
1073 /* Cleanup */
1074 while (i--)
1075 {
1076 if (apObj[auiIndices[i]])
1077 GDIOBJ_vUnlockObject(apObj[auiIndices[i]]);
1078 }
1079 return FALSE;
1080 }
1081 }
1082
1083 return TRUE;
1084 }
1085
1086 PVOID
1087 NTAPI
GDIOBJ_pvGetObjectAttr(POBJ pobj)1088 GDIOBJ_pvGetObjectAttr(POBJ pobj)
1089 {
1090 ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
1091 return gpentHmgr[ulIndex].pUser;
1092 }
1093
1094 VOID
1095 NTAPI
GDIOBJ_vSetObjectAttr(POBJ pobj,PVOID pvObjAttr)1096 GDIOBJ_vSetObjectAttr(POBJ pobj, PVOID pvObjAttr)
1097 {
1098 ULONG ulIndex;
1099
1100 ASSERT(pobj->hHmgr);
1101
1102 /* Get the handle index */
1103 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
1104
1105 /* Set pointer to the usermode attribute */
1106 gpentHmgr[ulIndex].pUser = pvObjAttr;
1107 }
1108
1109 VOID
1110 NTAPI
GDIOBJ_vDeleteObject(POBJ pobj)1111 GDIOBJ_vDeleteObject(POBJ pobj)
1112 {
1113 ULONG ulIndex;
1114
1115 /* Set the object's delete flag */
1116 InterlockedOr16((SHORT*)&pobj->BaseFlags, BASEFLAG_READY_TO_DIE);
1117 DBG_LOGEVENT(&pobj->slhLog, EVENT_DELETE, 0);
1118
1119 /* Get the handle index */
1120 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
1121 if (ulIndex)
1122 {
1123 /* Reset the handle valid bit */
1124 InterlockedAnd((LONG*)&gpaulRefCount[ulIndex], ~REF_MASK_VALID);
1125
1126 /* Check if the object is exclusively locked */
1127 if (pobj->cExclusiveLock != 0)
1128 {
1129 /* Reset lock owner and lock count */
1130 pobj->dwThreadId = 0;
1131 pobj->cExclusiveLock = 0;
1132
1133 /* Release the pushlock and reenable APCs */
1134 ExReleasePushLockExclusive(&pobj->pushlock);
1135 KeLeaveCriticalRegion();
1136 DECREASE_THREAD_LOCK_COUNT(pobj->hHmgr);
1137 }
1138 }
1139
1140 /* Dereference the object (will take care of deletion) */
1141 GDIOBJ_vDereferenceObject(pobj);
1142 }
1143
1144 BOOL
1145 NTAPI
GreIsHandleValid(HGDIOBJ hobj)1146 GreIsHandleValid(HGDIOBJ hobj)
1147 {
1148 PENTRY pentry;
1149
1150 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
1151 if (!pentry) return FALSE;
1152 GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
1153 return TRUE;
1154 }
1155
1156 BOOL
1157 NTAPI
GreDeleteObject(HGDIOBJ hobj)1158 GreDeleteObject(HGDIOBJ hobj)
1159 {
1160 PENTRY pentry;
1161
1162 /* Check for stock objects */
1163 if (GDI_HANDLE_IS_STOCKOBJ(hobj))
1164 {
1165 DPRINT1("GreDeleteObject: Cannot delete stock object %p.\n", hobj);
1166 return FALSE;
1167 }
1168
1169 /* Reference the handle entry */
1170 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
1171 if (!pentry)
1172 {
1173 DPRINT1("GreDeleteObject: Trying to delete invalid object %p\n", hobj);
1174 return FALSE;
1175 }
1176
1177 /* Check for public owner */
1178 if (pentry->ObjectOwner.ulObj == GDI_OBJ_HMGR_PUBLIC)
1179 {
1180 DPRINT1("GreDeleteObject: Trying to delete global object %p\n", hobj);
1181 GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
1182 return FALSE;
1183 }
1184
1185 /* Delete the object */
1186 GDIOBJ_vDeleteObject(pentry->einfo.pobj);
1187 return TRUE;
1188 }
1189
1190 ULONG
1191 NTAPI
GreGetObjectOwner(HGDIOBJ hobj)1192 GreGetObjectOwner(HGDIOBJ hobj)
1193 {
1194 ULONG ulIndex, ulOwner;
1195
1196 /* Get the handle index */
1197 ulIndex = GDI_HANDLE_GET_INDEX(hobj);
1198
1199 /* Check if the handle is valid */
1200 if (ulIndex >= GDI_HANDLE_COUNT ||
1201 gpentHmgr[ulIndex].Objt == GDIObjType_DEF_TYPE ||
1202 ((ULONG_PTR)hobj >> 16) != gpentHmgr[ulIndex].FullUnique)
1203 {
1204 DPRINT1("GreGetObjectOwner: invalid handle 0x%p.\n", hobj);
1205 return GDI_OBJ_HMGR_RESTRICTED;
1206 }
1207
1208 /* Get the object owner */
1209 ulOwner = gpentHmgr[ulIndex].ObjectOwner.ulObj;
1210
1211 if (ulOwner == HandleToUlong(PsGetCurrentProcessId()))
1212 return GDI_OBJ_HMGR_POWNED;
1213
1214 if (ulOwner == GDI_OBJ_HMGR_PUBLIC)
1215 return GDI_OBJ_HMGR_PUBLIC;
1216
1217 return GDI_OBJ_HMGR_RESTRICTED;
1218 }
1219
1220 BOOL
1221 NTAPI
GreSetObjectOwnerEx(HGDIOBJ hobj,ULONG ulOwner,ULONG Flags)1222 GreSetObjectOwnerEx(
1223 HGDIOBJ hobj,
1224 ULONG ulOwner,
1225 ULONG Flags)
1226 {
1227 PENTRY pentry;
1228
1229 /* Check for stock objects */
1230 if (GDI_HANDLE_IS_STOCKOBJ(hobj))
1231 {
1232 DPRINT("GreSetObjectOwner: Got stock object %p\n", hobj);
1233 return FALSE;
1234 }
1235
1236 /* Reference the handle entry */
1237 pentry = ENTRY_ReferenceEntryByHandle(hobj, Flags);
1238 if (!pentry)
1239 {
1240 DPRINT("GreSetObjectOwner: Invalid handle 0x%p.\n", hobj);
1241 return FALSE;
1242 }
1243
1244 /* Call internal function */
1245 GDIOBJ_vSetObjectOwner(pentry->einfo.pobj, ulOwner);
1246
1247 /* Dereference the object */
1248 GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
1249
1250 return TRUE;
1251 }
1252
1253 BOOL
1254 NTAPI
GreSetObjectOwner(HGDIOBJ hobj,ULONG ulOwner)1255 GreSetObjectOwner(
1256 HGDIOBJ hobj,
1257 ULONG ulOwner)
1258 {
1259 return GreSetObjectOwnerEx(hobj, ulOwner, 0);
1260 }
1261
1262 INT
1263 NTAPI
GreGetObject(IN HGDIOBJ hobj,IN INT cbCount,OUT PVOID pvBuffer)1264 GreGetObject(
1265 IN HGDIOBJ hobj,
1266 IN INT cbCount,
1267 OUT PVOID pvBuffer)
1268 {
1269 PVOID pvObj;
1270 UCHAR objt;
1271 INT iResult = 0;
1272
1273 /* Verify object type */
1274 objt = ((ULONG_PTR)hobj >> 16) & 0x1f;
1275 if (objt != GDIObjType_BRUSH_TYPE &&
1276 objt != GDIObjType_SURF_TYPE &&
1277 objt != GDIObjType_LFONT_TYPE &&
1278 objt != GDIObjType_PAL_TYPE)
1279 {
1280 DPRINT1("GreGetObject: Invalid object type\n");
1281 return 0;
1282 }
1283
1284 pvObj = GDIOBJ_ReferenceObjectByHandle(hobj, objt);
1285 if (!pvObj)
1286 {
1287 DPRINT("GreGetObject: Could not lock object\n");
1288 return 0;
1289 }
1290
1291 switch (GDI_HANDLE_GET_TYPE(hobj))
1292 {
1293 case GDILoObjType_LO_PEN_TYPE:
1294 case GDILoObjType_LO_EXTPEN_TYPE:
1295 iResult = PEN_GetObject(pvObj, cbCount, pvBuffer);
1296 break;
1297
1298 case GDILoObjType_LO_BRUSH_TYPE:
1299 iResult = BRUSH_GetObject(pvObj, cbCount, pvBuffer);
1300 break;
1301
1302 case GDILoObjType_LO_BITMAP_TYPE:
1303 iResult = BITMAP_GetObject(pvObj, cbCount, pvBuffer);
1304 break;
1305
1306 case GDILoObjType_LO_FONT_TYPE:
1307 iResult = FontGetObject(pvObj, cbCount, pvBuffer);
1308 break;
1309
1310 case GDILoObjType_LO_PALETTE_TYPE:
1311 iResult = PALETTE_GetObject(pvObj, cbCount, pvBuffer);
1312 break;
1313
1314 default:
1315 DPRINT1("GDI object type of 0x%p not implemented\n", hobj);
1316 break;
1317 }
1318
1319 GDIOBJ_vDereferenceObject(pvObj);
1320 return iResult;
1321 }
1322
1323 W32KAPI
1324 INT
1325 APIENTRY
NtGdiExtGetObjectW(IN HANDLE hobj,IN INT cjBufferSize,OUT LPVOID lpBuffer)1326 NtGdiExtGetObjectW(
1327 IN HANDLE hobj,
1328 IN INT cjBufferSize,
1329 OUT LPVOID lpBuffer)
1330 {
1331 UINT iResult, cjMaxSize;
1332 union
1333 {
1334 BITMAP bitmap;
1335 DIBSECTION dibsection;
1336 LOGPEN logpen;
1337 LOGBRUSH logbrush;
1338 LOGFONTW logfontw;
1339 EXTLOGFONTW extlogfontw;
1340 ENUMLOGFONTEXDVW enumlogfontexdvw;
1341 } object;
1342
1343 /* Normalize to the largest supported object size */
1344 cjMaxSize = min((UINT)cjBufferSize, sizeof(object));
1345
1346 /* Now do the actual call */
1347 iResult = GreGetObject(hobj, cjMaxSize, lpBuffer ? &object : NULL);
1348
1349 /* Check if we have a buffer and data */
1350 if ((lpBuffer != NULL) && (iResult != 0))
1351 {
1352 /* Enter SEH for buffer transfer */
1353 _SEH2_TRY
1354 {
1355 /* Probe the buffer and copy it */
1356 cjMaxSize = min(cjMaxSize, iResult);
1357 ProbeForWrite(lpBuffer, cjMaxSize, sizeof(WORD));
1358 RtlCopyMemory(lpBuffer, &object, cjMaxSize);
1359 }
1360 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1361 {
1362 /* Clear the return value.
1363 * Do *NOT* set last error here! */
1364 iResult = 0;
1365 }
1366 _SEH2_END;
1367 }
1368
1369 /* Return the count */
1370 return iResult;
1371 }
1372
1373 W32KAPI
1374 HANDLE
1375 APIENTRY
NtGdiCreateClientObj(IN ULONG ulType)1376 NtGdiCreateClientObj(
1377 IN ULONG ulType)
1378 {
1379 POBJ pObject;
1380 HANDLE handle;
1381
1382 /* Check if ulType is valid */
1383 if ((ulType != GDILoObjType_LO_METAFILE16_TYPE) &&
1384 (ulType != GDILoObjType_LO_METAFILE_TYPE) &&
1385 (ulType != GDILoObjType_LO_METADC16_TYPE))
1386 {
1387 DPRINT1("NtGdiCreateClientObj: Invalid object type 0x%lx.\n", ulType);
1388 return NULL;
1389 }
1390
1391 /* Allocate a new object */
1392 pObject = GDIOBJ_AllocateObject(GDIObjType_CLIENTOBJ_TYPE,
1393 sizeof(CLIENTOBJ),
1394 BASEFLAG_LOOKASIDE);
1395 if (!pObject)
1396 {
1397 DPRINT1("NtGdiCreateClientObj: Could not allocate a clientobj.\n");
1398 return NULL;
1399 }
1400
1401 /* Set the real object type */
1402 pObject->hHmgr = UlongToHandle(ulType | GDILoObjType_LO_CLIENTOBJ_TYPE);
1403
1404 /* Create a handle */
1405 handle = GDIOBJ_hInsertObject(pObject, GDI_OBJ_HMGR_POWNED);
1406 if (!handle)
1407 {
1408 DPRINT1("NtGdiCreateClientObj: Could not create a handle.\n");
1409 GDIOBJ_vFreeObject(pObject);
1410 return NULL;
1411 }
1412
1413 /* Unlock it */
1414 GDIOBJ_vUnlockObject(pObject);
1415
1416 return handle;
1417 }
1418
1419 W32KAPI
1420 BOOL
1421 APIENTRY
NtGdiDeleteClientObj(IN HANDLE hobj)1422 NtGdiDeleteClientObj(
1423 IN HANDLE hobj)
1424 {
1425 /* We first need to get the real type from the handle */
1426 ULONG ulType = GDI_HANDLE_GET_TYPE(hobj);
1427
1428 /* Check if it's really a CLIENTOBJ */
1429 if ((ulType & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE)
1430 {
1431 /* FIXME: SetLastError? */
1432 return FALSE;
1433 }
1434
1435 return GreDeleteObject(hobj);
1436 }
1437
1438
1439
1440 PGDI_HANDLE_TABLE GdiHandleTable = NULL;
1441
1442 PGDIOBJ NTAPI
GDIOBJ_ShareLockObj(HGDIOBJ hObj,DWORD ExpectedType)1443 GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
1444 {
1445 if (ExpectedType == GDI_OBJECT_TYPE_DONTCARE)
1446 ExpectedType = GDI_HANDLE_GET_TYPE(hObj);
1447 return GDIOBJ_ReferenceObjectByHandle(hObj, (ExpectedType >> 16) & 0x1f);
1448 }
1449
1450 // This function is not safe to use with concurrent deleting attempts
1451 // That shouldn't be a problem, since we don't have any processes yet,
1452 // that could delete the handle
1453 BOOL
1454 NTAPI
GDIOBJ_ConvertToStockObj(HGDIOBJ * phObj)1455 GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
1456 {
1457 PENTRY pentry;
1458 POBJ pobj;
1459
1460 /* Reference the handle entry */
1461 pentry = ENTRY_ReferenceEntryByHandle(*phObj, 0);
1462 if (!pentry)
1463 {
1464 DPRINT1("GDIOBJ: Requested handle 0x%p is not valid.\n", *phObj);
1465 return FALSE;
1466 }
1467
1468 /* Update the entry */
1469 pentry->FullUnique |= GDI_ENTRY_STOCK_MASK;
1470 pentry->ObjectOwner.ulObj = 0;
1471
1472 /* Get the pointer to the BASEOBJECT */
1473 pobj = pentry->einfo.pobj;
1474
1475 /* Calculate the new handle */
1476 pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)pobj->hHmgr | GDI_HANDLE_STOCK_MASK);
1477
1478 /* Return the new handle */
1479 *phObj = pobj->hHmgr;
1480
1481 /* Dereference the handle */
1482 GDIOBJ_vDereferenceObject(pobj);
1483
1484 return TRUE;
1485 }
1486
1487 BOOL
1488 NTAPI
GDIOBJ_ConvertFromStockObj(HGDIOBJ * phObj)1489 GDIOBJ_ConvertFromStockObj(HGDIOBJ *phObj)
1490 {
1491 PENTRY pentry;
1492 POBJ pobj;
1493
1494 /* Reference the handle entry */
1495 pentry = ENTRY_ReferenceEntryByHandle(*phObj, 0);
1496 if (!pentry)
1497 {
1498 DPRINT1("GDIOBJ: Requested handle 0x%p is not valid.\n", *phObj);
1499 return FALSE;
1500 }
1501
1502 /* Update the entry */
1503 pentry->FullUnique &= ~GDI_ENTRY_STOCK_MASK;
1504 pentry->ObjectOwner.ulObj = PtrToUlong(PsGetCurrentProcessId());
1505
1506 /* Get the pointer to the BASEOBJECT */
1507 pobj = pentry->einfo.pobj;
1508
1509 /* Calculate the new handle */
1510 pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)pobj->hHmgr & ~GDI_HANDLE_STOCK_MASK);
1511
1512 /* Return the new handle */
1513 *phObj = pobj->hHmgr;
1514
1515 /* Dereference the handle */
1516 GDIOBJ_vDereferenceObject(pobj);
1517
1518 return TRUE;
1519 }
1520
1521 POBJ NTAPI
GDIOBJ_AllocObjWithHandle(ULONG ObjectType,ULONG cjSize)1522 GDIOBJ_AllocObjWithHandle(ULONG ObjectType, ULONG cjSize)
1523 {
1524 POBJ pobj;
1525 FLONG fl = 0;
1526 UCHAR objt = (ObjectType >> 16) & 0xFF;
1527
1528 if ((objt == GDIObjType_DC_TYPE && cjSize == sizeof(DC)) ||
1529 (objt == GDIObjType_PAL_TYPE && cjSize == sizeof(PALETTE)) ||
1530 (objt == GDIObjType_RGN_TYPE && cjSize == sizeof(REGION)) ||
1531 (objt == GDIObjType_SURF_TYPE && cjSize == sizeof(SURFACE)) ||
1532 (objt == GDIObjType_PATH_TYPE && cjSize == sizeof(PATH)))
1533 {
1534 fl |= BASEFLAG_LOOKASIDE;
1535 }
1536
1537 pobj = GDIOBJ_AllocateObject(objt, cjSize, fl);
1538 if (!pobj)
1539 {
1540 return NULL;
1541 }
1542
1543 if (!GDIOBJ_hInsertObject(pobj, GDI_OBJ_HMGR_POWNED))
1544 {
1545 GDIOBJ_vFreeObject(pobj);
1546 return NULL;
1547 }
1548 return pobj;
1549 }
1550
1551 PVOID NTAPI
GDI_MapHandleTable(PEPROCESS pProcess)1552 GDI_MapHandleTable(PEPROCESS pProcess)
1553 {
1554 PVOID pvMappedView = NULL;
1555 NTSTATUS Status;
1556 LARGE_INTEGER liOffset;
1557 SIZE_T cjViewSize = sizeof(GDI_HANDLE_TABLE);
1558
1559 liOffset.QuadPart = 0;
1560
1561 ASSERT(gpvGdiHdlTblSection != NULL);
1562 ASSERT(pProcess != NULL);
1563
1564 Status = MmMapViewOfSection(gpvGdiHdlTblSection,
1565 pProcess,
1566 &pvMappedView,
1567 0,
1568 0,
1569 &liOffset,
1570 &cjViewSize,
1571 ViewUnmap,
1572 SEC_NO_CHANGE,
1573 PAGE_READONLY);
1574
1575 if (!NT_SUCCESS(Status))
1576 return NULL;
1577
1578 return pvMappedView;
1579 }
1580
1581 BOOL NTAPI
GDI_CleanupForProcess(struct _EPROCESS * Process)1582 GDI_CleanupForProcess(struct _EPROCESS *Process)
1583 {
1584 PENTRY pentry;
1585 ULONG ulIndex;
1586 DWORD dwProcessId;
1587 PPROCESSINFO ppi;
1588
1589 DPRINT("CleanupForProcess prochandle %p Pid %p\n",
1590 Process, Process->UniqueProcessId);
1591
1592 ASSERT(Process == PsGetCurrentProcess());
1593
1594 /* Get the current process Id */
1595 dwProcessId = PtrToUlong(PsGetCurrentProcessId());
1596
1597 /* Loop all handles in the handle table */
1598 for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++)
1599 {
1600 pentry = &gpentHmgr[ulIndex];
1601
1602 /* Check if the object is owned by the process */
1603 if (pentry->ObjectOwner.ulObj == dwProcessId)
1604 {
1605 ASSERT(pentry->einfo.pobj->cExclusiveLock == 0);
1606
1607 /* Reference the object and delete it */
1608 InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]);
1609 GDIOBJ_vDeleteObject(pentry->einfo.pobj);
1610 }
1611 }
1612
1613 #if DBG
1614 DbgGdiHTIntegrityCheck();
1615 #endif
1616
1617 ppi = PsGetCurrentProcessWin32Process();
1618 DPRINT("Completed cleanup for process %p\n", Process->UniqueProcessId);
1619 if (ppi->GDIHandleCount != 0)
1620 {
1621 DPRINT1("Leaking %d handles!\n", ppi->GDIHandleCount);
1622 ASSERT(FALSE);
1623 }
1624
1625 /* Loop all handles in the handle table */
1626 for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++)
1627 {
1628 pentry = &gpentHmgr[ulIndex];
1629
1630 /* Check if the object is owned by the process */
1631 if (pentry->ObjectOwner.ulObj == dwProcessId)
1632 {
1633 DPRINT1("Leaking object. Index=%lx, type=0x%x, refcount=%lx\n",
1634 ulIndex, pentry->Objt, gpaulRefCount[ulIndex]);
1635 DBG_DUMP_EVENT_LIST(&pentry->einfo.pobj->slhLog);
1636 //DBG_CLEANUP_EVENT_LIST(&pentry->einfo.pobj->slhLog);
1637 ASSERT(FALSE);
1638 }
1639 }
1640
1641 return TRUE;
1642 }
1643
1644 /// HACK!
1645 PGDI_POOL
GetBrushAttrPool(VOID)1646 GetBrushAttrPool(VOID)
1647 {
1648 PPROCESSINFO ppi;
1649
1650 ppi = PsGetCurrentProcessWin32Process();
1651 NT_ASSERT(ppi != NULL);
1652
1653 return ppi->pPoolBrushAttr;
1654 }
1655
1656 /* EOF */
1657