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