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