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