[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / 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: ...
7 */
8
9 /** INCLUDES ******************************************************************/
10
11 #include <win32k.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #define GDI_ENTRY_TO_INDEX(ht, e) \
16 (((ULONG_PTR)(e) - (ULONG_PTR)&((ht)->Entries[0])) / sizeof(GDI_TABLE_ENTRY))
17 #define GDI_HANDLE_GET_ENTRY(HandleTable, h) \
18 (&(HandleTable)->Entries[GDI_HANDLE_GET_INDEX((h))])
19
20 #define BASE_OBJTYPE_COUNT 32
21
22 #define DelayExecution() \
23 DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
24 KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
25
26 static
27 BOOL INTERNAL_CALL GDI_CleanupDummy(PVOID ObjectBody);
28
29 /** GLOBALS *******************************************************************/
30
31 typedef struct
32 {
33 BOOL bUseLookaside;
34 ULONG_PTR ulBodySize;
35 ULONG Tag;
36 GDICLEANUPPROC CleanupProc;
37 } OBJ_TYPE_INFO, *POBJ_TYPE_INFO;
38
39 static const
40 OBJ_TYPE_INFO ObjTypeInfo[BASE_OBJTYPE_COUNT] =
41 {
42 {0, 0, 0, NULL}, /* 00 reserved entry */
43 {1, sizeof(DC), TAG_DC, DC_Cleanup}, /* 01 DC */
44 {1, 0, 0, NULL}, /* 02 UNUSED1 */
45 {1, 0, 0, NULL}, /* 03 UNUSED2 */
46 {1, sizeof(ROSRGNDATA), TAG_REGION, REGION_Cleanup}, /* 04 RGN */
47 {1, sizeof(SURFACE), TAG_SURFACE, SURFACE_Cleanup}, /* 05 SURFACE */
48 {1, sizeof(CLIENTOBJ), TAG_CLIENTOBJ, GDI_CleanupDummy}, /* 06 CLIENTOBJ: METADC,... */
49 {1, sizeof(PATH), TAG_PATH, GDI_CleanupDummy}, /* 07 PATH */
50 {1, sizeof(PALETTE), TAG_PALETTE, PALETTE_Cleanup}, /* 08 PAL */
51 {1, sizeof(COLORSPACE), TAG_ICMLCS, GDI_CleanupDummy}, /* 09 ICMLCS, */
52 {1, sizeof(TEXTOBJ), TAG_LFONT, GDI_CleanupDummy}, /* 0a LFONT */
53 {0, 0, TAG_RFONT, NULL}, /* 0b RFONT, unused */
54 {0, 0, TAG_PFE, NULL}, /* 0c PFE, unused */
55 {0, 0, TAG_PFT, NULL}, /* 0d PFT, unused */
56 {0, sizeof(GDICLRXFORM), TAG_ICMCXF, GDI_CleanupDummy}, /* 0e ICMCXF, */
57 {0, 0, TAG_SPRITE, NULL}, /* 0f SPRITE, unused */
58 {1, sizeof(BRUSH), TAG_BRUSH, BRUSH_Cleanup}, /* 10 BRUSH, PEN, EXTPEN */
59 {0, 0, TAG_UMPD, NULL}, /* 11 UMPD, unused */
60 {0, 0, 0, NULL}, /* 12 UNUSED4 */
61 {0, 0, TAG_SPACE, NULL}, /* 13 SPACE, unused */
62 {0, 0, 0, NULL}, /* 14 UNUSED5 */
63 {0, 0, TAG_META, NULL}, /* 15 META, unused */
64 {0, 0, TAG_EFSTATE, NULL}, /* 16 EFSTATE, unused */
65 {0, 0, TAG_BMFD, NULL}, /* 17 BMFD, unused */
66 {0, 0, TAG_VTFD, NULL}, /* 18 VTFD, unused */
67 {0, 0, TAG_TTFD, NULL}, /* 19 TTFD, unused */
68 {0, 0, TAG_RC, NULL}, /* 1a RC, unused */
69 {0, 0, TAG_TEMP, NULL}, /* 1b TEMP, unused */
70 {0, sizeof(EDRIVEROBJ), TAG_DRVOBJ, DRIVEROBJ_Cleanup},/* 1c DRVOBJ */
71 {0, 0, TAG_DCIOBJ, NULL}, /* 1d DCIOBJ, unused */
72 {0, 0, TAG_SPOOL, NULL}, /* 1e SPOOL, unused */
73 {0, 0, 0, NULL}, /* 1f reserved entry */
74 };
75
76 static LARGE_INTEGER ShortDelay;
77 PGDI_HANDLE_TABLE GdiHandleTable = NULL;
78 PSECTION_OBJECT GdiTableSection = NULL;
79
80 /** INTERNAL FUNCTIONS ********************************************************/
81
82 // Audit Functions
83 int tDC = 0;
84 int tBRUSH = 0;
85 int tBITMAP = 0;
86 int tFONT = 0;
87 int tRGN = 0;
88
89 VOID
90 AllocTypeDataDump(INT TypeInfo)
91 {
92 switch( TypeInfo & GDI_HANDLE_TYPE_MASK )
93 {
94 case GDILoObjType_LO_BRUSH_TYPE:
95 tBRUSH++;
96 break;
97 case GDILoObjType_LO_DC_TYPE:
98 tDC++;
99 break;
100 case GDILoObjType_LO_BITMAP_TYPE:
101 tBITMAP++;
102 break;
103 case GDILoObjType_LO_FONT_TYPE:
104 tFONT++;
105 break;
106 case GDILoObjType_LO_REGION_TYPE:
107 tRGN++;
108 break;
109 }
110 }
111
112 VOID
113 DeAllocTypeDataDump(INT TypeInfo)
114 {
115 switch( TypeInfo & GDI_HANDLE_TYPE_MASK )
116 {
117 case GDILoObjType_LO_BRUSH_TYPE:
118 tBRUSH--;
119 break;
120 case GDILoObjType_LO_DC_TYPE:
121 tDC--;
122 break;
123 case GDILoObjType_LO_BITMAP_TYPE:
124 tBITMAP--;
125 break;
126 case GDILoObjType_LO_FONT_TYPE:
127 tFONT--;
128 break;
129 case GDILoObjType_LO_REGION_TYPE:
130 tRGN--;
131 break;
132 }
133 }
134
135 /*
136 * Dummy GDI Cleanup Callback
137 */
138 static
139 BOOL INTERNAL_CALL
140 GDI_CleanupDummy(PVOID ObjectBody)
141 {
142 return TRUE;
143 }
144
145 /*!
146 * Allocate GDI object table.
147 * \param Size - number of entries in the object table.
148 */
149 INIT_FUNCTION
150 PGDI_HANDLE_TABLE
151 INTERNAL_CALL
152 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject)
153 {
154 PGDI_HANDLE_TABLE HandleTable = NULL;
155 LARGE_INTEGER htSize;
156 UINT ObjType;
157 ULONG ViewSize = 0;
158 NTSTATUS Status;
159
160 ASSERT(SectionObject != NULL);
161
162 htSize.QuadPart = sizeof(GDI_HANDLE_TABLE);
163
164 Status = MmCreateSection((PVOID*)SectionObject,
165 SECTION_ALL_ACCESS,
166 NULL,
167 &htSize,
168 PAGE_READWRITE,
169 SEC_COMMIT,
170 NULL,
171 NULL);
172 if (!NT_SUCCESS(Status))
173 return NULL;
174
175 /* FIXME - use MmMapViewInSessionSpace once available! */
176 Status = MmMapViewInSystemSpace(*SectionObject,
177 (PVOID*)&HandleTable,
178 &ViewSize);
179 if (!NT_SUCCESS(Status))
180 {
181 ObDereferenceObject(*SectionObject);
182 *SectionObject = NULL;
183 return NULL;
184 }
185
186 RtlZeroMemory(HandleTable, sizeof(GDI_HANDLE_TABLE));
187
188 HandleTable->LookasideLists = ExAllocatePoolWithTag(NonPagedPool,
189 BASE_OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST),
190 TAG_GDIHNDTBLE);
191 if (HandleTable->LookasideLists == NULL)
192 {
193 MmUnmapViewInSystemSpace(HandleTable);
194 ObDereferenceObject(*SectionObject);
195 *SectionObject = NULL;
196 return NULL;
197 }
198
199 for (ObjType = 0; ObjType < BASE_OBJTYPE_COUNT; ObjType++)
200 {
201 if (ObjTypeInfo[ObjType].bUseLookaside)
202 {
203 ExInitializePagedLookasideList(HandleTable->LookasideLists + ObjType,
204 NULL,
205 NULL,
206 0,
207 ObjTypeInfo[ObjType].ulBodySize,
208 ObjTypeInfo[ObjType].Tag,
209 0);
210 }
211 }
212
213 ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */
214
215 HandleTable->FirstFree = 0;
216 HandleTable->FirstUnused = RESERVE_ENTRIES_COUNT;
217
218 return HandleTable;
219 }
220
221 INIT_FUNCTION
222 NTSTATUS
223 NTAPI
224 InitGdiHandleTable()
225 {
226 /* Create the GDI handle table */
227 GdiHandleTable = GDIOBJ_iAllocHandleTable(&GdiTableSection);
228 if (GdiHandleTable == NULL)
229 {
230 DPRINT1("Failed to initialize the GDI handle table.\n");
231 return STATUS_UNSUCCESSFUL;
232 }
233
234 return STATUS_SUCCESS;
235 }
236
237
238 static void FASTCALL
239 LockErrorDebugOutput(HGDIOBJ hObj, PGDI_TABLE_ENTRY Entry, LPSTR Function)
240 {
241 if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == 0)
242 {
243 DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function, hObj);
244 GDIDBG_TRACEDELETER(hObj);
245 }
246 else if (GDI_HANDLE_GET_REUSECNT(hObj) != GDI_ENTRY_GET_REUSECNT(Entry->Type))
247 {
248 DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
249 Function, hObj, GDI_HANDLE_GET_REUSECNT(hObj), GDI_ENTRY_GET_REUSECNT(Entry->Type));
250 }
251 else if (GDI_HANDLE_GET_TYPE(hObj) != ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK))
252 {
253 DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
254 Function, hObj, GDI_HANDLE_GET_TYPE(hObj), (Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK);
255 }
256 else
257 {
258 DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
259 Function, hObj, Entry->Type);
260 }
261 GDIDBG_TRACECALLER();
262 }
263
264 ULONG
265 FASTCALL
266 InterlockedPopFreeEntry(VOID)
267 {
268 ULONG iFirst, iNext, iPrev;
269 PGDI_TABLE_ENTRY pEntry;
270
271 DPRINT("Enter InterLockedPopFreeEntry\n");
272
273 do
274 {
275 /* Get the index and sequence number of the first free entry */
276 iFirst = GdiHandleTable->FirstFree;
277
278 /* Check if we have a free entry */
279 if (!(iFirst & GDI_HANDLE_INDEX_MASK))
280 {
281 /* Increment FirstUnused and get the new index */
282 iFirst = InterlockedIncrement((LONG*)&GdiHandleTable->FirstUnused) - 1;
283
284 /* Check if we have unused entries left */
285 if (iFirst >= GDI_HANDLE_COUNT)
286 {
287 DPRINT1("No more gdi handles left!\n");
288 return 0;
289 }
290
291 /* Return the old index */
292 return iFirst;
293 }
294
295 /* Get a pointer to the first free entry */
296 pEntry = GdiHandleTable->Entries + (iFirst & GDI_HANDLE_INDEX_MASK);
297
298 /* Create a new value with an increased sequence number */
299 iNext = (USHORT)(ULONG_PTR)pEntry->KernelData;
300 iNext |= (iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000;
301
302 /* Try to exchange the FirstFree value */
303 iPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree,
304 iNext,
305 iFirst);
306 }
307 while (iPrev != iFirst);
308
309 /* Sanity check: is entry really free? */
310 ASSERT(((ULONG_PTR)pEntry->KernelData & ~GDI_HANDLE_INDEX_MASK) == 0);
311
312 return iFirst & GDI_HANDLE_INDEX_MASK;
313 }
314
315 /* Pushes an entry of the handle table to the free list,
316 The entry must be unlocked and the base type field must be 0 */
317 VOID
318 FASTCALL
319 InterlockedPushFreeEntry(ULONG idxToFree)
320 {
321 ULONG iToFree, iFirst, iPrev;
322 PGDI_TABLE_ENTRY pFreeEntry;
323
324 DPRINT("Enter InterlockedPushFreeEntry\n");
325
326 pFreeEntry = GdiHandleTable->Entries + idxToFree;
327 ASSERT((pFreeEntry->Type & GDI_ENTRY_BASETYPE_MASK) == 0);
328 ASSERT(pFreeEntry->ProcessId == 0);
329 pFreeEntry->UserData = NULL; // FIXME
330 ASSERT(pFreeEntry->UserData == NULL);
331
332 do
333 {
334 /* Get the current first free index and sequence number */
335 iFirst = GdiHandleTable->FirstFree;
336
337 /* Set the KernelData member to the index of the first free entry */
338 pFreeEntry->KernelData = UlongToPtr(iFirst & GDI_HANDLE_INDEX_MASK);
339
340 /* Combine new index and increased sequence number in iToFree */
341 iToFree = idxToFree | ((iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000);
342
343 /* Try to atomically update the first free entry */
344 iPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree,
345 iToFree,
346 iFirst);
347 }
348 while (iPrev != iFirst);
349 }
350
351
352 BOOL
353 INTERNAL_CALL
354 GDIOBJ_ValidateHandle(HGDIOBJ hObj, ULONG ObjectType)
355 {
356 PGDI_TABLE_ENTRY Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
357 if ((((ULONG_PTR)hObj & GDI_HANDLE_TYPE_MASK) == ObjectType) &&
358 (Entry->Type << GDI_ENTRY_UPPER_SHIFT) == GDI_HANDLE_GET_UPPER(hObj))
359 {
360 HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
361 if (pid == NULL || pid == PsGetCurrentProcessId())
362 {
363 return TRUE;
364 }
365 }
366 return FALSE;
367 }
368
369 POBJ INTERNAL_CALL
370 GDIOBJ_AllocObj(UCHAR BaseType)
371 {
372 POBJ pObject;
373
374 ASSERT((BaseType & ~GDIObjTypeTotal) == 0);
375 // BaseType &= GDI_HANDLE_BASETYPE_MASK;
376
377 if (ObjTypeInfo[BaseType].bUseLookaside)
378 {
379 PPAGED_LOOKASIDE_LIST LookasideList;
380
381 LookasideList = GdiHandleTable->LookasideLists + BaseType;
382 pObject = ExAllocateFromPagedLookasideList(LookasideList);
383 }
384 else
385 {
386 pObject = ExAllocatePoolWithTag(PagedPool,
387 ObjTypeInfo[BaseType].ulBodySize,
388 ObjTypeInfo[BaseType].Tag);
389 }
390
391 if (pObject)
392 {
393 RtlZeroMemory(pObject, ObjTypeInfo[BaseType].ulBodySize);
394 }
395
396 return pObject;
397 }
398
399
400 /*!
401 * Allocate memory for GDI object and return handle to it.
402 *
403 * \param ObjectType - type of object \ref GDI object types
404 *
405 * \return Pointer to the allocated object, which is locked.
406 */
407 POBJ INTERNAL_CALL
408 GDIOBJ_AllocObjWithHandle(ULONG ObjectType)
409 {
410 PPROCESSINFO W32Process;
411 POBJ newObject = NULL;
412 HANDLE CurrentProcessId, LockedProcessId;
413 UCHAR TypeIndex;
414 UINT Index;
415 PGDI_TABLE_ENTRY Entry;
416 LONG TypeInfo;
417
418 GDIDBG_INITLOOPTRACE();
419
420 W32Process = PsGetCurrentProcessWin32Process();
421 /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
422 to take too many GDI objects, itself. */
423 if (W32Process && W32Process->GDIHandleCount >= 0x2710)
424 {
425 DPRINT1("Too many objects for process!!!\n");
426 DPRINT1("DC %d BRUSH %d BITMAP %d FONT %d RGN %d\n",tDC,tBRUSH,tBITMAP,tFONT,tRGN);
427 GDIDBG_DUMPHANDLETABLE();
428 return NULL;
429 }
430
431 ASSERT(ObjectType != GDI_OBJECT_TYPE_DONTCARE);
432
433 TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(ObjectType);
434
435 newObject = GDIOBJ_AllocObj(TypeIndex);
436 if (!newObject)
437 {
438 DPRINT1("Not enough memory to allocate gdi object!\n");
439 return NULL;
440 }
441
442 CurrentProcessId = PsGetCurrentProcessId();
443 LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1);
444
445 // RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
446
447 /* On Windows the higher 16 bit of the type field don't contain the
448 full type from the handle, but the base type.
449 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
450 TypeInfo = (ObjectType & GDI_HANDLE_BASETYPE_MASK) | (ObjectType >> GDI_ENTRY_UPPER_SHIFT);
451
452 Index = InterlockedPopFreeEntry();
453 if (Index != 0)
454 {
455 HANDLE PrevProcId;
456
457 Entry = &GdiHandleTable->Entries[Index];
458
459 LockHandle:
460 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, 0);
461 if (PrevProcId == NULL)
462 {
463 PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
464 HGDIOBJ Handle;
465
466 Entry->KernelData = newObject;
467
468 /* copy the reuse-counter */
469 TypeInfo |= Entry->Type & GDI_ENTRY_REUSE_MASK;
470
471 /* we found a free entry, no need to exchange this field atomically
472 since we're holding the lock */
473 Entry->Type = TypeInfo;
474
475 /* Create a handle */
476 Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT));
477
478 /* Initialize BaseObject fields */
479 newObject->hHmgr = Handle;
480 newObject->ulShareCount = 0;
481 newObject->cExclusiveLock = 1;
482 newObject->Tid = Thread;
483 #if DBG
484 if (Thread) Thread->cExclusiveLocks++;
485 #endif
486
487 AllocTypeDataDump(TypeInfo);
488
489 /* unlock the entry */
490 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId);
491
492 GDIDBG_CAPTUREALLOCATOR(Index);
493
494 if (W32Process != NULL)
495 {
496 InterlockedIncrement(&W32Process->GDIHandleCount);
497 }
498
499 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, newObject);
500 return newObject;
501 }
502 else
503 {
504 GDIDBG_TRACELOOP(Index, PrevProcId, CurrentProcessId);
505 /* damn, someone is trying to lock the object even though it doesn't
506 even exist anymore, wait a little and try again!
507 FIXME - we shouldn't loop forever! Give up after some time! */
508 DelayExecution();
509 /* try again */
510 goto LockHandle;
511 }
512 }
513
514 GDIOBJ_FreeObj(newObject, TypeIndex);
515
516 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
517 GDIDBG_DUMPHANDLETABLE();
518
519 return NULL;
520 }
521
522
523 VOID INTERNAL_CALL
524 GDIOBJ_FreeObj(POBJ pObject, UCHAR BaseType)
525 {
526 /* Object must not have a handle! */
527 ASSERT(pObject->hHmgr == NULL);
528
529 if (ObjTypeInfo[BaseType].bUseLookaside)
530 {
531 PPAGED_LOOKASIDE_LIST LookasideList;
532
533 LookasideList = GdiHandleTable->LookasideLists + BaseType;
534 ExFreeToPagedLookasideList(LookasideList, pObject);
535 }
536 else
537 {
538 ExFreePool(pObject);
539 }
540 }
541
542 /*!
543 * Free memory allocated for the GDI object. For each object type this function calls the
544 * appropriate cleanup routine.
545 *
546 * \param hObj - handle of the object to be deleted.
547 *
548 * \return Returns TRUE if succesful.
549 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
550 * to the calling process.
551 *
552 * \bug This function should return VOID and kill the object no matter what...
553 */
554 BOOL INTERNAL_CALL
555 GDIOBJ_FreeObjByHandle(HGDIOBJ hObj, DWORD ExpectedType)
556 {
557 PGDI_TABLE_ENTRY Entry;
558 HANDLE ProcessId, LockedProcessId, PrevProcId;
559 ULONG HandleType, HandleUpper, TypeIndex;
560 BOOL Silent;
561
562 GDIDBG_INITLOOPTRACE();
563
564 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj);
565
566 if (GDI_HANDLE_IS_STOCKOBJ(hObj))
567 {
568 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj);
569 GDIDBG_TRACECALLER();
570 return FALSE;
571 }
572
573 ProcessId = PsGetCurrentProcessId();
574 LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
575
576 Silent = (ExpectedType & GDI_OBJECT_TYPE_SILENT);
577 ExpectedType &= ~GDI_OBJECT_TYPE_SILENT;
578
579 HandleType = GDI_HANDLE_GET_TYPE(hObj);
580 HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
581
582 /* Check if we have the requested type */
583 if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
584 HandleType != ExpectedType) ||
585 HandleType == 0 )
586 {
587 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
588 hObj, HandleType, ExpectedType);
589 GDIDBG_TRACECALLER();
590 return FALSE;
591 }
592
593 Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
594
595 LockHandle:
596 /* lock the object, we must not delete global objects, so don't exchange the locking
597 process ID to zero when attempting to lock a global object... */
598 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
599 if (PrevProcId == ProcessId)
600 {
601 if ( (Entry->KernelData != NULL) &&
602 ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) &&
603 ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == (HandleUpper & GDI_ENTRY_BASETYPE_MASK)) )
604 {
605 POBJ Object;
606 PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
607
608 Object = Entry->KernelData;
609
610 if ((Object->cExclusiveLock == 0 || Object->Tid == Thread) &&
611 Object->ulShareCount == 0)
612 {
613 BOOL Ret;
614 PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process();
615
616 /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
617 Entry->Type = (Entry->Type + GDI_ENTRY_REUSE_INC) & ~GDI_ENTRY_BASETYPE_MASK;
618
619 /* unlock the handle slot */
620 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL);
621
622 /* push this entry to the free list */
623 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable, Entry));
624
625 Object->hHmgr = NULL;
626 #if DBG
627 if (Thread)
628 {
629 if (Thread->cExclusiveLocks < Object->cExclusiveLock)
630 {
631 DPRINT1("cExclusiveLocks = %ld, object: %ld\n",
632 Thread->cExclusiveLocks, Object->cExclusiveLock);
633 ASSERT(FALSE);
634 }
635 Thread->cExclusiveLocks -= Object->cExclusiveLock;
636 }
637 #endif
638
639 if (W32Process != NULL)
640 {
641 InterlockedDecrement(&W32Process->GDIHandleCount);
642 }
643
644 /* call the cleanup routine. */
645 TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(HandleType);
646 Ret = ObjTypeInfo[TypeIndex].CleanupProc(Object);
647
648 DeAllocTypeDataDump(HandleType);
649
650 /* Now it's time to free the memory */
651 GDIOBJ_FreeObj(Object, TypeIndex);
652
653 GDIDBG_CAPTUREDELETER(hObj);
654 return Ret;
655 }
656 else if (Object->ulShareCount != 0)
657 {
658 NTSTATUS Status;
659 PEPROCESS OldProcess;
660 Object->BaseFlags |= BASEFLAG_READY_TO_DIE;
661 DPRINT("Object %p, ulShareCount = %d\n", Object->hHmgr, Object->ulShareCount);
662 /* Set NULL owner. Do the work here to avoid race conditions */
663 Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
664 if (NT_SUCCESS(Status))
665 {
666 PPROCESSINFO W32Process = (PPROCESSINFO)OldProcess->Win32Process;
667 if (W32Process != NULL)
668 {
669 InterlockedDecrement(&W32Process->GDIHandleCount);
670 }
671 ObDereferenceObject(OldProcess);
672 }
673 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL);
674 /* Don't wait on shared locks */
675 return FALSE;
676 }
677 else
678 {
679 /*
680 * The object is currently locked by another thread, so freeing is forbidden!
681 */
682 DPRINT1("Object->cExclusiveLock = %d\n", Object->cExclusiveLock);
683 GDIDBG_TRACECALLER();
684 GDIDBG_TRACELOCKER(hObj);
685 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
686 /* do not assert here for it will call again from dxg.sys it being call twice */
687
688 DelayExecution();
689 goto LockHandle;
690 }
691 }
692 else
693 {
694 LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj");
695 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
696 }
697 }
698 else if (PrevProcId == LockedProcessId)
699 {
700 GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
701
702 /* the object is currently locked, wait some time and try again.
703 FIXME - we shouldn't loop forever! Give up after some time! */
704 DelayExecution();
705 /* try again */
706 goto LockHandle;
707 }
708 else
709 {
710 if (!Silent)
711 {
712 if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == 0)
713 {
714 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj);
715 }
716 else if (((ULONG_PTR)PrevProcId & ~0x1) == 0)
717 {
718 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj);
719 }
720 else
721 {
722 DPRINT1("Attempted to free foreign handle: 0x%x Owner: 0x%x from Caller: 0x%x\n", hObj, (ULONG_PTR)PrevProcId & ~0x1, (ULONG_PTR)ProcessId & ~0x1);
723 }
724 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry->Type, Entry->KernelData, Entry->ProcessId);
725 GDIDBG_TRACECALLER();
726 GDIDBG_TRACEALLOCATOR(hObj);
727 }
728 }
729
730 return FALSE;
731 }
732
733 BOOL
734 FASTCALL
735 IsObjectDead(HGDIOBJ hObject)
736 {
737 INT Index = GDI_HANDLE_GET_INDEX(hObject);
738 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
739 // We check to see if the objects are knocking on deaths door.
740 if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
741 return FALSE;
742 else
743 {
744 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject);
745 return TRUE; // return true and move on.
746 }
747 }
748
749
750 BOOL
751 FASTCALL
752 bPEBCacheHandle(HGDIOBJ Handle, int oType, PVOID pAttr)
753 {
754 PGDIHANDLECACHE GdiHandleCache;
755 HGDIOBJ *hPtr;
756 BOOL Ret = FALSE;
757 int Offset = 0, Number;
758 HANDLE Lock;
759
760 GdiHandleCache = (PGDIHANDLECACHE)NtCurrentTeb()->ProcessEnvironmentBlock->GdiHandleBuffer;
761
762 switch (oType)
763 {
764 case hctBrushHandle:
765 Offset = 0;
766 break;
767
768 case hctPenHandle:
769 Offset = CACHE_BRUSH_ENTRIES;
770 break;
771
772 case hctRegionHandle:
773 Offset = CACHE_BRUSH_ENTRIES+CACHE_PEN_ENTRIES;
774 break;
775
776 default:
777 return FALSE;
778 }
779
780 Lock = InterlockedCompareExchangePointer( (PVOID*)&GdiHandleCache->ulLock,
781 NtCurrentTeb(),
782 NULL );
783 if (Lock) return FALSE;
784
785 _SEH2_TRY
786 {
787 Number = GdiHandleCache->ulNumHandles[oType];
788
789 hPtr = GdiHandleCache->Handle + Offset;
790
791 if ( pAttr && oType == hctRegionHandle)
792 {
793 if ( Number < CACHE_REGION_ENTRIES )
794 {
795 ((PRGN_ATTR)pAttr)->AttrFlags |= ATTR_CACHED;
796 hPtr[Number] = Handle;
797 GdiHandleCache->ulNumHandles[oType]++;
798 DPRINT("Put Handle Count %d PEB 0x%x\n", GdiHandleCache->ulNumHandles[oType], NtCurrentTeb()->ProcessEnvironmentBlock);
799 Ret = TRUE;
800 }
801 }
802 }
803 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
804 {
805 Ret = FALSE;
806 }
807 _SEH2_END;
808
809 (void)InterlockedExchangePointer((PVOID*)&GdiHandleCache->ulLock, Lock);
810 return Ret;
811 }
812
813 /*!
814 * Delete GDI object
815 * \param hObject object handle
816 * \return if the function fails the returned value is FALSE.
817 */
818 BOOL
819 FASTCALL
820 GreDeleteObject(HGDIOBJ hObject)
821 {
822 INT Index;
823 PGDI_TABLE_ENTRY Entry;
824 DWORD dwObjectType;
825 PVOID pAttr = NULL;
826
827 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
828 if (!IsObjectDead(hObject))
829 {
830 dwObjectType = GDIOBJ_GetObjectType(hObject);
831
832 Index = GDI_HANDLE_GET_INDEX(hObject);
833 Entry = &GdiHandleTable->Entries[Index];
834 pAttr = Entry->UserData;
835
836 switch (dwObjectType)
837 {
838 case GDI_OBJECT_TYPE_BRUSH:
839 break;
840
841 case GDI_OBJECT_TYPE_REGION:
842 /* If pAttr NULL, the probability is high for System Region. */
843 if ( pAttr &&
844 bPEBCacheHandle(hObject, hctRegionHandle, pAttr))
845 {
846 /* User space handle only! */
847 return TRUE;
848 }
849 if (pAttr)
850 {
851 FreeObjectAttr(pAttr);
852 Entry->UserData = NULL;
853 }
854 break;
855
856 case GDI_OBJECT_TYPE_DC:
857 // DC_FreeDcAttr(hObject);
858 break;
859 }
860
861 return NULL != hObject
862 ? GDIOBJ_FreeObjByHandle(hObject, dwObjectType) : FALSE;
863 }
864 else
865 {
866 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject);
867 return TRUE; // return true and move on.
868 }
869 }
870
871 VOID
872 FASTCALL
873 IntDeleteHandlesForProcess(struct _EPROCESS *Process, ULONG ObjectType)
874 {
875 PGDI_TABLE_ENTRY Entry, End;
876 ULONG Index = RESERVE_ENTRIES_COUNT;
877 HANDLE ProcId;
878 PPROCESSINFO W32Process;
879
880 W32Process = (PPROCESSINFO)Process->Win32Process;
881 ASSERT(W32Process);
882
883 if (W32Process->GDIHandleCount > 0)
884 {
885 ProcId = Process->UniqueProcessId;
886
887 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
888 we should delete it directly here! */
889
890 End = &GdiHandleTable->Entries[GDI_HANDLE_COUNT];
891 for (Entry = &GdiHandleTable->Entries[RESERVE_ENTRIES_COUNT];
892 Entry != End;
893 Entry++, Index++)
894 {
895 /* ignore the lock bit */
896 if ( (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId)
897 {
898 if ( (Entry->Type & GDI_ENTRY_BASETYPE_MASK) == ObjectType ||
899 ObjectType == GDI_OBJECT_TYPE_DONTCARE)
900 {
901 HGDIOBJ ObjectHandle;
902
903 /* Create the object handle for the entry, the lower(!) 16 bit of the
904 Type field includes the type of the object including the stock
905 object flag - but since stock objects don't have a process id we can
906 simply ignore this fact here. */
907 ObjectHandle = (HGDIOBJ)(Index | (Entry->Type << GDI_ENTRY_UPPER_SHIFT));
908
909 if (!GDIOBJ_FreeObjByHandle(ObjectHandle, GDI_OBJECT_TYPE_DONTCARE))
910 {
911 DPRINT1("Failed to delete object %p!\n", ObjectHandle);
912 }
913
914 if (W32Process->GDIHandleCount == 0)
915 {
916 /* there are no more gdi handles for this process, bail */
917 break;
918 }
919 }
920 }
921 }
922 }
923 }
924
925
926 /*!
927 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
928 * \param Process - PID of the process that will be destroyed.
929 */
930 BOOL INTERNAL_CALL
931 GDI_CleanupForProcess(struct _EPROCESS *Process)
932 {
933 PEPROCESS CurrentProcess;
934 PPROCESSINFO W32Process;
935
936 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId);
937 CurrentProcess = PsGetCurrentProcess();
938 if (CurrentProcess != Process)
939 {
940 KeAttachProcess(&Process->Pcb);
941 }
942
943 W32Process = (PPROCESSINFO)CurrentProcess->Win32Process;
944
945 /* Delete objects. Begin with types that are not referenced by other types */
946 IntDeleteHandlesForProcess(Process, GDILoObjType_LO_DC_TYPE);
947 IntDeleteHandlesForProcess(Process, GDILoObjType_LO_BRUSH_TYPE);
948 IntDeleteHandlesForProcess(Process, GDILoObjType_LO_BITMAP_TYPE);
949
950 /* Finally finish with what's left */
951 IntDeleteHandlesForProcess(Process, GDI_OBJECT_TYPE_DONTCARE);
952
953 if (CurrentProcess != Process)
954 {
955 KeDetachProcess();
956 }
957
958 #ifdef GDI_DEBUG
959 GdiDbgHTIntegrityCheck();
960 #endif
961
962 DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);
963 if (W32Process->GDIHandleCount > 0)
964 {
965 DPRINT1("Leaking %d handles!\n", W32Process->GDIHandleCount);
966 }
967
968 return TRUE;
969 }
970
971 /*!
972 * Return pointer to the object by handle.
973 *
974 * \param hObj Object handle
975 * \return Pointer to the object.
976 *
977 * \note Process can only get pointer to the objects it created or global objects.
978 *
979 * \todo Get rid of the ExpectedType parameter!
980 */
981 PGDIOBJ INTERNAL_CALL
982 GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
983 {
984 ULONG HandleIndex;
985 PGDI_TABLE_ENTRY Entry;
986 HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
987 POBJ Object = NULL;
988 ULONG HandleType, HandleUpper;
989
990 /* Check for dummy call */
991 if(hObj == NULL)
992 return NULL ;
993
994 GDIDBG_INITLOOPTRACE();
995
996 HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
997 HandleType = GDI_HANDLE_GET_TYPE(hObj);
998 HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
999
1000 /* Check that the handle index is valid. */
1001 if (HandleIndex >= GDI_HANDLE_COUNT )
1002 return NULL;
1003
1004 Entry = &GdiHandleTable->Entries[HandleIndex];
1005
1006 /* Check if we have the requested type */
1007 if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
1008 HandleType != ExpectedType) ||
1009 HandleType == 0 )
1010 {
1011 DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1012 hObj, HandleType, ExpectedType);
1013 GDIDBG_TRACECALLER();
1014 GDIDBG_TRACEALLOCATOR(hObj);
1015 GDIDBG_TRACEDELETER(hObj);
1016 return NULL;
1017 }
1018
1019 ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
1020
1021 /*
1022 * Prevent the thread from being terminated during the locking process.
1023 * It would result in undesired effects and inconsistency of the global
1024 * handle table.
1025 */
1026
1027 KeEnterCriticalRegion();
1028
1029 /*
1030 * Loop until we either successfully lock the handle entry & object or
1031 * fail some of the check.
1032 */
1033
1034 for (;;)
1035 {
1036 HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
1037
1038 /* Check for invalid owner. */
1039 if (ProcessId != HandleProcessId && HandleProcessId != NULL)
1040 {
1041 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj, ProcessId, HandleProcessId);
1042 GDIDBG_TRACECALLER();
1043 GDIDBG_TRACEALLOCATOR(hObj);
1044 break;
1045 }
1046
1047 /* Lock the handle table entry. */
1048 LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
1049 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
1050 LockedProcessId,
1051 HandleProcessId);
1052
1053 if (PrevProcId == HandleProcessId)
1054 {
1055 /*
1056 * We're locking an object that belongs to our process or it's a
1057 * global object if HandleProcessId is 0 here.
1058 */
1059
1060 if ( (Entry->KernelData != NULL) &&
1061 ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
1062 {
1063 PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
1064 Object = Entry->KernelData;
1065
1066 if (Object->cExclusiveLock == 0)
1067 {
1068 Object->Tid = Thread;
1069 Object->cExclusiveLock = 1;
1070 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj))
1071 #if DBG
1072 if (Thread) Thread->cExclusiveLocks++;
1073 #endif
1074 }
1075 else
1076 {
1077 if (Object->Tid != Thread)
1078 {
1079 /* Unlock the handle table entry. */
1080 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1081
1082 DelayExecution();
1083 continue;
1084 }
1085 InterlockedIncrement((PLONG)&Object->cExclusiveLock);
1086 #if DBG
1087 if (Thread) Thread->cExclusiveLocks++;
1088 #endif
1089 }
1090 }
1091 else
1092 {
1093 /*
1094 * Debugging code. Report attempts to lock deleted handles and
1095 * locking type mismatches.
1096 */
1097 LockErrorDebugOutput(hObj, Entry, "GDIOBJ_LockObj");
1098 }
1099
1100 /* Unlock the handle table entry. */
1101 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1102
1103 break;
1104 }
1105 else
1106 {
1107 /*
1108 * The handle is currently locked, wait some time and try again.
1109 */
1110 GDIDBG_TRACELOOP(hObj, PrevProcId, NULL);
1111
1112 DelayExecution();
1113 continue;
1114 }
1115 }
1116
1117 KeLeaveCriticalRegion();
1118
1119 return Object;
1120 }
1121
1122
1123 /*!
1124 * Return pointer to the object by handle (and allow sharing of the handle
1125 * across threads).
1126 *
1127 * \param hObj Object handle
1128 * \return Pointer to the object.
1129 *
1130 * \note Process can only get pointer to the objects it created or global objects.
1131 *
1132 * \todo Get rid of the ExpectedType parameter!
1133 */
1134 PGDIOBJ INTERNAL_CALL
1135 GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
1136 {
1137 ULONG HandleIndex;
1138 PGDI_TABLE_ENTRY Entry;
1139 HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
1140 POBJ Object = NULL;
1141 ULONG_PTR HandleType, HandleUpper;
1142
1143 /* Check for dummy call */
1144 if(hObj == NULL)
1145 return NULL ;
1146
1147 HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
1148 HandleType = GDI_HANDLE_GET_TYPE(hObj);
1149 HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
1150
1151 /* Check that the handle index is valid. */
1152 if (HandleIndex >= GDI_HANDLE_COUNT)
1153 return NULL;
1154
1155 /* Check if we have the requested type */
1156 if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
1157 HandleType != ExpectedType) ||
1158 HandleType == 0 )
1159 {
1160 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1161 hObj, HandleType, ExpectedType);
1162 return NULL;
1163 }
1164
1165 Entry = &GdiHandleTable->Entries[HandleIndex];
1166
1167 ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
1168 HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
1169
1170 /* Check for invalid owner. */
1171 if (ProcessId != HandleProcessId && HandleProcessId != NULL)
1172 {
1173 return NULL;
1174 }
1175
1176 /*
1177 * Prevent the thread from being terminated during the locking process.
1178 * It would result in undesired effects and inconsistency of the global
1179 * handle table.
1180 */
1181
1182 KeEnterCriticalRegion();
1183
1184 /*
1185 * Loop until we either successfully lock the handle entry & object or
1186 * fail some of the check.
1187 */
1188
1189 for (;;)
1190 {
1191 /* Lock the handle table entry. */
1192 LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
1193 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
1194 LockedProcessId,
1195 HandleProcessId);
1196
1197 if (PrevProcId == HandleProcessId)
1198 {
1199 /*
1200 * We're locking an object that belongs to our process or it's a
1201 * global object if HandleProcessId is 0 here.
1202 */
1203
1204 if ( (Entry->KernelData != NULL) &&
1205 (HandleUpper == (Entry->Type << GDI_ENTRY_UPPER_SHIFT)) )
1206 {
1207 Object = (POBJ)Entry->KernelData;
1208
1209 GDIDBG_CAPTURESHARELOCKER(HandleIndex);
1210 #ifdef GDI_DEBUG3
1211 if (InterlockedIncrement((PLONG)&Object->ulShareCount) == 1)
1212 {
1213 memset(GDIHandleLocker[HandleIndex], 0x00, GDI_STACK_LEVELS * sizeof(ULONG));
1214 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleShareLocker[HandleIndex], NULL);
1215 }
1216 #else
1217 InterlockedIncrement((PLONG)&Object->ulShareCount);
1218 #endif
1219 }
1220 else
1221 {
1222 /*
1223 * Debugging code. Report attempts to lock deleted handles and
1224 * locking type mismatches.
1225 */
1226 LockErrorDebugOutput(hObj, Entry, "GDIOBJ_ShareLockObj");
1227 }
1228
1229 /* Unlock the handle table entry. */
1230 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1231
1232 break;
1233 }
1234 else
1235 {
1236 /*
1237 * The handle is currently locked, wait some time and try again.
1238 */
1239
1240 DelayExecution();
1241 continue;
1242 }
1243 }
1244
1245 KeLeaveCriticalRegion();
1246
1247 return Object;
1248 }
1249
1250 BOOL INTERNAL_CALL
1251 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle)
1252 {
1253 PGDI_TABLE_ENTRY Entry;
1254 HANDLE ProcessId;
1255 BOOL Ret;
1256
1257 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
1258
1259 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
1260 {
1261 ProcessId = PsGetCurrentProcessId();
1262
1263 Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
1264 Ret = Entry->KernelData != NULL &&
1265 (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
1266 (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcessId;
1267
1268 return Ret;
1269 }
1270
1271 return FALSE;
1272 }
1273
1274 BOOL INTERNAL_CALL
1275 GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
1276 {
1277 /*
1278 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1279 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1280 */
1281 PGDI_TABLE_ENTRY Entry;
1282 HANDLE ProcessId, LockedProcessId, PrevProcId;
1283 PTHREADINFO Thread;
1284 HGDIOBJ hObj;
1285
1286 GDIDBG_INITLOOPTRACE();
1287
1288 ASSERT(phObj);
1289 hObj = *phObj;
1290
1291 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj);
1292
1293 Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
1294
1295 if (!GDI_HANDLE_IS_STOCKOBJ(hObj))
1296 {
1297 ProcessId = PsGetCurrentProcessId();
1298 LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
1299
1300 Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
1301
1302 LockHandle:
1303 /* lock the object, we must not convert stock objects, so don't check!!! */
1304 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
1305 if (PrevProcId == ProcessId)
1306 {
1307 LONG NewType, PrevType, OldType;
1308
1309 /* we're locking an object that belongs to our process. First calculate
1310 the new object type including the stock object flag and then try to
1311 exchange it.*/
1312 /* On Windows the higher 16 bit of the type field don't contain the
1313 full type from the handle, but the base type.
1314 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1315 OldType = ((ULONG)hObj & GDI_HANDLE_BASETYPE_MASK) | ((ULONG)hObj >> GDI_ENTRY_UPPER_SHIFT);
1316 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1317 we copy them as we can't get them from the handle */
1318 OldType |= Entry->Type & GDI_ENTRY_FLAGS_MASK;
1319
1320 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1321 NewType = OldType | GDI_ENTRY_STOCK_MASK;
1322
1323 /* Try to exchange the type field - but only if the old (previous type) matches! */
1324 PrevType = InterlockedCompareExchange(&Entry->Type, NewType, OldType);
1325 if (PrevType == OldType && Entry->KernelData != NULL)
1326 {
1327 PTHREADINFO PrevThread;
1328 POBJ Object;
1329
1330 /* We successfully set the stock object flag.
1331 KernelData should never be NULL here!!! */
1332 ASSERT(Entry->KernelData);
1333
1334 Object = Entry->KernelData;
1335
1336 PrevThread = Object->Tid;
1337 if (Object->cExclusiveLock == 0 || PrevThread == Thread)
1338 {
1339 /* dereference the process' object counter */
1340 if (PrevProcId != GDI_GLOBAL_PROCESS)
1341 {
1342 PEPROCESS OldProcess;
1343 PPROCESSINFO W32Process;
1344 NTSTATUS Status;
1345
1346 /* FIXME */
1347 Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
1348 if (NT_SUCCESS(Status))
1349 {
1350 W32Process = (PPROCESSINFO)OldProcess->Win32Process;
1351 if (W32Process != NULL)
1352 {
1353 InterlockedDecrement(&W32Process->GDIHandleCount);
1354 }
1355 ObDereferenceObject(OldProcess);
1356 }
1357 }
1358
1359 hObj = (HGDIOBJ)((ULONG)(hObj) | GDI_HANDLE_STOCK_MASK);
1360 *phObj = hObj;
1361 Object->hHmgr = hObj;
1362
1363 /* remove the process id lock and make it global */
1364 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, GDI_GLOBAL_PROCESS);
1365
1366 /* we're done, successfully converted the object */
1367 return TRUE;
1368 }
1369 else
1370 {
1371 GDIDBG_TRACELOOP(hObj, PrevThread, Thread);
1372
1373 /* WTF?! The object is already locked by a different thread!
1374 Release the lock, wait a bit and try again!
1375 FIXME - we should give up after some time unless we want to wait forever! */
1376 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1377
1378 DelayExecution();
1379 goto LockHandle;
1380 }
1381 }
1382 else
1383 {
1384 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj);
1385 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType, Entry->Type, NewType, Entry->KernelData);
1386 }
1387 }
1388 else if (PrevProcId == LockedProcessId)
1389 {
1390 GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
1391
1392 /* the object is currently locked, wait some time and try again.
1393 FIXME - we shouldn't loop forever! Give up after some time! */
1394 DelayExecution();
1395 /* try again */
1396 goto LockHandle;
1397 }
1398 else
1399 {
1400 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj);
1401 }
1402 }
1403
1404 return FALSE;
1405 }
1406
1407 BOOL INTERNAL_CALL
1408 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
1409 {
1410 PGDI_TABLE_ENTRY Entry;
1411 HANDLE ProcessId, LockedProcessId, PrevProcId;
1412 PTHREADINFO Thread;
1413 BOOL Ret = TRUE;
1414
1415 GDIDBG_INITLOOPTRACE();
1416
1417 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0));
1418
1419 Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
1420
1421 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
1422 {
1423 ProcessId = PsGetCurrentProcessId();
1424 LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
1425
1426 Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
1427
1428 LockHandle:
1429 /* lock the object, we must not convert stock objects, so don't check!!! */
1430 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, ProcessId, LockedProcessId);
1431 if (PrevProcId == ProcessId)
1432 {
1433 PTHREADINFO PrevThread;
1434
1435 if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
1436 {
1437 POBJ Object = Entry->KernelData;
1438
1439 PrevThread = Object->Tid;
1440 if (Object->cExclusiveLock == 0 || PrevThread == Thread)
1441 {
1442 PEPROCESS OldProcess;
1443 PPROCESSINFO W32Process;
1444 NTSTATUS Status;
1445
1446 if (NewOwner != NULL)
1447 {
1448 ProcessId = PsGetProcessId(NewOwner);
1449 }
1450 else
1451 ProcessId = 0;
1452
1453 if((ULONG_PTR)ProcessId == ((ULONG_PTR)PrevProcId & ~0x1))
1454 {
1455 DPRINT("Setting same process than previous one, nothing to do\n");
1456 goto done;
1457 }
1458
1459 /* dereference the process' object counter */
1460 /* FIXME */
1461 if ((ULONG_PTR)PrevProcId & ~0x1)
1462 {
1463 Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
1464 if (NT_SUCCESS(Status))
1465 {
1466 W32Process = (PPROCESSINFO)OldProcess->Win32Process;
1467 if (W32Process != NULL)
1468 {
1469 InterlockedDecrement(&W32Process->GDIHandleCount);
1470 }
1471 ObDereferenceObject(OldProcess);
1472 }
1473 }
1474
1475 if (NewOwner != NULL)
1476 {
1477 /* Increase the new process' object counter */
1478 W32Process = (PPROCESSINFO)NewOwner->Win32Process;
1479 if (W32Process != NULL)
1480 {
1481 InterlockedIncrement(&W32Process->GDIHandleCount);
1482 }
1483 }
1484
1485 done:
1486 /* remove the process id lock and change it to the new process id */
1487 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, ProcessId);
1488
1489 /* we're done! */
1490 return Ret;
1491 }
1492 else
1493 {
1494 GDIDBG_TRACELOOP(ObjectHandle, PrevThread, Thread);
1495
1496 /* WTF?! The object is already locked by a different thread!
1497 Release the lock, wait a bit and try again! DO reset the pid lock
1498 so we make sure we don't access invalid memory in case the object is
1499 being deleted in the meantime (because we don't have aquired a reference
1500 at this point).
1501 FIXME - we should give up after some time unless we want to wait forever! */
1502 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1503
1504 DelayExecution();
1505 goto LockHandle;
1506 }
1507 }
1508 else
1509 {
1510 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle);
1511 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry->Type, Entry->KernelData);
1512 Ret = FALSE;
1513 }
1514 }
1515 else if (PrevProcId == LockedProcessId)
1516 {
1517 GDIDBG_TRACELOOP(ObjectHandle, PrevProcId, ProcessId);
1518
1519 /* the object is currently locked, wait some time and try again.
1520 FIXME - we shouldn't loop forever! Give up after some time! */
1521 DelayExecution();
1522 /* try again */
1523 goto LockHandle;
1524 }
1525 else if (((ULONG_PTR)PrevProcId & ~0x1) == 0)
1526 {
1527 /* allow changing ownership of global objects */
1528 ProcessId = NULL;
1529 LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
1530 goto LockHandle;
1531 }
1532 else if ((HANDLE)((ULONG_PTR)PrevProcId & ~0x1) != PsGetCurrentProcessId())
1533 {
1534 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle, (ULONG_PTR)PrevProcId & ~0x1, PsGetCurrentProcessId());
1535 Ret = FALSE;
1536 }
1537 else
1538 {
1539 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle);
1540 Ret = FALSE;
1541 }
1542 }
1543 return Ret;
1544 }
1545
1546 BOOL INTERNAL_CALL
1547 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
1548 {
1549 PGDI_TABLE_ENTRY FromEntry;
1550 PTHREADINFO Thread;
1551 HANDLE FromProcessId, FromLockedProcessId, FromPrevProcId;
1552 BOOL Ret = TRUE;
1553
1554 GDIDBG_INITLOOPTRACE();
1555
1556 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo);
1557
1558 Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
1559
1560 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo))
1561 {
1562 FromEntry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, CopyFrom);
1563
1564 FromProcessId = (HANDLE)((ULONG_PTR)FromEntry->ProcessId & ~0x1);
1565 FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
1566
1567 LockHandleFrom:
1568 /* lock the object, we must not convert stock objects, so don't check!!! */
1569 FromPrevProcId = InterlockedCompareExchangePointer((PVOID*)&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
1570 if (FromPrevProcId == FromProcessId)
1571 {
1572 PTHREADINFO PrevThread;
1573 POBJ Object;
1574
1575 if ((FromEntry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
1576 {
1577 Object = FromEntry->KernelData;
1578
1579 /* save the pointer to the calling thread so we know it was this thread
1580 that locked the object */
1581 PrevThread = Object->Tid;
1582 if (Object->cExclusiveLock == 0 || PrevThread == Thread)
1583 {
1584 /* now let's change the ownership of the target object */
1585
1586 if (((ULONG_PTR)FromPrevProcId & ~0x1) != 0)
1587 {
1588 PEPROCESS ProcessTo;
1589 /* FIXME */
1590 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1), &ProcessTo)))
1591 {
1592 GDIOBJ_SetOwnership(CopyTo, ProcessTo);
1593 ObDereferenceObject(ProcessTo);
1594 }
1595 }
1596 else
1597 {
1598 /* mark the object as global */
1599 GDIOBJ_SetOwnership(CopyTo, NULL);
1600 }
1601
1602 (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
1603 }
1604 else
1605 {
1606 GDIDBG_TRACELOOP(CopyFrom, PrevThread, Thread);
1607
1608 /* WTF?! The object is already locked by a different thread!
1609 Release the lock, wait a bit and try again! DO reset the pid lock
1610 so we make sure we don't access invalid memory in case the object is
1611 being deleted in the meantime (because we don't have aquired a reference
1612 at this point).
1613 FIXME - we should give up after some time unless we want to wait forever! */
1614 (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
1615
1616 DelayExecution();
1617 goto LockHandleFrom;
1618 }
1619 }
1620 else
1621 {
1622 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom);
1623 Ret = FALSE;
1624 }
1625 }
1626 else if (FromPrevProcId == FromLockedProcessId)
1627 {
1628 GDIDBG_TRACELOOP(CopyFrom, FromPrevProcId, FromProcessId);
1629
1630 /* the object is currently locked, wait some time and try again.
1631 FIXME - we shouldn't loop forever! Give up after some time! */
1632 DelayExecution();
1633 /* try again */
1634 goto LockHandleFrom;
1635 }
1636 else if ((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1) != PsGetCurrentProcessId())
1637 {
1638 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1639 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom, (ULONG_PTR)FromPrevProcId & ~0x1, PsGetCurrentProcessId());
1640 FromProcessId = (HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1);
1641 FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
1642 goto LockHandleFrom;
1643 }
1644 else
1645 {
1646 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom);
1647 Ret = FALSE;
1648 }
1649 }
1650 return Ret;
1651 }
1652
1653 PVOID INTERNAL_CALL
1654 GDI_MapHandleTable(PSECTION_OBJECT SectionObject, PEPROCESS Process)
1655 {
1656 PVOID MappedView = NULL;
1657 NTSTATUS Status;
1658 LARGE_INTEGER Offset;
1659 ULONG ViewSize = sizeof(GDI_HANDLE_TABLE);
1660
1661 Offset.QuadPart = 0;
1662
1663 ASSERT(SectionObject != NULL);
1664 ASSERT(Process != NULL);
1665
1666 Status = MmMapViewOfSection(SectionObject,
1667 Process,
1668 &MappedView,
1669 0,
1670 0,
1671 &Offset,
1672 &ViewSize,
1673 ViewUnmap,
1674 SEC_NO_CHANGE,
1675 PAGE_READONLY);
1676
1677 if (!NT_SUCCESS(Status))
1678 return NULL;
1679
1680 return MappedView;
1681 }
1682
1683 /* Locks 2 or 3 objects at a time */
1684 VOID
1685 INTERNAL_CALL
1686 GDIOBJ_LockMultipleObjs(ULONG ulCount,
1687 IN HGDIOBJ* ahObj,
1688 OUT PGDIOBJ* apObj)
1689 {
1690 UINT auiIndices[3] = {0,1,2};
1691 UINT i, tmp ;
1692 BOOL bUnsorted = TRUE;
1693
1694 /* First is greatest */
1695 while(bUnsorted)
1696 {
1697 bUnsorted = FALSE;
1698 for(i=1; i<ulCount; i++)
1699 {
1700 if((ULONG_PTR)ahObj[auiIndices[i-1]] < (ULONG_PTR)ahObj[auiIndices[i]])
1701 {
1702 tmp = auiIndices[i-1];
1703 auiIndices[i-1] = auiIndices[i];
1704 auiIndices[i] = tmp;
1705 bUnsorted = TRUE;
1706 }
1707 }
1708 }
1709
1710 for(i=0;i<ulCount;i++)
1711 apObj[auiIndices[i]] = GDIOBJ_LockObj(ahObj[auiIndices[i]], GDI_OBJECT_TYPE_DONTCARE);
1712 }
1713
1714
1715 /** PUBLIC FUNCTIONS **********************************************************/
1716
1717 BOOL
1718 FASTCALL
1719 IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
1720 {
1721 INT Index;
1722 PGDI_TABLE_ENTRY Entry;
1723 /*
1724 System Regions:
1725 These regions do not use attribute sections and when allocated, use gdiobj
1726 level functions.
1727 */
1728 // FIXME! HAX!!! Remove this once we get everything right!
1729 Index = GDI_HANDLE_GET_INDEX(hRgn);
1730 Entry = &GdiHandleTable->Entries[Index];
1731 if (Entry->UserData) FreeObjectAttr(Entry->UserData);
1732 Entry->UserData = NULL;
1733 //
1734 if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
1735 {
1736 return GDIOBJ_SetOwnership(hRgn, NULL);
1737 }
1738 if (OwnerMask == GDI_OBJ_HMGR_POWNED)
1739 {
1740 return GDIOBJ_SetOwnership((HGDIOBJ) hRgn, PsGetCurrentProcess() );
1741 }
1742 return FALSE;
1743 }
1744
1745 BOOL
1746 FASTCALL
1747 IntGdiSetBrushOwner(PBRUSH pbr, DWORD OwnerMask)
1748 {
1749 HBRUSH hBR;
1750 PEPROCESS Owner = NULL;
1751 PGDI_TABLE_ENTRY pEntry = NULL;
1752
1753 if (!pbr) return FALSE;
1754
1755 hBR = pbr->BaseObject.hHmgr;
1756
1757 if (!hBR || (GDI_HANDLE_GET_TYPE(hBR) != GDI_OBJECT_TYPE_BRUSH))
1758 return FALSE;
1759 else
1760 {
1761 INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hBR);
1762 pEntry = &GdiHandleTable->Entries[Index];
1763 }
1764
1765 if (pbr->flAttrs & GDIBRUSH_IS_GLOBAL)
1766 {
1767 GDIOBJ_ShareUnlockObjByPtr((POBJ)pbr);
1768 return TRUE;
1769 }
1770
1771 if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
1772 {
1773 // Set this Brush to inaccessible mode and to an Owner of NONE.
1774 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1775
1776 if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, Owner))
1777 return FALSE;
1778
1779 // Deny user access to User Data.
1780 pEntry->UserData = NULL; // This hBR is inaccessible!
1781 }
1782
1783 if (OwnerMask == GDI_OBJ_HMGR_POWNED)
1784 {
1785 if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, PsGetCurrentProcess() ))
1786 return FALSE;
1787
1788 // Allow user access to User Data.
1789 pEntry->UserData = pbr->pBrushAttr;
1790 }
1791 return TRUE;
1792 }
1793
1794 BOOL
1795 FASTCALL
1796 IntGdiSetDCOwnerEx( HDC hDC, DWORD OwnerMask, BOOL NoSetBrush)
1797 {
1798 PDC pDC;
1799 BOOL Ret = FALSE;
1800
1801 if (!hDC || (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_DC)) return FALSE;
1802
1803 if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
1804 {
1805 pDC = DC_LockDc ( hDC );
1806 MmCopyFromCaller(&pDC->dcattr, pDC->pdcattr, sizeof(DC_ATTR));
1807 DC_vFreeDcAttr(pDC);
1808 DC_UnlockDc( pDC );
1809
1810 if (!DC_SetOwnership( hDC, NULL )) // This hDC is inaccessible!
1811 return Ret;
1812 }
1813
1814 if (OwnerMask == GDI_OBJ_HMGR_POWNED)
1815 {
1816 pDC = DC_LockDc ( hDC );
1817 ASSERT(pDC->pdcattr == &pDC->dcattr);
1818 DC_UnlockDc( pDC );
1819
1820 if (!DC_SetOwnership( hDC, PsGetCurrentProcess() )) return Ret;
1821
1822 DC_AllocateDcAttr( hDC ); // Allocate new dcattr
1823
1824 DCU_SynchDcAttrtoUser( hDC ); // Copy data from dc to dcattr
1825 }
1826
1827 if ((OwnerMask != GDI_OBJ_HMGR_NONE) && !NoSetBrush)
1828 {
1829 pDC = DC_LockDc ( hDC );
1830 if (IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrFill, OwnerMask))
1831 IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrLine, OwnerMask);
1832 DC_UnlockDc( pDC );
1833 }
1834 return TRUE;
1835 }
1836
1837 INT
1838 FASTCALL
1839 GreGetObjectOwner(HGDIOBJ Handle, GDIOBJTYPE ObjType)
1840 {
1841 INT Ret = GDI_OBJ_HMGR_RESTRICTED;
1842
1843 if ( GDI_HANDLE_GET_INDEX(Handle) < GDI_HANDLE_COUNT )
1844 {
1845 PGDI_TABLE_ENTRY pEntry = &GdiHandleTable->Entries[GDI_HANDLE_GET_INDEX(Handle)];
1846
1847 if (pEntry->ObjectType == ObjType)
1848 {
1849 if (pEntry->FullUnique == (GDI_HANDLE_GET_UPPER(Handle) >> GDI_ENTRY_UPPER_SHIFT))
1850 Ret = pEntry->ProcessId & ~1;
1851 }
1852 }
1853 return Ret;
1854 }
1855
1856 W32KAPI
1857 HANDLE
1858 APIENTRY
1859 NtGdiCreateClientObj(
1860 IN ULONG ulType
1861 )
1862 {
1863 POBJ pObject;
1864 HANDLE handle;
1865
1866 /* Mask out everything that would change the type in a wrong manner */
1867 ulType &= (GDI_HANDLE_TYPE_MASK & ~GDI_HANDLE_BASETYPE_MASK);
1868
1869 /* Allocate a new object */
1870 pObject = GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ | ulType);
1871 if (!pObject)
1872 {
1873 return NULL;
1874 }
1875
1876 /* get the handle */
1877 handle = pObject->hHmgr;
1878
1879 /* Unlock it */
1880 GDIOBJ_UnlockObjByPtr(pObject);
1881
1882 return handle;
1883 }
1884
1885 W32KAPI
1886 BOOL
1887 APIENTRY
1888 NtGdiDeleteClientObj(
1889 IN HANDLE h
1890 )
1891 {
1892 /* We first need to get the real type from the handle */
1893 ULONG type = GDI_HANDLE_GET_TYPE(h);
1894
1895 /* Check if it's really a CLIENTOBJ */
1896 if ((type & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE)
1897 {
1898 /* FIXME: SetLastError? */
1899 return FALSE;
1900 }
1901 return GDIOBJ_FreeObjByHandle(h, type);
1902 }
1903
1904 INT
1905 FASTCALL
1906 IntGdiGetObject(IN HANDLE Handle,
1907 IN INT cbCount,
1908 IN LPVOID lpBuffer)
1909 {
1910 PVOID pGdiObject;
1911 INT Result = 0;
1912 DWORD dwObjectType;
1913
1914 pGdiObject = GDIOBJ_LockObj(Handle, GDI_OBJECT_TYPE_DONTCARE);
1915 if (!pGdiObject)
1916 {
1917 EngSetLastError(ERROR_INVALID_HANDLE);
1918 return 0;
1919 }
1920
1921 dwObjectType = GDIOBJ_GetObjectType(Handle);
1922 switch (dwObjectType)
1923 {
1924 case GDI_OBJECT_TYPE_PEN:
1925 case GDI_OBJECT_TYPE_EXTPEN:
1926 Result = PEN_GetObject((PBRUSH) pGdiObject, cbCount, (PLOGPEN) lpBuffer); // IntGdiCreatePenIndirect
1927 break;
1928
1929 case GDI_OBJECT_TYPE_BRUSH:
1930 Result = BRUSH_GetObject((PBRUSH ) pGdiObject, cbCount, (LPLOGBRUSH)lpBuffer);
1931 break;
1932
1933 case GDI_OBJECT_TYPE_BITMAP:
1934 Result = BITMAP_GetObject((SURFACE *) pGdiObject, cbCount, lpBuffer);
1935 break;
1936 case GDI_OBJECT_TYPE_FONT:
1937 Result = FontGetObject((PTEXTOBJ) pGdiObject, cbCount, lpBuffer);
1938 #if 0
1939 // Fix the LOGFONT structure for the stock fonts
1940 if (FIRST_STOCK_HANDLE <= Handle && Handle <= LAST_STOCK_HANDLE)
1941 {
1942 FixStockFontSizeW(Handle, cbCount, lpBuffer);
1943 }
1944 #endif
1945 break;
1946
1947 case GDI_OBJECT_TYPE_PALETTE:
1948 Result = PALETTE_GetObject((PPALETTE) pGdiObject, cbCount, lpBuffer);
1949 break;
1950
1951 default:
1952 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType);
1953 break;
1954 }
1955
1956 GDIOBJ_UnlockObjByPtr(pGdiObject);
1957
1958 return Result;
1959 }
1960
1961
1962
1963 W32KAPI
1964 INT
1965 APIENTRY
1966 NtGdiExtGetObjectW(IN HANDLE hGdiObj,
1967 IN INT cbCount,
1968 OUT LPVOID lpBuffer)
1969 {
1970 INT iRetCount = 0;
1971 INT cbCopyCount;
1972 union
1973 {
1974 BITMAP bitmap;
1975 DIBSECTION dibsection;
1976 LOGPEN logpen;
1977 LOGBRUSH logbrush;
1978 LOGFONTW logfontw;
1979 EXTLOGFONTW extlogfontw;
1980 ENUMLOGFONTEXDVW enumlogfontexdvw;
1981 } Object;
1982
1983 // Normalize to the largest supported object size
1984 cbCount = min((UINT)cbCount, sizeof(Object));
1985
1986 // Now do the actual call
1987 iRetCount = IntGdiGetObject(hGdiObj, cbCount, lpBuffer ? &Object : NULL);
1988 cbCopyCount = min((UINT)cbCount, (UINT)iRetCount);
1989
1990 // Make sure we have a buffer and a copy size
1991 if ((cbCopyCount) && (lpBuffer))
1992 {
1993 // Enter SEH for buffer transfer
1994 _SEH2_TRY
1995 {
1996 // Probe the buffer and copy it
1997 ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD));
1998 RtlCopyMemory(lpBuffer, &Object, cbCopyCount);
1999 }
2000 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2001 {
2002 // Clear the return value.
2003 // Do *NOT* set last error here!
2004 iRetCount = 0;
2005 }
2006 _SEH2_END;
2007 }
2008 // Return the count
2009 return iRetCount;
2010 }
2011
2012 /* EOF */