[WIN32K]
[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 <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
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 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 GDIDBG_INITLOOPTRACE();
956
957 HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
958 HandleType = GDI_HANDLE_GET_TYPE(hObj);
959 HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
960
961 /* Check that the handle index is valid. */
962 if (HandleIndex >= GDI_HANDLE_COUNT)
963 return NULL;
964
965 Entry = &GdiHandleTable->Entries[HandleIndex];
966
967 /* Check if we have the requested type */
968 if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
969 HandleType != ExpectedType) ||
970 HandleType == 0 )
971 {
972 DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
973 hObj, HandleType, ExpectedType);
974 GDIDBG_TRACECALLER();
975 GDIDBG_TRACEALLOCATOR(hObj);
976 GDIDBG_TRACEDELETER(hObj);
977 return NULL;
978 }
979
980 ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
981 HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
982
983 /* Check for invalid owner. */
984 if (ProcessId != HandleProcessId && HandleProcessId != NULL)
985 {
986 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj, ProcessId, HandleProcessId);
987 GDIDBG_TRACECALLER();
988 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj));
989 return NULL;
990 }
991
992 /*
993 * Prevent the thread from being terminated during the locking process.
994 * It would result in undesired effects and inconsistency of the global
995 * handle table.
996 */
997
998 KeEnterCriticalRegion();
999
1000 /*
1001 * Loop until we either successfully lock the handle entry & object or
1002 * fail some of the check.
1003 */
1004
1005 for (;;)
1006 {
1007 /* Lock the handle table entry. */
1008 LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
1009 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
1010 LockedProcessId,
1011 HandleProcessId);
1012
1013 if (PrevProcId == HandleProcessId)
1014 {
1015 /*
1016 * We're locking an object that belongs to our process or it's a
1017 * global object if HandleProcessId is 0 here.
1018 */
1019
1020 if ( (Entry->KernelData != NULL) &&
1021 ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
1022 {
1023 PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
1024 Object = Entry->KernelData;
1025
1026 if (Object->cExclusiveLock == 0)
1027 {
1028 Object->Tid = Thread;
1029 Object->cExclusiveLock = 1;
1030 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj))
1031 }
1032 else
1033 {
1034 if (Object->Tid != Thread)
1035 {
1036 GDIDBG_TRACELOOP(hObj, Object->Tid, Thread);
1037 GDIDBG_TRACECALLER();
1038 GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj));
1039 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj));
1040
1041 /* Unlock the handle table entry. */
1042 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1043
1044 DelayExecution();
1045 continue;
1046 }
1047 InterlockedIncrement((PLONG)&Object->cExclusiveLock);
1048 }
1049 }
1050 else
1051 {
1052 /*
1053 * Debugging code. Report attempts to lock deleted handles and
1054 * locking type mismatches.
1055 */
1056 LockErrorDebugOutput(hObj, Entry, "GDIOBJ_LockObj");
1057 }
1058
1059 /* Unlock the handle table entry. */
1060 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1061
1062 break;
1063 }
1064 else
1065 {
1066 /*
1067 * The handle is currently locked, wait some time and try again.
1068 */
1069 GDIDBG_TRACELOOP(hObj, PrevProcId, NULL);
1070
1071 DelayExecution();
1072 continue;
1073 }
1074 }
1075
1076 KeLeaveCriticalRegion();
1077
1078 return Object;
1079 }
1080
1081
1082 /*!
1083 * Return pointer to the object by handle (and allow sharing of the handle
1084 * across threads).
1085 *
1086 * \param hObj Object handle
1087 * \return Pointer to the object.
1088 *
1089 * \note Process can only get pointer to the objects it created or global objects.
1090 *
1091 * \todo Get rid of the ExpectedType parameter!
1092 */
1093 PGDIOBJ INTERNAL_CALL
1094 GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
1095 {
1096 ULONG HandleIndex;
1097 PGDI_TABLE_ENTRY Entry;
1098 HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
1099 POBJ Object = NULL;
1100 ULONG_PTR HandleType, HandleUpper;
1101
1102 HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
1103 HandleType = GDI_HANDLE_GET_TYPE(hObj);
1104 HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
1105
1106 /* Check that the handle index is valid. */
1107 if (HandleIndex >= GDI_HANDLE_COUNT)
1108 return NULL;
1109
1110 /* Check if we have the requested type */
1111 if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
1112 HandleType != ExpectedType) ||
1113 HandleType == 0 )
1114 {
1115 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1116 hObj, HandleType, ExpectedType);
1117 return NULL;
1118 }
1119
1120 Entry = &GdiHandleTable->Entries[HandleIndex];
1121
1122 ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
1123 HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
1124
1125 /* Check for invalid owner. */
1126 if (ProcessId != HandleProcessId && HandleProcessId != NULL)
1127 {
1128 return NULL;
1129 }
1130
1131 /*
1132 * Prevent the thread from being terminated during the locking process.
1133 * It would result in undesired effects and inconsistency of the global
1134 * handle table.
1135 */
1136
1137 KeEnterCriticalRegion();
1138
1139 /*
1140 * Loop until we either successfully lock the handle entry & object or
1141 * fail some of the check.
1142 */
1143
1144 for (;;)
1145 {
1146 /* Lock the handle table entry. */
1147 LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
1148 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
1149 LockedProcessId,
1150 HandleProcessId);
1151
1152 if (PrevProcId == HandleProcessId)
1153 {
1154 /*
1155 * We're locking an object that belongs to our process or it's a
1156 * global object if HandleProcessId is 0 here.
1157 */
1158
1159 if ( (Entry->KernelData != NULL) &&
1160 (HandleUpper == (Entry->Type << GDI_ENTRY_UPPER_SHIFT)) )
1161 {
1162 Object = (POBJ)Entry->KernelData;
1163
1164 GDIDBG_CAPTURESHARELOCKER(HandleIndex);
1165 #ifdef GDI_DEBUG3
1166 if (InterlockedIncrement((PLONG)&Object->ulShareCount) == 1)
1167 {
1168 memset(GDIHandleLocker[HandleIndex], 0x00, GDI_STACK_LEVELS * sizeof(ULONG));
1169 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleShareLocker[HandleIndex], NULL);
1170 }
1171 #else
1172 InterlockedIncrement((PLONG)&Object->ulShareCount);
1173 #endif
1174 }
1175 else
1176 {
1177 /*
1178 * Debugging code. Report attempts to lock deleted handles and
1179 * locking type mismatches.
1180 */
1181 LockErrorDebugOutput(hObj, Entry, "GDIOBJ_ShareLockObj");
1182 }
1183
1184 /* Unlock the handle table entry. */
1185 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1186
1187 break;
1188 }
1189 else
1190 {
1191 /*
1192 * The handle is currently locked, wait some time and try again.
1193 */
1194
1195 DelayExecution();
1196 continue;
1197 }
1198 }
1199
1200 KeLeaveCriticalRegion();
1201
1202 return Object;
1203 }
1204
1205 BOOL INTERNAL_CALL
1206 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle)
1207 {
1208 PGDI_TABLE_ENTRY Entry;
1209 HANDLE ProcessId;
1210 BOOL Ret;
1211
1212 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
1213
1214 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
1215 {
1216 ProcessId = PsGetCurrentProcessId();
1217
1218 Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
1219 Ret = Entry->KernelData != NULL &&
1220 (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
1221 (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcessId;
1222
1223 return Ret;
1224 }
1225
1226 return FALSE;
1227 }
1228
1229 BOOL INTERNAL_CALL
1230 GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
1231 {
1232 /*
1233 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1234 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1235 */
1236 PGDI_TABLE_ENTRY Entry;
1237 HANDLE ProcessId, LockedProcessId, PrevProcId;
1238 PTHREADINFO Thread;
1239 HGDIOBJ hObj;
1240
1241 GDIDBG_INITLOOPTRACE();
1242
1243 ASSERT(phObj);
1244 hObj = *phObj;
1245
1246 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj);
1247
1248 Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
1249
1250 if (!GDI_HANDLE_IS_STOCKOBJ(hObj))
1251 {
1252 ProcessId = PsGetCurrentProcessId();
1253 LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
1254
1255 Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
1256
1257 LockHandle:
1258 /* lock the object, we must not convert stock objects, so don't check!!! */
1259 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
1260 if (PrevProcId == ProcessId)
1261 {
1262 LONG NewType, PrevType, OldType;
1263
1264 /* we're locking an object that belongs to our process. First calculate
1265 the new object type including the stock object flag and then try to
1266 exchange it.*/
1267 /* On Windows the higher 16 bit of the type field don't contain the
1268 full type from the handle, but the base type.
1269 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1270 OldType = ((ULONG)hObj & GDI_HANDLE_BASETYPE_MASK) | ((ULONG)hObj >> GDI_ENTRY_UPPER_SHIFT);
1271 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1272 we copy them as we can't get them from the handle */
1273 OldType |= Entry->Type & GDI_ENTRY_FLAGS_MASK;
1274
1275 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1276 NewType = OldType | GDI_ENTRY_STOCK_MASK;
1277
1278 /* Try to exchange the type field - but only if the old (previous type) matches! */
1279 PrevType = InterlockedCompareExchange(&Entry->Type, NewType, OldType);
1280 if (PrevType == OldType && Entry->KernelData != NULL)
1281 {
1282 PTHREADINFO PrevThread;
1283 POBJ Object;
1284
1285 /* We successfully set the stock object flag.
1286 KernelData should never be NULL here!!! */
1287 ASSERT(Entry->KernelData);
1288
1289 Object = Entry->KernelData;
1290
1291 PrevThread = Object->Tid;
1292 if (Object->cExclusiveLock == 0 || PrevThread == Thread)
1293 {
1294 /* dereference the process' object counter */
1295 if (PrevProcId != GDI_GLOBAL_PROCESS)
1296 {
1297 PEPROCESS OldProcess;
1298 PPROCESSINFO W32Process;
1299 NTSTATUS Status;
1300
1301 /* FIXME */
1302 Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
1303 if (NT_SUCCESS(Status))
1304 {
1305 W32Process = (PPROCESSINFO)OldProcess->Win32Process;
1306 if (W32Process != NULL)
1307 {
1308 InterlockedDecrement(&W32Process->GDIHandleCount);
1309 }
1310 ObDereferenceObject(OldProcess);
1311 }
1312 }
1313
1314 hObj = (HGDIOBJ)((ULONG)(hObj) | GDI_HANDLE_STOCK_MASK);
1315 *phObj = hObj;
1316 Object->hHmgr = hObj;
1317
1318 /* remove the process id lock and make it global */
1319 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, GDI_GLOBAL_PROCESS);
1320
1321 /* we're done, successfully converted the object */
1322 return TRUE;
1323 }
1324 else
1325 {
1326 GDIDBG_TRACELOOP(hObj, PrevThread, Thread);
1327
1328 /* WTF?! The object is already locked by a different thread!
1329 Release the lock, wait a bit and try again!
1330 FIXME - we should give up after some time unless we want to wait forever! */
1331 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1332
1333 DelayExecution();
1334 goto LockHandle;
1335 }
1336 }
1337 else
1338 {
1339 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj);
1340 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType, Entry->Type, NewType, Entry->KernelData);
1341 }
1342 }
1343 else if (PrevProcId == LockedProcessId)
1344 {
1345 GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
1346
1347 /* the object is currently locked, wait some time and try again.
1348 FIXME - we shouldn't loop forever! Give up after some time! */
1349 DelayExecution();
1350 /* try again */
1351 goto LockHandle;
1352 }
1353 else
1354 {
1355 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj);
1356 }
1357 }
1358
1359 return FALSE;
1360 }
1361
1362 BOOL INTERNAL_CALL
1363 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
1364 {
1365 PGDI_TABLE_ENTRY Entry;
1366 HANDLE ProcessId, LockedProcessId, PrevProcId;
1367 PTHREADINFO Thread;
1368 BOOL Ret = TRUE;
1369
1370 GDIDBG_INITLOOPTRACE();
1371
1372 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0));
1373
1374 Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
1375
1376 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
1377 {
1378 ProcessId = PsGetCurrentProcessId();
1379 LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
1380
1381 Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
1382
1383 LockHandle:
1384 /* lock the object, we must not convert stock objects, so don't check!!! */
1385 PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, ProcessId, LockedProcessId);
1386 if (PrevProcId == ProcessId)
1387 {
1388 PTHREADINFO PrevThread;
1389
1390 if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
1391 {
1392 POBJ Object = Entry->KernelData;
1393
1394 PrevThread = Object->Tid;
1395 if (Object->cExclusiveLock == 0 || PrevThread == Thread)
1396 {
1397 PEPROCESS OldProcess;
1398 PPROCESSINFO W32Process;
1399 NTSTATUS Status;
1400
1401 /* dereference the process' object counter */
1402 /* FIXME */
1403 if ((ULONG_PTR)PrevProcId & ~0x1)
1404 {
1405 Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
1406 if (NT_SUCCESS(Status))
1407 {
1408 W32Process = (PPROCESSINFO)OldProcess->Win32Process;
1409 if (W32Process != NULL)
1410 {
1411 InterlockedDecrement(&W32Process->GDIHandleCount);
1412 }
1413 ObDereferenceObject(OldProcess);
1414 }
1415 }
1416
1417 if (NewOwner != NULL)
1418 {
1419 ProcessId = PsGetProcessId(NewOwner);
1420
1421 /* Increase the new process' object counter */
1422 W32Process = (PPROCESSINFO)NewOwner->Win32Process;
1423 if (W32Process != NULL)
1424 {
1425 InterlockedIncrement(&W32Process->GDIHandleCount);
1426 }
1427 }
1428 else
1429 ProcessId = 0;
1430
1431 /* remove the process id lock and change it to the new process id */
1432 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, ProcessId);
1433
1434 /* we're done! */
1435 return Ret;
1436 }
1437 else
1438 {
1439 GDIDBG_TRACELOOP(ObjectHandle, PrevThread, Thread);
1440
1441 /* WTF?! The object is already locked by a different thread!
1442 Release the lock, wait a bit and try again! DO reset the pid lock
1443 so we make sure we don't access invalid memory in case the object is
1444 being deleted in the meantime (because we don't have aquired a reference
1445 at this point).
1446 FIXME - we should give up after some time unless we want to wait forever! */
1447 (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
1448
1449 DelayExecution();
1450 goto LockHandle;
1451 }
1452 }
1453 else
1454 {
1455 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle);
1456 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry->Type, Entry->KernelData);
1457 Ret = FALSE;
1458 }
1459 }
1460 else if (PrevProcId == LockedProcessId)
1461 {
1462 GDIDBG_TRACELOOP(ObjectHandle, PrevProcId, ProcessId);
1463
1464 /* the object is currently locked, wait some time and try again.
1465 FIXME - we shouldn't loop forever! Give up after some time! */
1466 DelayExecution();
1467 /* try again */
1468 goto LockHandle;
1469 }
1470 else if (((ULONG_PTR)PrevProcId & ~0x1) == 0)
1471 {
1472 /* allow changing ownership of global objects */
1473 ProcessId = NULL;
1474 LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
1475 goto LockHandle;
1476 }
1477 else if ((HANDLE)((ULONG_PTR)PrevProcId & ~0x1) != PsGetCurrentProcessId())
1478 {
1479 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle, (ULONG_PTR)PrevProcId & ~0x1, PsGetCurrentProcessId());
1480 Ret = FALSE;
1481 }
1482 else
1483 {
1484 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle);
1485 Ret = FALSE;
1486 }
1487 }
1488 return Ret;
1489 }
1490
1491 BOOL INTERNAL_CALL
1492 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
1493 {
1494 PGDI_TABLE_ENTRY FromEntry;
1495 PTHREADINFO Thread;
1496 HANDLE FromProcessId, FromLockedProcessId, FromPrevProcId;
1497 BOOL Ret = TRUE;
1498
1499 GDIDBG_INITLOOPTRACE();
1500
1501 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo);
1502
1503 Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
1504
1505 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo))
1506 {
1507 FromEntry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, CopyFrom);
1508
1509 FromProcessId = (HANDLE)((ULONG_PTR)FromEntry->ProcessId & ~0x1);
1510 FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
1511
1512 LockHandleFrom:
1513 /* lock the object, we must not convert stock objects, so don't check!!! */
1514 FromPrevProcId = InterlockedCompareExchangePointer((PVOID*)&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
1515 if (FromPrevProcId == FromProcessId)
1516 {
1517 PTHREADINFO PrevThread;
1518 POBJ Object;
1519
1520 if ((FromEntry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
1521 {
1522 Object = FromEntry->KernelData;
1523
1524 /* save the pointer to the calling thread so we know it was this thread
1525 that locked the object */
1526 PrevThread = Object->Tid;
1527 if (Object->cExclusiveLock == 0 || PrevThread == Thread)
1528 {
1529 /* now let's change the ownership of the target object */
1530
1531 if (((ULONG_PTR)FromPrevProcId & ~0x1) != 0)
1532 {
1533 PEPROCESS ProcessTo;
1534 /* FIXME */
1535 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1), &ProcessTo)))
1536 {
1537 GDIOBJ_SetOwnership(CopyTo, ProcessTo);
1538 ObDereferenceObject(ProcessTo);
1539 }
1540 }
1541 else
1542 {
1543 /* mark the object as global */
1544 GDIOBJ_SetOwnership(CopyTo, NULL);
1545 }
1546
1547 (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
1548 }
1549 else
1550 {
1551 GDIDBG_TRACELOOP(CopyFrom, PrevThread, Thread);
1552
1553 /* WTF?! The object is already locked by a different thread!
1554 Release the lock, wait a bit and try again! DO reset the pid lock
1555 so we make sure we don't access invalid memory in case the object is
1556 being deleted in the meantime (because we don't have aquired a reference
1557 at this point).
1558 FIXME - we should give up after some time unless we want to wait forever! */
1559 (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
1560
1561 DelayExecution();
1562 goto LockHandleFrom;
1563 }
1564 }
1565 else
1566 {
1567 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom);
1568 Ret = FALSE;
1569 }
1570 }
1571 else if (FromPrevProcId == FromLockedProcessId)
1572 {
1573 GDIDBG_TRACELOOP(CopyFrom, FromPrevProcId, FromProcessId);
1574
1575 /* the object is currently locked, wait some time and try again.
1576 FIXME - we shouldn't loop forever! Give up after some time! */
1577 DelayExecution();
1578 /* try again */
1579 goto LockHandleFrom;
1580 }
1581 else if ((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1) != PsGetCurrentProcessId())
1582 {
1583 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1584 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom, (ULONG_PTR)FromPrevProcId & ~0x1, PsGetCurrentProcessId());
1585 FromProcessId = (HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1);
1586 FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
1587 goto LockHandleFrom;
1588 }
1589 else
1590 {
1591 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom);
1592 Ret = FALSE;
1593 }
1594 }
1595 return Ret;
1596 }
1597
1598 PVOID INTERNAL_CALL
1599 GDI_MapHandleTable(PSECTION_OBJECT SectionObject, PEPROCESS Process)
1600 {
1601 PVOID MappedView = NULL;
1602 NTSTATUS Status;
1603 LARGE_INTEGER Offset;
1604 ULONG ViewSize = sizeof(GDI_HANDLE_TABLE);
1605
1606 Offset.QuadPart = 0;
1607
1608 ASSERT(SectionObject != NULL);
1609 ASSERT(Process != NULL);
1610
1611 Status = MmMapViewOfSection(SectionObject,
1612 Process,
1613 &MappedView,
1614 0,
1615 0,
1616 &Offset,
1617 &ViewSize,
1618 ViewUnmap,
1619 SEC_NO_CHANGE,
1620 PAGE_READONLY);
1621
1622 if (!NT_SUCCESS(Status))
1623 return NULL;
1624
1625 return MappedView;
1626 }
1627
1628 /* Locks multiple objects at a time */
1629 VOID
1630 INTERNAL_CALL
1631 GDIOBJ_LockMultipleObjs(ULONG ulCount,
1632 IN HGDIOBJ* ahObj,
1633 OUT PGDIOBJ* apObj)
1634 {
1635 UINT i;
1636 HGDIOBJ hTmp ;
1637 BOOL unsorted = TRUE;
1638 /* We bubble-sort them */
1639 while(unsorted)
1640 {
1641 unsorted = FALSE ;
1642 for(i=0; i<ulCount - 1; i++)
1643 {
1644 /* The greatest the first */
1645 if((ULONG_PTR)ahObj[i] < (ULONG_PTR)ahObj[i+1])
1646 {
1647 hTmp = ahObj[i];
1648 ahObj[i]=ahObj[i+1];
1649 ahObj[i+1] = hTmp;
1650 unsorted = TRUE ;
1651 }
1652 }
1653 }
1654 /* Then we lock them */
1655 for(i=0; i<ulCount; i++)
1656 {
1657 apObj[i]=GDIOBJ_LockObj(ahObj[i], GDI_OBJECT_TYPE_DONTCARE);
1658 }
1659 }
1660
1661
1662 /** PUBLIC FUNCTIONS **********************************************************/
1663
1664 BOOL
1665 FASTCALL
1666 IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
1667 {
1668 INT Index;
1669 PGDI_TABLE_ENTRY Entry;
1670 /*
1671 System Regions:
1672 These regions do not use attribute sections and when allocated, use gdiobj
1673 level functions.
1674 */
1675 // FIXME! HAX!!! Remove this once we get everything right!
1676 Index = GDI_HANDLE_GET_INDEX(hRgn);
1677 Entry = &GdiHandleTable->Entries[Index];
1678 if (Entry->UserData) FreeObjectAttr(Entry->UserData);
1679 Entry->UserData = NULL;
1680 //
1681 if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
1682 {
1683 return GDIOBJ_SetOwnership(hRgn, NULL);
1684 }
1685 if (OwnerMask == GDI_OBJ_HMGR_POWNED)
1686 {
1687 return GDIOBJ_SetOwnership((HGDIOBJ) hRgn, PsGetCurrentProcess() );
1688 }
1689 return FALSE;
1690 }
1691
1692 BOOL
1693 FASTCALL
1694 IntGdiSetBrushOwner(PBRUSH pbr, DWORD OwnerMask)
1695 {
1696 HBRUSH hBR;
1697 PEPROCESS Owner = NULL;
1698 PGDI_TABLE_ENTRY pEntry = NULL;
1699
1700 if (!pbr) return FALSE;
1701
1702 hBR = pbr->BaseObject.hHmgr;
1703
1704 if (!hBR || (GDI_HANDLE_GET_TYPE(hBR) != GDI_OBJECT_TYPE_BRUSH))
1705 return FALSE;
1706 else
1707 {
1708 INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hBR);
1709 pEntry = &GdiHandleTable->Entries[Index];
1710 }
1711
1712 if (pbr->flAttrs & GDIBRUSH_IS_GLOBAL)
1713 {
1714 GDIOBJ_ShareUnlockObjByPtr((POBJ)pbr);
1715 return TRUE;
1716 }
1717
1718 if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
1719 {
1720 // Set this Brush to inaccessible mode and to an Owner of NONE.
1721 // if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
1722
1723 if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, Owner))
1724 return FALSE;
1725
1726 // Deny user access to User Data.
1727 pEntry->UserData = NULL; // This hBR is inaccessible!
1728 }
1729
1730 if (OwnerMask == GDI_OBJ_HMGR_POWNED)
1731 {
1732 if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, PsGetCurrentProcess() ))
1733 return FALSE;
1734
1735 // Allow user access to User Data.
1736 pEntry->UserData = pbr->pBrushAttr;
1737 }
1738 return TRUE;
1739 }
1740
1741 BOOL
1742 FASTCALL
1743 IntGdiSetDCOwnerEx( HDC hDC, DWORD OwnerMask, BOOL NoSetBrush)
1744 {
1745 PDC pDC;
1746 BOOL Ret = FALSE;
1747
1748 if (!hDC || (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_DC)) return FALSE;
1749
1750 if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
1751 {
1752 pDC = DC_LockDc ( hDC );
1753 MmCopyFromCaller(&pDC->dcattr, pDC->pdcattr, sizeof(DC_ATTR));
1754 DC_vFreeDcAttr(pDC);
1755 DC_UnlockDc( pDC );
1756
1757 if (!DC_SetOwnership( hDC, NULL )) // This hDC is inaccessible!
1758 return Ret;
1759 }
1760
1761 if (OwnerMask == GDI_OBJ_HMGR_POWNED)
1762 {
1763 pDC = DC_LockDc ( hDC );
1764 ASSERT(pDC->pdcattr == &pDC->dcattr);
1765 DC_UnlockDc( pDC );
1766
1767 if (!DC_SetOwnership( hDC, PsGetCurrentProcess() )) return Ret;
1768
1769 DC_AllocateDcAttr( hDC ); // Allocate new dcattr
1770
1771 DCU_SynchDcAttrtoUser( hDC ); // Copy data from dc to dcattr
1772 }
1773
1774 if ((OwnerMask != GDI_OBJ_HMGR_NONE) && !NoSetBrush)
1775 {
1776 pDC = DC_LockDc ( hDC );
1777 if (IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrFill, OwnerMask))
1778 IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrLine, OwnerMask);
1779 DC_UnlockDc( pDC );
1780 }
1781 return TRUE;
1782 }
1783
1784 INT
1785 FASTCALL
1786 GreGetObjectOwner(HGDIOBJ Handle, GDIOBJTYPE ObjType)
1787 {
1788 INT Ret = GDI_OBJ_HMGR_RESTRICTED;
1789
1790 if ( GDI_HANDLE_GET_INDEX(Handle) < GDI_HANDLE_COUNT )
1791 {
1792 PGDI_TABLE_ENTRY pEntry = &GdiHandleTable->Entries[GDI_HANDLE_GET_INDEX(Handle)];
1793
1794 if (pEntry->ObjectType == ObjType)
1795 {
1796 if (pEntry->FullUnique == (GDI_HANDLE_GET_UPPER(Handle) >> GDI_ENTRY_UPPER_SHIFT))
1797 Ret = pEntry->ProcessId & ~1;
1798 }
1799 }
1800 return Ret;
1801 }
1802
1803 W32KAPI
1804 HANDLE
1805 APIENTRY
1806 NtGdiCreateClientObj(
1807 IN ULONG ulType
1808 )
1809 {
1810 POBJ pObject;
1811 HANDLE handle;
1812
1813 /* Mask out everything that would change the type in a wrong manner */
1814 ulType &= (GDI_HANDLE_TYPE_MASK & ~GDI_HANDLE_BASETYPE_MASK);
1815
1816 /* Allocate a new object */
1817 pObject = GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ | ulType);
1818 if (!pObject)
1819 {
1820 return NULL;
1821 }
1822
1823 /* get the handle */
1824 handle = pObject->hHmgr;
1825
1826 /* Unlock it */
1827 GDIOBJ_UnlockObjByPtr(pObject);
1828
1829 return handle;
1830 }
1831
1832 W32KAPI
1833 BOOL
1834 APIENTRY
1835 NtGdiDeleteClientObj(
1836 IN HANDLE h
1837 )
1838 {
1839 /* We first need to get the real type from the handle */
1840 ULONG type = GDI_HANDLE_GET_TYPE(h);
1841
1842 /* Check if it's really a CLIENTOBJ */
1843 if ((type & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE)
1844 {
1845 /* FIXME: SetLastError? */
1846 return FALSE;
1847 }
1848 return GDIOBJ_FreeObjByHandle(h, type);
1849 }
1850
1851 INT
1852 FASTCALL
1853 IntGdiGetObject(IN HANDLE Handle,
1854 IN INT cbCount,
1855 IN LPVOID lpBuffer)
1856 {
1857 PVOID pGdiObject;
1858 INT Result = 0;
1859 DWORD dwObjectType;
1860
1861 pGdiObject = GDIOBJ_LockObj(Handle, GDI_OBJECT_TYPE_DONTCARE);
1862 if (!pGdiObject)
1863 {
1864 SetLastWin32Error(ERROR_INVALID_HANDLE);
1865 return 0;
1866 }
1867
1868 dwObjectType = GDIOBJ_GetObjectType(Handle);
1869 switch (dwObjectType)
1870 {
1871 case GDI_OBJECT_TYPE_PEN:
1872 case GDI_OBJECT_TYPE_EXTPEN:
1873 Result = PEN_GetObject((PBRUSH) pGdiObject, cbCount, (PLOGPEN) lpBuffer); // IntGdiCreatePenIndirect
1874 break;
1875
1876 case GDI_OBJECT_TYPE_BRUSH:
1877 Result = BRUSH_GetObject((PBRUSH ) pGdiObject, cbCount, (LPLOGBRUSH)lpBuffer);
1878 break;
1879
1880 case GDI_OBJECT_TYPE_BITMAP:
1881 Result = BITMAP_GetObject((SURFACE *) pGdiObject, cbCount, lpBuffer);
1882 break;
1883 case GDI_OBJECT_TYPE_FONT:
1884 Result = FontGetObject((PTEXTOBJ) pGdiObject, cbCount, lpBuffer);
1885 #if 0
1886 // Fix the LOGFONT structure for the stock fonts
1887 if (FIRST_STOCK_HANDLE <= Handle && Handle <= LAST_STOCK_HANDLE)
1888 {
1889 FixStockFontSizeW(Handle, cbCount, lpBuffer);
1890 }
1891 #endif
1892 break;
1893
1894 case GDI_OBJECT_TYPE_PALETTE:
1895 Result = PALETTE_GetObject((PPALETTE) pGdiObject, cbCount, lpBuffer);
1896 break;
1897
1898 default:
1899 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType);
1900 break;
1901 }
1902
1903 GDIOBJ_UnlockObjByPtr(pGdiObject);
1904
1905 return Result;
1906 }
1907
1908
1909
1910 W32KAPI
1911 INT
1912 APIENTRY
1913 NtGdiExtGetObjectW(IN HANDLE hGdiObj,
1914 IN INT cbCount,
1915 OUT LPVOID lpBuffer)
1916 {
1917 INT iRetCount = 0;
1918 INT cbCopyCount;
1919 union
1920 {
1921 BITMAP bitmap;
1922 DIBSECTION dibsection;
1923 LOGPEN logpen;
1924 LOGBRUSH logbrush;
1925 LOGFONTW logfontw;
1926 EXTLOGFONTW extlogfontw;
1927 ENUMLOGFONTEXDVW enumlogfontexdvw;
1928 } Object;
1929
1930 // Normalize to the largest supported object size
1931 cbCount = min((UINT)cbCount, sizeof(Object));
1932
1933 // Now do the actual call
1934 iRetCount = IntGdiGetObject(hGdiObj, cbCount, lpBuffer ? &Object : NULL);
1935 cbCopyCount = min((UINT)cbCount, (UINT)iRetCount);
1936
1937 // Make sure we have a buffer and a copy size
1938 if ((cbCopyCount) && (lpBuffer))
1939 {
1940 // Enter SEH for buffer transfer
1941 _SEH2_TRY
1942 {
1943 // Probe the buffer and copy it
1944 ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD));
1945 RtlCopyMemory(lpBuffer, &Object, cbCopyCount);
1946 }
1947 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1948 {
1949 // Clear the return value.
1950 // Do *NOT* set last error here!
1951 iRetCount = 0;
1952 }
1953 _SEH2_END;
1954 }
1955 // Return the count
1956 return iRetCount;
1957 }
1958
1959 /* EOF */