1c0dc8e8b3c25c6671e36764ca8927a81e79caa9
[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 //#define GDI_DEBUG
12
13 #include <w32k.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 */ /* FIXME: -fno-unit-at-a-time breaks this */
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 */ /* FIXME: -fno-unit-at-a-time breaks this */
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 Object->BaseFlags |= BASEFLAG_READY_TO_DIE;
635 DPRINT("Object %p, ulShareCount = %d\n", Object->hHmgr, Object->ulShareCount);
636 //GDIDBG_TRACECALLER();
637 //GDIDBG_TRACESHARELOCKER(GDI_HANDLE_GET_INDEX(hObj));
638 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
639 /* Don't wait on shared locks */
640 return FALSE;
641 }
642 else
643 {
644 /*
645 * The object is currently locked by another thread, so freeing is forbidden!
646 */
647 DPRINT1("Object->cExclusiveLock = %d\n", Object->cExclusiveLock);
648 GDIDBG_TRACECALLER();
649 GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj));
650 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
651 /* do not assert here for it will call again from dxg.sys it being call twice */
652
653 DelayExecution();
654 goto LockHandle;
655 }
656 }
657 else
658 {
659 LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj");
660 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
661 }
662 }
663 else if (PrevProcId == LockedProcessId)
664 {
665 GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
666
667 /* the object is currently locked, wait some time and try again.
668 FIXME - we shouldn't loop forever! Give up after some time! */
669 DelayExecution();
670 /* try again */
671 goto LockHandle;
672 }
673 else
674 {
675 if (!Silent)
676 {
677 if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == 0)
678 {
679 DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj);
680 }
681 else if (((ULONG_PTR)PrevProcId & ~0x1) == 0)
682 {
683 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj);
684 }
685 else
686 {
687 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);
688 }
689 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry->Type, Entry->KernelData, Entry->ProcessId);
690 GDIDBG_TRACECALLER();
691 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj));
692 }
693 }
694
695 return FALSE;
696 }
697
698 BOOL
699 FASTCALL
700 IsObjectDead(HGDIOBJ hObject)
701 {
702 INT Index = GDI_HANDLE_GET_INDEX(hObject);
703 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
704 // We check to see if the objects are knocking on deaths door.
705 if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
706 return FALSE;
707 else
708 {
709 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject);
710 return TRUE; // return true and move on.
711 }
712 }
713
714
715 BOOL
716 FASTCALL
717 bPEBCacheHandle(HGDIOBJ Handle, int oType, PVOID pAttr)
718 {
719 PGDIHANDLECACHE GdiHandleCache;
720 HGDIOBJ *hPtr;
721 BOOL Ret = FALSE;
722 int Offset = 0, Number;
723 HANDLE Lock;
724
725 GdiHandleCache = (PGDIHANDLECACHE)NtCurrentTeb()->ProcessEnvironmentBlock->GdiHandleBuffer;
726
727 switch (oType)
728 {
729 case hctBrushHandle:
730 Offset = 0;
731 break;
732
733 case hctPenHandle:
734 Offset = CACHE_BRUSH_ENTRIES;
735 break;
736
737 case hctRegionHandle:
738 Offset = CACHE_BRUSH_ENTRIES+CACHE_PEN_ENTRIES;
739 break;
740
741 default:
742 return FALSE;
743 }
744
745 Lock = InterlockedCompareExchangePointer( (PVOID*)&GdiHandleCache->ulLock,
746 NtCurrentTeb(),
747 NULL );
748 if (Lock) return FALSE;
749
750 _SEH2_TRY
751 {
752 Number = GdiHandleCache->ulNumHandles[oType];
753
754 hPtr = GdiHandleCache->Handle + Offset;
755
756 if ( pAttr && oType == hctRegionHandle)
757 {
758 if ( Number < CACHE_REGION_ENTRIES )
759 {
760 ((PRGN_ATTR)pAttr)->AttrFlags |= ATTR_CACHED;
761 hPtr[Number] = Handle;
762 GdiHandleCache->ulNumHandles[oType]++;
763 DPRINT("Put Handle Count %d PEB 0x%x\n", GdiHandleCache->ulNumHandles[oType], NtCurrentTeb()->ProcessEnvironmentBlock);
764 Ret = TRUE;
765 }
766 }
767 }
768 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
769 {
770 Ret = FALSE;
771 }
772 _SEH2_END;
773
774 (void)InterlockedExchangePointer((PVOID*)&GdiHandleCache->ulLock, Lock);
775 return Ret;
776 }
777
778 /*!
779 * Delete GDI object
780 * \param hObject object handle
781 * \return if the function fails the returned value is FALSE.
782 */
783 BOOL
784 FASTCALL
785 GreDeleteObject(HGDIOBJ hObject)
786 {
787 INT Index;
788 PGDI_TABLE_ENTRY Entry;
789 DWORD dwObjectType;
790 PVOID pAttr = NULL;
791
792 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
793 if (!IsObjectDead(hObject))
794 {
795 dwObjectType = GDIOBJ_GetObjectType(hObject);
796
797 Index = GDI_HANDLE_GET_INDEX(hObject);
798 Entry = &GdiHandleTable->Entries[Index];
799 pAttr = Entry->UserData;
800
801 switch (dwObjectType)
802 {
803 case GDI_OBJECT_TYPE_BRUSH:
804 break;
805
806 case GDI_OBJECT_TYPE_REGION:
807 /* If pAttr NULL, the probability is high for System Region. */
808 if ( pAttr &&
809 bPEBCacheHandle(hObject, hctRegionHandle, pAttr))
810 {
811 /* User space handle only! */
812 return TRUE;
813 }
814 if (pAttr)
815 {
816 FreeObjectAttr(pAttr);
817 Entry->UserData = NULL;
818 }
819 break;
820
821 case GDI_OBJECT_TYPE_DC:
822 DC_FreeDcAttr(hObject);
823 break;
824 }
825
826 return NULL != hObject
827 ? GDIOBJ_FreeObjByHandle(hObject, dwObjectType) : FALSE;
828 }
829 else
830 {
831 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject);
832 return TRUE; // return true and move on.
833 }
834 }
835
836 VOID
837 FASTCALL
838 IntDeleteHandlesForProcess(struct _EPROCESS *Process, ULONG ObjectType)
839 {
840 PGDI_TABLE_ENTRY Entry, End;
841 ULONG Index = RESERVE_ENTRIES_COUNT;
842 HANDLE ProcId;
843 PPROCESSINFO W32Process;
844
845 W32Process = (PPROCESSINFO)Process->Win32Process;
846 ASSERT(W32Process);
847
848 if (W32Process->GDIHandleCount > 0)
849 {
850 ProcId = Process->UniqueProcessId;
851
852 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
853 we should delete it directly here! */
854
855 End = &GdiHandleTable->Entries[GDI_HANDLE_COUNT];
856 for (Entry = &GdiHandleTable->Entries[RESERVE_ENTRIES_COUNT];
857 Entry != End;
858 Entry++, Index++)
859 {
860 /* ignore the lock bit */
861 if ( (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId)
862 {
863 if ( (Entry->Type & GDI_ENTRY_BASETYPE_MASK) == ObjectType ||
864 ObjectType == GDI_OBJECT_TYPE_DONTCARE)
865 {
866 HGDIOBJ ObjectHandle;
867
868 /* Create the object handle for the entry, the lower(!) 16 bit of the
869 Type field includes the type of the object including the stock
870 object flag - but since stock objects don't have a process id we can
871 simply ignore this fact here. */
872 ObjectHandle = (HGDIOBJ)(Index | (Entry->Type << GDI_ENTRY_UPPER_SHIFT));
873
874 if (!GDIOBJ_FreeObjByHandle(ObjectHandle, GDI_OBJECT_TYPE_DONTCARE))
875 {
876 DPRINT1("Failed to delete object %p!\n", ObjectHandle);
877 }
878
879 if (W32Process->GDIHandleCount == 0)
880 {
881 /* there are no more gdi handles for this process, bail */
882 break;
883 }
884 }
885 }
886 }
887 }
888 }
889
890
891 /*!
892 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
893 * \param Process - PID of the process that will be destroyed.
894 */
895 BOOL INTERNAL_CALL
896 GDI_CleanupForProcess(struct _EPROCESS *Process)
897 {
898 PEPROCESS CurrentProcess;
899 PPROCESSINFO W32Process;
900
901 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId);
902 CurrentProcess = PsGetCurrentProcess();
903 if (CurrentProcess != Process)
904 {
905 KeAttachProcess(&Process->Pcb);
906 }
907
908 W32Process = (PPROCESSINFO)CurrentProcess->Win32Process;
909
910 /* Delete objects. Begin with types that are not referenced by other types */
911 IntDeleteHandlesForProcess(Process, GDILoObjType_LO_DC_TYPE);
912 IntDeleteHandlesForProcess(Process, GDILoObjType_LO_BRUSH_TYPE);
913 IntDeleteHandlesForProcess(Process, GDILoObjType_LO_BITMAP_TYPE);
914
915 /* Finally finish with what's left */
916 IntDeleteHandlesForProcess(Process, GDI_OBJECT_TYPE_DONTCARE);
917
918 if (CurrentProcess != Process)
919 {
920 KeDetachProcess();
921 }
922
923 #ifdef GDI_DEBUG
924 GdiDbgHTIntegrityCheck();
925 #endif
926
927 DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);
928 if (W32Process->GDIHandleCount > 0)
929 {
930 DPRINT1("Leaking %d handles!\n", W32Process->GDIHandleCount);
931 }
932
933 return TRUE;
934 }
935
936 /*!
937 * Return pointer to the object by handle.
938 *
939 * \param hObj Object handle
940 * \return Pointer to the object.
941 *
942 * \note Process can only get pointer to the objects it created or global objects.
943 *
944 * \todo Get rid of the ExpectedType parameter!
945 */
946 PGDIOBJ INTERNAL_CALL
947 GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
948 {
949 ULONG HandleIndex;
950 PGDI_TABLE_ENTRY Entry;
951 HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
952 POBJ Object = NULL;
953 ULONG HandleType, HandleUpper;
954
955 HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
956 HandleType = GDI_HANDLE_GET_TYPE(hObj);
957 HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
958
959 /* Check that the handle index is valid. */
960 if (HandleIndex >= GDI_HANDLE_COUNT)
961 return NULL;
962
963 Entry = &GdiHandleTable->Entries[HandleIndex];
964
965 /* Check if we have the requested type */
966 if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
967 HandleType != ExpectedType) ||
968 HandleType == 0 )
969 {
970 DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
971 hObj, HandleType, ExpectedType);
972 GDIDBG_TRACECALLER();
973 GDIDBG_TRACEALLOCATOR(hObj);
974 GDIDBG_TRACEDELETER(hObj);
975 return NULL;
976 }
977
978 ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
979 HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
980
981 /* Check for invalid owner. */
982 if (ProcessId != HandleProcessId && HandleProcessId != NULL)
983 {
984 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj, ProcessId, HandleProcessId);
985 GDIDBG_TRACECALLER();
986 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj));
987 return NULL;
988 }
989
990 /*
991 * Prevent the thread from being terminated during the locking process.
992 * It would result in undesired effects and inconsistency of the global
993 * handle table.
994 */
995
996 KeEnterCriticalRegion();
997
998 /*
999 * Loop until we either successfully lock the handle entry & object or
1000 * fail some of the check.
1001 */
1002
1003 for (;;)
1004 {
1005 /* Lock the handle table entry. */
1006 LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
1007 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
1008 LockedProcessId,
1009 HandleProcessId);
1010
1011 if (PrevProcId == HandleProcessId)
1012 {
1013 /*
1014 * We're locking an object that belongs to our process or it's a
1015 * global object if HandleProcessId is 0 here.
1016 */
1017
1018 if ( (Entry->KernelData != NULL) &&
1019 ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
1020 {
1021 PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
1022 Object = Entry->KernelData;
1023
1024 if (Object->cExclusiveLock == 0)
1025 {
1026 Object->Tid = Thread;
1027 Object->cExclusiveLock = 1;
1028 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj))
1029 }
1030 else
1031 {
1032 if (Object->Tid != Thread)
1033 {
1034 /* Unlock the handle table entry. */
1035 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1036
1037 DelayExecution();
1038 continue;
1039 }
1040 InterlockedIncrement((PLONG)&Object->cExclusiveLock);
1041 }
1042 }
1043 else
1044 {
1045 /*
1046 * Debugging code. Report attempts to lock deleted handles and
1047 * locking type mismatches.
1048 */
1049 LockErrorDebugOutput(hObj, Entry, "GDIOBJ_LockObj");
1050 }
1051
1052 /* Unlock the handle table entry. */
1053 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1054
1055 break;
1056 }
1057 else
1058 {
1059 /*
1060 * The handle is currently locked, wait some time and try again.
1061 */
1062
1063 DelayExecution();
1064 continue;
1065 }
1066 }
1067
1068 KeLeaveCriticalRegion();
1069
1070 return Object;
1071 }
1072
1073
1074 /*!
1075 * Return pointer to the object by handle (and allow sharing of the handle
1076 * across threads).
1077 *
1078 * \param hObj Object handle
1079 * \return Pointer to the object.
1080 *
1081 * \note Process can only get pointer to the objects it created or global objects.
1082 *
1083 * \todo Get rid of the ExpectedType parameter!
1084 */
1085 PGDIOBJ INTERNAL_CALL
1086 GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
1087 {
1088 ULONG HandleIndex;
1089 PGDI_TABLE_ENTRY Entry;
1090 HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
1091 POBJ Object = NULL;
1092 ULONG_PTR HandleType, HandleUpper;
1093
1094 HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
1095 HandleType = GDI_HANDLE_GET_TYPE(hObj);
1096 HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
1097
1098 /* Check that the handle index is valid. */
1099 if (HandleIndex >= GDI_HANDLE_COUNT)
1100 return NULL;
1101
1102 /* Check if we have the requested type */
1103 if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
1104 HandleType != ExpectedType) ||
1105 HandleType == 0 )
1106 {
1107 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1108 hObj, HandleType, ExpectedType);
1109 return NULL;
1110 }
1111
1112 Entry = &GdiHandleTable->Entries[HandleIndex];
1113
1114 ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
1115 HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
1116
1117 /* Check for invalid owner. */
1118 if (ProcessId != HandleProcessId && HandleProcessId != NULL)
1119 {
1120 return NULL;
1121 }
1122
1123 /*
1124 * Prevent the thread from being terminated during the locking process.
1125 * It would result in undesired effects and inconsistency of the global
1126 * handle table.
1127 */
1128
1129 KeEnterCriticalRegion();
1130
1131 /*
1132 * Loop until we either successfully lock the handle entry & object or
1133 * fail some of the check.
1134 */
1135
1136 for (;;)
1137 {
1138 /* Lock the handle table entry. */
1139 LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
1140 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
1141 LockedProcessId,
1142 HandleProcessId);
1143
1144 if (PrevProcId == HandleProcessId)
1145 {
1146 /*
1147 * We're locking an object that belongs to our process or it's a
1148 * global object if HandleProcessId is 0 here.
1149 */
1150
1151 if ( (Entry->KernelData != NULL) &&
1152 (HandleUpper == (Entry->Type << GDI_ENTRY_UPPER_SHIFT)) )
1153 {
1154 Object = (POBJ)Entry->KernelData;
1155
1156 GDIDBG_CAPTURESHARELOCKER(HandleIndex);
1157 #ifdef GDI_DEBUG3
1158 if (InterlockedIncrement((PLONG)&Object->ulShareCount) == 1)
1159 {
1160 memset(GDIHandleLocker[HandleIndex], 0x00, GDI_STACK_LEVELS * sizeof(ULONG));
1161 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleShareLocker[HandleIndex], NULL);
1162 }
1163 #else
1164 InterlockedIncrement((PLONG)&Object->ulShareCount);
1165 #endif
1166 }
1167 else
1168 {
1169 /*
1170 * Debugging code. Report attempts to lock deleted handles and
1171 * locking type mismatches.
1172 */
1173 LockErrorDebugOutput(hObj, Entry, "GDIOBJ_ShareLockObj");
1174 }
1175
1176 /* Unlock the handle table entry. */
1177 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1178
1179 break;
1180 }
1181 else
1182 {
1183 /*
1184 * The handle is currently locked, wait some time and try again.
1185 */
1186
1187 DelayExecution();
1188 continue;
1189 }
1190 }
1191
1192 KeLeaveCriticalRegion();
1193
1194 return Object;
1195 }
1196
1197 BOOL INTERNAL_CALL
1198 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle)
1199 {
1200 PGDI_TABLE_ENTRY Entry;
1201 HANDLE ProcessId;
1202 BOOL Ret;
1203
1204 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
1205
1206 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
1207 {
1208 ProcessId = PsGetCurrentProcessId();
1209
1210 Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
1211 Ret = Entry->KernelData != NULL &&
1212 (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
1213 (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcessId;
1214
1215 return Ret;
1216 }
1217
1218 return FALSE;
1219 }
1220
1221 BOOL INTERNAL_CALL
1222 GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
1223 {
1224 /*
1225 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1226 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1227 */
1228 PGDI_TABLE_ENTRY Entry;
1229 HANDLE ProcessId, LockedProcessId, PrevProcId;
1230 PTHREADINFO Thread;
1231 HGDIOBJ hObj;
1232
1233 GDIDBG_INITLOOPTRACE();
1234
1235 ASSERT(phObj);
1236 hObj = *phObj;
1237
1238 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj);
1239
1240 Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
1241
1242 if (!GDI_HANDLE_IS_STOCKOBJ(hObj))
1243 {
1244 ProcessId = PsGetCurrentProcessId();
1245 LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
1246
1247 Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
1248
1249 LockHandle:
1250 /* lock the object, we must not convert stock objects, so don't check!!! */
1251 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
1252 if (PrevProcId == ProcessId)
1253 {
1254 LONG NewType, PrevType, OldType;
1255
1256 /* we're locking an object that belongs to our process. First calculate
1257 the new object type including the stock object flag and then try to
1258 exchange it.*/
1259 /* On Windows the higher 16 bit of the type field don't contain the
1260 full type from the handle, but the base type.
1261 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1262 OldType = ((ULONG)hObj & GDI_HANDLE_BASETYPE_MASK) | ((ULONG)hObj >> GDI_ENTRY_UPPER_SHIFT);
1263 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1264 we copy them as we can't get them from the handle */
1265 OldType |= Entry->Type & GDI_ENTRY_FLAGS_MASK;
1266
1267 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1268 NewType = OldType | GDI_ENTRY_STOCK_MASK;
1269
1270 /* Try to exchange the type field - but only if the old (previous type) matches! */
1271 PrevType = InterlockedCompareExchange(&Entry->Type, NewType, OldType);
1272 if (PrevType == OldType && Entry->KernelData != NULL)
1273 {
1274 PTHREADINFO PrevThread;
1275 POBJ Object;
1276
1277 /* We successfully set the stock object flag.
1278 KernelData should never be NULL here!!! */
1279 ASSERT(Entry->KernelData);
1280
1281 Object = Entry->KernelData;
1282
1283 PrevThread = Object->Tid;
1284 if (Object->cExclusiveLock == 0 || PrevThread == Thread)
1285 {
1286 /* dereference the process' object counter */
1287 if (PrevProcId != GDI_GLOBAL_PROCESS)
1288 {
1289 PEPROCESS OldProcess;
1290 PPROCESSINFO W32Process;
1291 NTSTATUS Status;
1292
1293 /* FIXME */
1294 Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
1295 if (NT_SUCCESS(Status))
1296 {
1297 W32Process = (PPROCESSINFO)OldProcess->Win32Process;
1298 if (W32Process != NULL)
1299 {
1300 InterlockedDecrement(&W32Process->GDIHandleCount);
1301 }
1302 ObDereferenceObject(OldProcess);
1303 }
1304 }
1305
1306 hObj = (HGDIOBJ)((ULONG)(hObj) | GDI_HANDLE_STOCK_MASK);
1307 *phObj = hObj;
1308 Object->hHmgr = hObj;
1309
1310 /* remove the process id lock and make it global */
1311 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, GDI_GLOBAL_PROCESS);
1312
1313 /* we're done, successfully converted the object */
1314 return TRUE;
1315 }
1316 else
1317 {
1318 GDIDBG_TRACELOOP(hObj, PrevThread, Thread);
1319
1320 /* WTF?! The object is already locked by a different thread!
1321 Release the lock, wait a bit and try again!
1322 FIXME - we should give up after some time unless we want to wait forever! */
1323 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1324
1325 DelayExecution();
1326 goto LockHandle;
1327 }
1328 }
1329 else
1330 {
1331 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj);
1332 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType, Entry->Type, NewType, Entry->KernelData);
1333 }
1334 }
1335 else if (PrevProcId == LockedProcessId)
1336 {
1337 GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
1338
1339 /* the object is currently locked, wait some time and try again.
1340 FIXME - we shouldn't loop forever! Give up after some time! */
1341 DelayExecution();
1342 /* try again */
1343 goto LockHandle;
1344 }
1345 else
1346 {
1347 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj);
1348 }
1349 }
1350
1351 return FALSE;
1352 }
1353
1354 BOOL INTERNAL_CALL
1355 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
1356 {
1357 PGDI_TABLE_ENTRY Entry;
1358 HANDLE ProcessId, LockedProcessId, PrevProcId;
1359 PTHREADINFO Thread;
1360 BOOL Ret = TRUE;
1361
1362 GDIDBG_INITLOOPTRACE();
1363
1364 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0));
1365
1366 Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
1367
1368 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
1369 {
1370 ProcessId = PsGetCurrentProcessId();
1371 LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
1372
1373 Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
1374
1375 LockHandle:
1376 /* lock the object, we must not convert stock objects, so don't check!!! */
1377 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, ProcessId, LockedProcessId);
1378 if (PrevProcId == ProcessId)
1379 {
1380 PTHREADINFO PrevThread;
1381
1382 if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
1383 {
1384 POBJ Object = Entry->KernelData;
1385
1386 PrevThread = Object->Tid;
1387 if (Object->cExclusiveLock == 0 || PrevThread == Thread)
1388 {
1389 PEPROCESS OldProcess;
1390 PPROCESSINFO W32Process;
1391 NTSTATUS Status;
1392
1393 /* dereference the process' object counter */
1394 /* FIXME */
1395 if ((ULONG_PTR)PrevProcId & ~0x1)
1396 {
1397 Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
1398 if (NT_SUCCESS(Status))
1399 {
1400 W32Process = (PPROCESSINFO)OldProcess->Win32Process;
1401 if (W32Process != NULL)
1402 {
1403 InterlockedDecrement(&W32Process->GDIHandleCount);
1404 }
1405 ObDereferenceObject(OldProcess);
1406 }
1407 }
1408
1409 if (NewOwner != NULL)
1410 {
1411 ProcessId = PsGetProcessId(NewOwner);
1412
1413 /* Increase the new process' object counter */
1414 W32Process = (PPROCESSINFO)NewOwner->Win32Process;
1415 if (W32Process != NULL)
1416 {
1417 InterlockedIncrement(&W32Process->GDIHandleCount);
1418 }
1419 }
1420 else
1421 ProcessId = 0;
1422
1423 /* remove the process id lock and change it to the new process id */
1424 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, ProcessId);
1425
1426 /* we're done! */
1427 return Ret;
1428 }
1429 else
1430 {
1431 GDIDBG_TRACELOOP(ObjectHandle, PrevThread, Thread);
1432
1433 /* WTF?! The object is already locked by a different thread!
1434 Release the lock, wait a bit and try again! DO reset the pid lock
1435 so we make sure we don't access invalid memory in case the object is
1436 being deleted in the meantime (because we don't have aquired a reference
1437 at this point).
1438 FIXME - we should give up after some time unless we want to wait forever! */
1439 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1440
1441 DelayExecution();
1442 goto LockHandle;
1443 }
1444 }
1445 else
1446 {
1447 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle);
1448 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry->Type, Entry->KernelData);
1449 Ret = FALSE;
1450 }
1451 }
1452 else if (PrevProcId == LockedProcessId)
1453 {
1454 GDIDBG_TRACELOOP(ObjectHandle, PrevProcId, ProcessId);
1455
1456 /* the object is currently locked, wait some time and try again.
1457 FIXME - we shouldn't loop forever! Give up after some time! */
1458 DelayExecution();
1459 /* try again */
1460 goto LockHandle;
1461 }
1462 else if (((ULONG_PTR)PrevProcId & ~0x1) == 0)
1463 {
1464 /* allow changing ownership of global objects */
1465 ProcessId = NULL;
1466 LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
1467 goto LockHandle;
1468 }
1469 else if ((HANDLE)((ULONG_PTR)PrevProcId & ~0x1) != PsGetCurrentProcessId())
1470 {
1471 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle, (ULONG_PTR)PrevProcId & ~0x1, PsGetCurrentProcessId());
1472 Ret = FALSE;
1473 }
1474 else
1475 {
1476 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle);
1477 Ret = FALSE;
1478 }
1479 }
1480 return Ret;
1481 }
1482
1483 BOOL INTERNAL_CALL
1484 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
1485 {
1486 PGDI_TABLE_ENTRY FromEntry;
1487 PTHREADINFO Thread;
1488 HANDLE FromProcessId, FromLockedProcessId, FromPrevProcId;
1489 BOOL Ret = TRUE;
1490
1491 GDIDBG_INITLOOPTRACE();
1492
1493 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo);
1494
1495 Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
1496
1497 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo))
1498 {
1499 FromEntry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, CopyFrom);
1500
1501 FromProcessId = (HANDLE)((ULONG_PTR)FromEntry->ProcessId & ~0x1);
1502 FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
1503
1504 LockHandleFrom:
1505 /* lock the object, we must not convert stock objects, so don't check!!! */
1506 FromPrevProcId = InterlockedCompareExchangePointer((PVOID*)&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
1507 if (FromPrevProcId == FromProcessId)
1508 {
1509 PTHREADINFO PrevThread;
1510 POBJ Object;
1511
1512 if ((FromEntry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
1513 {
1514 Object = FromEntry->KernelData;
1515
1516 /* save the pointer to the calling thread so we know it was this thread
1517 that locked the object */
1518 PrevThread = Object->Tid;
1519 if (Object->cExclusiveLock == 0 || PrevThread == Thread)
1520 {
1521 /* now let's change the ownership of the target object */
1522
1523 if (((ULONG_PTR)FromPrevProcId & ~0x1) != 0)
1524 {
1525 PEPROCESS ProcessTo;
1526 /* FIXME */
1527 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1), &ProcessTo)))
1528 {
1529 GDIOBJ_SetOwnership(CopyTo, ProcessTo);
1530 ObDereferenceObject(ProcessTo);
1531 }
1532 }
1533 else
1534 {
1535 /* mark the object as global */
1536 GDIOBJ_SetOwnership(CopyTo, NULL);
1537 }
1538
1539 (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
1540 }
1541 else
1542 {
1543 GDIDBG_TRACELOOP(CopyFrom, PrevThread, Thread);
1544
1545 /* WTF?! The object is already locked by a different thread!
1546 Release the lock, wait a bit and try again! DO reset the pid lock
1547 so we make sure we don't access invalid memory in case the object is
1548 being deleted in the meantime (because we don't have aquired a reference
1549 at this point).
1550 FIXME - we should give up after some time unless we want to wait forever! */
1551 (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
1552
1553 DelayExecution();
1554 goto LockHandleFrom;
1555 }
1556 }
1557 else
1558 {
1559 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom);
1560 Ret = FALSE;
1561 }
1562 }
1563 else if (FromPrevProcId == FromLockedProcessId)
1564 {
1565 GDIDBG_TRACELOOP(CopyFrom, FromPrevProcId, FromProcessId);
1566
1567 /* the object is currently locked, wait some time and try again.
1568 FIXME - we shouldn't loop forever! Give up after some time! */
1569 DelayExecution();
1570 /* try again */
1571 goto LockHandleFrom;
1572 }
1573 else if ((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1) != PsGetCurrentProcessId())
1574 {
1575 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1576 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom, (ULONG_PTR)FromPrevProcId & ~0x1, PsGetCurrentProcessId());
1577 FromProcessId = (HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1);
1578 FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
1579 goto LockHandleFrom;
1580 }
1581 else
1582 {
1583 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom);
1584 Ret = FALSE;
1585 }
1586 }
1587 return Ret;
1588 }
1589
1590 PVOID INTERNAL_CALL
1591 GDI_MapHandleTable(PSECTION_OBJECT SectionObject, PEPROCESS Process)
1592 {
1593 PVOID MappedView = NULL;
1594 NTSTATUS Status;
1595 LARGE_INTEGER Offset;
1596 ULONG ViewSize = sizeof(GDI_HANDLE_TABLE);
1597
1598 Offset.QuadPart = 0;
1599
1600 ASSERT(SectionObject != NULL);
1601 ASSERT(Process != NULL);
1602
1603 Status = MmMapViewOfSection(SectionObject,
1604 Process,
1605 &MappedView,
1606 0,
1607 0,
1608 &Offset,
1609 &ViewSize,
1610 ViewUnmap,
1611 SEC_NO_CHANGE,
1612 PAGE_READONLY);
1613
1614 if (!NT_SUCCESS(Status))
1615 return NULL;
1616
1617 return MappedView;
1618 }
1619
1620 /** PUBLIC FUNCTIONS **********************************************************/
1621
1622 BOOL
1623 FASTCALL
1624 IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
1625 {
1626 INT Index;
1627 PGDI_TABLE_ENTRY Entry;
1628 /*
1629 System Regions:
1630 These regions do not use attribute sections and when allocated, use gdiobj
1631 level functions.
1632 */
1633 // FIXME! HAX!!! Remove this once we get everything right!
1634 Index = GDI_HANDLE_GET_INDEX(hRgn);
1635 Entry = &GdiHandleTable->Entries[Index];
1636 if (Entry->UserData) FreeObjectAttr(Entry->UserData);
1637 Entry->UserData = NULL;
1638 //
1639 if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
1640 {
1641 return GDIOBJ_SetOwnership(hRgn, NULL);
1642 }
1643 if (OwnerMask == GDI_OBJ_HMGR_POWNED)
1644 {
1645 return GDIOBJ_SetOwnership((HGDIOBJ) hRgn, PsGetCurrentProcess() );
1646 }
1647 return FALSE;
1648 }
1649
1650 BOOL
1651 FASTCALL
1652 IntGdiSetBrushOwner(PBRUSH pbr, DWORD OwnerMask)
1653 {
1654 HBRUSH hBR;
1655 PEPROCESS Owner = NULL;
1656 PGDI_TABLE_ENTRY pEntry = NULL;
1657
1658 if (!pbr) return FALSE;
1659
1660 hBR = pbr->BaseObject.hHmgr;
1661
1662 if (!hBR || (GDI_HANDLE_GET_TYPE(hBR) != GDI_OBJECT_TYPE_BRUSH))
1663 return FALSE;
1664 else
1665 {
1666 INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hBR);
1667 pEntry = &GdiHandleTable->Entries[Index];
1668 }
1669
1670 if (pbr->flAttrs & GDIBRUSH_IS_GLOBAL)
1671 {
1672 GDIOBJ_ShareUnlockObjByPtr((POBJ)pbr);
1673 return TRUE;
1674 }
1675
1676 if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
1677 {
1678 // Set this Brush to inaccessible mode and to an Owner of NONE.
1679 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1680
1681 if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, Owner))
1682 return FALSE;
1683
1684 // Deny user access to User Data.
1685 pEntry->UserData = NULL; // This hBR is inaccessible!
1686 }
1687
1688 if (OwnerMask == GDI_OBJ_HMGR_POWNED)
1689 {
1690 if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, PsGetCurrentProcess() ))
1691 return FALSE;
1692
1693 // Allow user access to User Data.
1694 pEntry->UserData = pbr->pBrushAttr;
1695 }
1696 return TRUE;
1697 }
1698
1699 BOOL
1700 FASTCALL
1701 IntGdiSetDCOwnerEx( HDC hDC, DWORD OwnerMask, BOOL NoSetBrush)
1702 {
1703 PDC pDC;
1704 BOOL Ret = FALSE;
1705
1706 if (!hDC || (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_DC)) return FALSE;
1707
1708 if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
1709 {
1710 pDC = DC_LockDc ( hDC );
1711 MmCopyFromCaller(&pDC->dcattr, pDC->pdcattr, sizeof(DC_ATTR));
1712 DC_UnlockDc( pDC );
1713
1714 DC_FreeDcAttr( hDC ); // Free the dcattr!
1715
1716 if (!DC_SetOwnership( hDC, NULL )) // This hDC is inaccessible!
1717 return Ret;
1718 }
1719
1720 if (OwnerMask == GDI_OBJ_HMGR_POWNED)
1721 {
1722 pDC = DC_LockDc ( hDC );
1723 ASSERT(pDC->pdcattr == &pDC->dcattr);
1724 DC_UnlockDc( pDC );
1725
1726 if (!DC_SetOwnership( hDC, PsGetCurrentProcess() )) return Ret;
1727
1728 DC_AllocateDcAttr( hDC ); // Allocate new dcattr
1729
1730 DCU_SynchDcAttrtoUser( hDC ); // Copy data from dc to dcattr
1731 }
1732
1733 if ((OwnerMask != GDI_OBJ_HMGR_NONE) && !NoSetBrush)
1734 {
1735 pDC = DC_LockDc ( hDC );
1736 if (IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrFill, OwnerMask))
1737 IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrLine, OwnerMask);
1738 DC_UnlockDc( pDC );
1739 }
1740 return TRUE;
1741 }
1742
1743 INT
1744 FASTCALL
1745 GreGetObjectOwner(HGDIOBJ Handle, GDIOBJTYPE ObjType)
1746 {
1747 INT Ret = GDI_OBJ_HMGR_RESTRICTED;
1748
1749 if ( GDI_HANDLE_GET_INDEX(Handle) < GDI_HANDLE_COUNT )
1750 {
1751 PGDI_TABLE_ENTRY pEntry = &GdiHandleTable->Entries[GDI_HANDLE_GET_INDEX(Handle)];
1752
1753 if (pEntry->ObjectType == ObjType)
1754 {
1755 if (pEntry->FullUnique == (GDI_HANDLE_GET_UPPER(Handle) >> GDI_ENTRY_UPPER_SHIFT))
1756 Ret = pEntry->ProcessId & ~1;
1757 }
1758 }
1759 return Ret;
1760 }
1761
1762 W32KAPI
1763 HANDLE
1764 APIENTRY
1765 NtGdiCreateClientObj(
1766 IN ULONG ulType
1767 )
1768 {
1769 POBJ pObject;
1770 HANDLE handle;
1771
1772 /* Mask out everything that would change the type in a wrong manner */
1773 ulType &= (GDI_HANDLE_TYPE_MASK & ~GDI_HANDLE_BASETYPE_MASK);
1774
1775 /* Allocate a new object */
1776 pObject = GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ | ulType);
1777 if (!pObject)
1778 {
1779 return NULL;
1780 }
1781
1782 /* get the handle */
1783 handle = pObject->hHmgr;
1784
1785 /* Unlock it */
1786 GDIOBJ_UnlockObjByPtr(pObject);
1787
1788 return handle;
1789 }
1790
1791 W32KAPI
1792 BOOL
1793 APIENTRY
1794 NtGdiDeleteClientObj(
1795 IN HANDLE h
1796 )
1797 {
1798 /* We first need to get the real type from the handle */
1799 ULONG type = GDI_HANDLE_GET_TYPE(h);
1800
1801 /* Check if it's really a CLIENTOBJ */
1802 if ((type & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE)
1803 {
1804 /* FIXME: SetLastError? */
1805 return FALSE;
1806 }
1807 return GDIOBJ_FreeObjByHandle(h, type);
1808 }
1809
1810 INT
1811 FASTCALL
1812 IntGdiGetObject(IN HANDLE Handle,
1813 IN INT cbCount,
1814 IN LPVOID lpBuffer)
1815 {
1816 PVOID pGdiObject;
1817 INT Result = 0;
1818 DWORD dwObjectType;
1819
1820 pGdiObject = GDIOBJ_LockObj(Handle, GDI_OBJECT_TYPE_DONTCARE);
1821 if (!pGdiObject)
1822 {
1823 SetLastWin32Error(ERROR_INVALID_HANDLE);
1824 return 0;
1825 }
1826
1827 dwObjectType = GDIOBJ_GetObjectType(Handle);
1828 switch (dwObjectType)
1829 {
1830 case GDI_OBJECT_TYPE_PEN:
1831 case GDI_OBJECT_TYPE_EXTPEN:
1832 Result = PEN_GetObject((PBRUSH) pGdiObject, cbCount, (PLOGPEN) lpBuffer); // IntGdiCreatePenIndirect
1833 break;
1834
1835 case GDI_OBJECT_TYPE_BRUSH:
1836 Result = BRUSH_GetObject((PBRUSH ) pGdiObject, cbCount, (LPLOGBRUSH)lpBuffer);
1837 break;
1838
1839 case GDI_OBJECT_TYPE_BITMAP:
1840 Result = BITMAP_GetObject((SURFACE *) pGdiObject, cbCount, lpBuffer);
1841 break;
1842 case GDI_OBJECT_TYPE_FONT:
1843 Result = FontGetObject((PTEXTOBJ) pGdiObject, cbCount, lpBuffer);
1844 #if 0
1845 // Fix the LOGFONT structure for the stock fonts
1846 if (FIRST_STOCK_HANDLE <= Handle && Handle <= LAST_STOCK_HANDLE)
1847 {
1848 FixStockFontSizeW(Handle, cbCount, lpBuffer);
1849 }
1850 #endif
1851 break;
1852
1853 case GDI_OBJECT_TYPE_PALETTE:
1854 Result = PALETTE_GetObject((PPALETTE) pGdiObject, cbCount, lpBuffer);
1855 break;
1856
1857 default:
1858 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType);
1859 break;
1860 }
1861
1862 GDIOBJ_UnlockObjByPtr(pGdiObject);
1863
1864 return Result;
1865 }
1866
1867
1868
1869 W32KAPI
1870 INT
1871 APIENTRY
1872 NtGdiExtGetObjectW(IN HANDLE hGdiObj,
1873 IN INT cbCount,
1874 OUT LPVOID lpBuffer)
1875 {
1876 INT iRetCount = 0;
1877 INT cbCopyCount;
1878 union
1879 {
1880 BITMAP bitmap;
1881 DIBSECTION dibsection;
1882 LOGPEN logpen;
1883 LOGBRUSH logbrush;
1884 LOGFONTW logfontw;
1885 EXTLOGFONTW extlogfontw;
1886 ENUMLOGFONTEXDVW enumlogfontexdvw;
1887 } Object;
1888
1889 // Normalize to the largest supported object size
1890 cbCount = min((UINT)cbCount, sizeof(Object));
1891
1892 // Now do the actual call
1893 iRetCount = IntGdiGetObject(hGdiObj, cbCount, lpBuffer ? &Object : NULL);
1894 cbCopyCount = min((UINT)cbCount, (UINT)iRetCount);
1895
1896 // Make sure we have a buffer and a copy size
1897 if ((cbCopyCount) && (lpBuffer))
1898 {
1899 // Enter SEH for buffer transfer
1900 _SEH2_TRY
1901 {
1902 // Probe the buffer and copy it
1903 ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD));
1904 RtlCopyMemory(lpBuffer, &Object, cbCopyCount);
1905 }
1906 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1907 {
1908 // Clear the return value.
1909 // Do *NOT* set last error here!
1910 iRetCount = 0;
1911 }
1912 _SEH2_END;
1913 }
1914 // Return the count
1915 return iRetCount;
1916 }
1917
1918 /* EOF */