2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998 - 2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * GDIOBJ.C - GDI object manipulation routines
30 /* FIXME include right header for KeRosDumpStackFrames */
31 VOID NTAPI
KeRosDumpStackFrames(PULONG
, ULONG
);
34 BOOLEAN STDCALL
KiRosPrintAddress(PVOID Address
);
35 NTSYSAPI ULONG NTAPI
RtlWalkFrameChain(OUT PVOID
*Callers
, IN ULONG Count
, IN ULONG Flags
);
38 #define GDI_ENTRY_TO_INDEX(ht, e) \
39 (((ULONG_PTR)(e) - (ULONG_PTR)&((ht)->Entries[0])) / sizeof(GDI_TABLE_ENTRY))
40 #define GDI_HANDLE_GET_ENTRY(HandleTable, h) \
41 (&(HandleTable)->Entries[GDI_HANDLE_GET_INDEX((h))])
43 #define GDIBdyToHdr(body) \
44 ((PGDIOBJHDR)(body) - 1)
45 #define GDIHdrToBdy(hdr) \
46 (PGDIOBJ)((PGDIOBJHDR)(hdr) + 1)
48 /* apparently the first 10 entries are never used in windows as they are empty */
49 #define RESERVE_ENTRIES_COUNT 10
52 * Dummy GDI Cleanup Callback
54 static BOOL INTERNAL_CALL
55 GDI_CleanupDummy(PVOID ObjectBody
)
65 GDICLEANUPPROC CleanupProc
;
66 } OBJ_TYPE_INFO
, *POBJ_TYPE_INFO
;
69 OBJ_TYPE_INFO ObjTypeInfo
[] =
71 {0, 0, 0, NULL
}, /* 00 reserved entry */
72 {1, sizeof(DC
), TAG_DC
, DC_Cleanup
}, /* 01 DC */
73 {1, 0, 0, NULL
}, /* 02 UNUSED1 */
74 {1, 0, 0, NULL
}, /* 03 UNUSED2 */
75 {1, sizeof(ROSRGNDATA
), TAG_REGION
, RGNDATA_Cleanup
}, /* 04 RGN */
76 {1, sizeof(BITMAPOBJ
), TAG_SURFACE
, BITMAP_Cleanup
}, /* 05 SURFACE */
77 {0, sizeof(DC
), TAG_CLIENTOBJ
, GDI_CleanupDummy
}, /* 06 CLIENTOBJ: METADC,... FIXME: don't use DC struct */
78 {0, 0, TAG_PATH
, NULL
}, /* 07 PATH, unused */
79 {1, sizeof(PALGDI
), TAG_PALETTE
, PALETTE_Cleanup
}, /* 08 PAL */
80 {0, 0, TAG_ICMLCS
, NULL
}, /* 09 ICMLCS, unused */
81 {1, sizeof(TEXTOBJ
), TAG_LFONT
, GDI_CleanupDummy
}, /* 0a LFONT */
82 {0, 0, TAG_RFONT
, NULL
}, /* 0b RFONT, unused */
83 {0, 0, TAG_PFE
, NULL
}, /* 0c PFE, unused */
84 {0, 0, TAG_PFT
, NULL
}, /* 0d PFT, unused */
85 {0, 0, TAG_ICMCXF
, NULL
}, /* 0e ICMCXF, unused */
86 {0, 0, TAG_SPRITE
, NULL
}, /* 0f SPRITE, unused */
87 {1, sizeof(GDIBRUSHOBJ
), TAG_BRUSH
, BRUSH_Cleanup
}, /* 10 BRUSH, PEN, EXTPEN */
88 {0, 0, TAG_UMPD
, NULL
}, /* 11 UMPD, unused */
89 {0, 0, 0, NULL
}, /* 12 UNUSED4 */
90 {0, 0, TAG_SPACE
, NULL
}, /* 13 SPACE, unused */
91 {0, 0, 0, NULL
}, /* 14 UNUSED5 */
92 {0, 0, TAG_META
, NULL
}, /* 15 META, unused */
93 {0, 0, TAG_EFSTATE
, NULL
}, /* 16 EFSTATE, unused */
94 {0, 0, TAG_BMFD
, NULL
}, /* 17 BMFD, unused */
95 {0, 0, TAG_TTFD
, NULL
}, /* 18 VTFD, unused */
96 {0, 0, TAG_TTFD
, NULL
}, /* 19 TTFD, unused */
97 {0, 0, TAG_RC
, NULL
}, /* 1a RC, unused */
98 {0, 0, TAG_TEMP
, NULL
}, /* 1b TEMP, unused */
99 {0, 0, TAG_DRVOBJ
, NULL
}, /* 1c DRVOBJ, unused */
100 {0, 0, TAG_DCIOBJ
, NULL
}, /* 1d DCIOBJ, unused */
101 {0, 0, TAG_SPOOL
, NULL
}, /* 1e SPOOL, unused */
104 #define BASE_OBJTYPE_COUNT (sizeof(ObjTypeInfo) / sizeof(ObjTypeInfo[0]))
106 static LARGE_INTEGER ShortDelay
;
108 #define DelayExecution() \
109 DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
110 KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
113 * Allocate GDI object table.
114 * \param Size - number of entries in the object table.
116 PGDI_HANDLE_TABLE INTERNAL_CALL
117 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT
*SectionObject
)
119 PGDI_HANDLE_TABLE HandleTable
= NULL
;
120 LARGE_INTEGER htSize
;
125 ASSERT(SectionObject
!= NULL
);
127 htSize
.QuadPart
= sizeof(GDI_HANDLE_TABLE
);
129 Status
= MmCreateSection((PVOID
*)SectionObject
,
137 if (!NT_SUCCESS(Status
))
140 /* FIXME - use MmMapViewInSessionSpace once available! */
141 Status
= MmMapViewInSystemSpace(*SectionObject
,
142 (PVOID
*)&HandleTable
,
144 if (!NT_SUCCESS(Status
))
146 ObDereferenceObject(*SectionObject
);
147 *SectionObject
= NULL
;
151 RtlZeroMemory(HandleTable
, sizeof(GDI_HANDLE_TABLE
));
153 HandleTable
->LookasideLists
= ExAllocatePoolWithTag(NonPagedPool
,
154 BASE_OBJTYPE_COUNT
* sizeof(PAGED_LOOKASIDE_LIST
),
156 if (HandleTable
->LookasideLists
== NULL
)
158 MmUnmapViewInSystemSpace(HandleTable
);
159 ObDereferenceObject(*SectionObject
);
160 *SectionObject
= NULL
;
164 for (ObjType
= 0; ObjType
< BASE_OBJTYPE_COUNT
; ObjType
++)
166 if (ObjTypeInfo
[ObjType
].bUseLookaside
)
168 ExInitializePagedLookasideList(HandleTable
->LookasideLists
+ ObjType
,
172 ObjTypeInfo
[ObjType
].ulBodySize
,
173 ObjTypeInfo
[ObjType
].Tag
,
178 ShortDelay
.QuadPart
= -5000LL; /* FIXME - 0.5 ms? */
180 HandleTable
->FirstFree
= 0;
181 HandleTable
->FirstUnused
= RESERVE_ENTRIES_COUNT
;
186 static __inline PPAGED_LOOKASIDE_LIST
187 FindLookasideList(ULONG TypeIndex
)
189 return GdiHandleTable
->LookasideLists
+ TypeIndex
;
193 RunCleanupCallback(PGDIOBJ pObj
, ULONG TypeIndex
)
195 return ((GDICLEANUPPROC
)ObjTypeInfo
[TypeIndex
].CleanupProc
)(pObj
);
198 static __inline ULONG
199 GetObjectSize(ULONG TypeIndex
)
201 return ObjTypeInfo
[TypeIndex
].ulBodySize
;
206 static int leak_reported
= 0;
207 #define GDI_STACK_LEVELS 12
208 static ULONG GDIHandleAllocator
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
209 static ULONG GDIHandleLocker
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
210 struct DbgOpenGDIHandle
216 static struct DbgOpenGDIHandle h
[H
];
218 void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable
)
220 int i
, n
= 0, j
, k
, J
;
224 DPRINT1("gdi handle abusers already reported!\n");
229 DPRINT1("reporting gdi handle abusers:\n");
231 /* step through GDI handle table and find out who our culprit is... */
232 for (i
= RESERVE_ENTRIES_COUNT
; i
< GDI_HANDLE_COUNT
; i
++)
234 for (j
= 0; j
< n
; j
++)
238 for (k
= 0; k
< GDI_STACK_LEVELS
; k
++)
240 if (GDIHandleAllocator
[i
][k
]
241 != GDIHandleAllocator
[J
][k
])
264 /* bubble sort time! weeeeee!! */
265 for (i
= 0; i
< n
-1; i
++)
267 if (h
[i
].count
< h
[i
+1].count
)
269 struct DbgOpenGDIHandle t
;
273 while (j
> 0 && h
[j
-1].count
< t
.count
)
278 /* print the worst offenders... */
279 DbgPrint("Worst GDI Handle leak offenders (out of %i unique locations):\n", n
);
280 for (i
= 0; i
< n
&& h
[i
].count
> 1; i
++)
283 DbgPrint(" %i allocs: ", h
[i
].count
);
284 for (j
= 0; j
< GDI_STACK_LEVELS
; j
++)
286 ULONG Addr
= GDIHandleAllocator
[h
[i
].idx
][j
];
287 if (!KiRosPrintAddress((PVOID
)Addr
))
288 DbgPrint("<%X>", Addr
);
292 if (i
< n
&& h
[i
].count
== 1)
293 DbgPrint("(list terminated - the remaining entries have 1 allocation only)\n");
297 CaptureStackBackTace(PVOID
* pFrames
, ULONG nFramesToCapture
)
301 memset(pFrames
, 0x00, (nFramesToCapture
+ 1) * sizeof(PVOID
));
303 nFrameCount
= RtlCaptureStackBackTrace(1, nFramesToCapture
, pFrames
, NULL
);
305 if (nFrameCount
< nFramesToCapture
)
307 nFrameCount
+= RtlWalkFrameChain(pFrames
+ nFrameCount
, nFramesToCapture
- nFrameCount
, 1);
313 #define GDIDBG_TRACECALLER() \
314 DPRINT1("-> called from:\n"); \
315 KeRosDumpStackFrames(NULL, 20);
316 #define GDIDBG_TRACEALLOCATOR(index)
317 // DPRINT1("-> allocated from:\n");
318 // KeRosDumpStackFrames(GDIHandleAllocator[index], GDI_STACK_LEVELS);
319 #define GDIDBG_TRACELOCKER(index)
320 // DPRINT1("-> locked from:\n");
321 // KeRosDumpStackFrames(GDIHandleLocker[index], GDI_STACK_LEVELS);
322 #define GDIDBG_CAPTUREALLOCATOR(index) \
323 CaptureStackBackTace((PVOID*)GDIHandleAllocator[index], GDI_STACK_LEVELS);
324 #define GDIDBG_CAPTURELOCKER(index) \
325 CaptureStackBackTace((PVOID*)GDIHandleLocker[index], GDI_STACK_LEVELS);
327 #define GDIDBG_DUMPHANDLETABLE() \
328 IntDumpHandleTable(GdiHandleTable)
332 #define GDIDBG_TRACECALLER()
333 #define GDIDBG_TRACEALLOCATOR(index)
334 #define GDIDBG_TRACELOCKER(index)
335 #define GDIDBG_CAPTUREALLOCATOR(index)
336 #define GDIDBG_CAPTURELOCKER(index)
337 #define GDIDBG_DUMPHANDLETABLE()
339 #endif /* GDI_DEBUG */
343 LockErrorDebugOutput(HGDIOBJ hObj
, PGDI_TABLE_ENTRY Entry
, LPSTR Function
)
345 if ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0)
347 DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function
, hObj
);
349 else if (GDI_HANDLE_GET_REUSECNT(hObj
) != GDI_ENTRY_GET_REUSECNT(Entry
->Type
))
351 DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
352 Function
, hObj
, GDI_HANDLE_GET_REUSECNT(hObj
), GDI_ENTRY_GET_REUSECNT(Entry
->Type
));
354 else if (GDI_HANDLE_GET_TYPE(hObj
) != ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
))
356 DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
357 Function
, hObj
, GDI_HANDLE_GET_TYPE(hObj
), (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) & GDI_HANDLE_TYPE_MASK
);
361 DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
362 Function
, hObj
, Entry
->Type
);
365 DPRINT1("-> called from:\n");
366 KeRosDumpStackFrames(NULL
, 20);
372 InterlockedPopFreeEntry()
374 ULONG idxFirstFree
, idxNextFree
, idxPrev
;
375 PGDI_TABLE_ENTRY pFreeEntry
;
377 DPRINT("Enter InterLockedPopFreeEntry\n");
381 idxFirstFree
= GdiHandleTable
->FirstFree
;
384 pFreeEntry
= GdiHandleTable
->Entries
+ idxFirstFree
;
385 ASSERT(((ULONG
)pFreeEntry
->KernelData
& ~GDI_HANDLE_INDEX_MASK
) == 0);
386 idxNextFree
= (ULONG
)pFreeEntry
->KernelData
;
387 idxPrev
= (ULONG
)_InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
, idxNextFree
, idxFirstFree
);
391 idxFirstFree
= GdiHandleTable
->FirstUnused
;
392 idxNextFree
= idxFirstFree
+ 1;
393 if (idxNextFree
>= GDI_HANDLE_COUNT
)
395 DPRINT1("No more gdi handles left!\n");
398 idxPrev
= (ULONG
)_InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstUnused
, idxNextFree
, idxFirstFree
);
401 while (idxPrev
!= idxFirstFree
);
406 /* Pushes an entry of the handle table to the free list,
407 The entry must be unlocked and the base type field must be 0 */
410 InterlockedPushFreeEntry(ULONG idxToFree
)
412 ULONG idxFirstFree
, idxPrev
;
413 PGDI_TABLE_ENTRY pFreeEntry
;
415 DPRINT("Enter InterlockedPushFreeEntry\n");
417 pFreeEntry
= GdiHandleTable
->Entries
+ idxToFree
;
418 ASSERT((pFreeEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == 0);
419 ASSERT(pFreeEntry
->ProcessId
== 0);
420 pFreeEntry
->UserData
= NULL
;
424 idxFirstFree
= GdiHandleTable
->FirstFree
;
425 pFreeEntry
->KernelData
= (PVOID
)idxFirstFree
;
427 idxPrev
= (ULONG
)_InterlockedCompareExchange((LONG
*)&GdiHandleTable
->FirstFree
, idxToFree
, idxFirstFree
);
429 while (idxPrev
!= idxFirstFree
);
435 GDIOBJ_ValidateHandle(HGDIOBJ hObj
, ULONG ObjectType
)
437 PGDI_TABLE_ENTRY Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
438 if ((((ULONG_PTR
)hObj
& GDI_HANDLE_TYPE_MASK
) == ObjectType
) &&
439 (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == GDI_HANDLE_GET_UPPER(hObj
))
441 HANDLE pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
442 if (pid
== NULL
|| pid
== PsGetCurrentProcessId())
451 * Allocate memory for GDI object and return handle to it.
453 * \param ObjectType - type of object \ref GDI object types
455 * \return Handle of the allocated object.
457 * \note Use GDIOBJ_Lock() to obtain pointer to the new object.
458 * \todo return the object pointer and lock it by default.
460 HGDIOBJ INTERNAL_CALL
461 GDIOBJ_AllocObj(ULONG ObjectType
)
463 PW32PROCESS W32Process
;
464 POBJ newObject
= NULL
;
465 PPAGED_LOOKASIDE_LIST LookasideList
= NULL
;
466 HANDLE CurrentProcessId
, LockedProcessId
;
472 W32Process
= PsGetCurrentProcessWin32Process();
473 /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
474 to take too many GDI objects, itself. */
475 if (W32Process
&& W32Process
->GDIObjects
>= 0x2710)
478 ASSERT(ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
);
480 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(ObjectType
);
481 if (ObjTypeInfo
[TypeIndex
].bUseLookaside
)
483 LookasideList
= FindLookasideList(TypeIndex
);
484 if (LookasideList
!= NULL
)
486 newObject
= ExAllocateFromPagedLookasideList(LookasideList
);
491 newObject
= ExAllocatePoolWithTag(PagedPool
,
492 ObjTypeInfo
[TypeIndex
].ulBodySize
,
493 ObjTypeInfo
[TypeIndex
].Tag
);
495 if (newObject
!= NULL
)
498 PGDI_TABLE_ENTRY Entry
;
501 CurrentProcessId
= PsGetCurrentProcessId();
502 LockedProcessId
= (HANDLE
)((ULONG_PTR
)CurrentProcessId
| 0x1);
504 RtlZeroMemory(newObject
, GetObjectSize(TypeIndex
));
506 /* On Windows the higher 16 bit of the type field don't contain the
507 full type from the handle, but the base type.
508 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
509 TypeInfo
= (ObjectType
& GDI_HANDLE_BASETYPE_MASK
) | (ObjectType
>> GDI_ENTRY_UPPER_SHIFT
);
511 Index
= InterlockedPopFreeEntry();
516 Entry
= &GdiHandleTable
->Entries
[Index
];
519 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, 0);
520 if (PrevProcId
== NULL
)
524 Entry
->KernelData
= newObject
;
526 /* copy the reuse-counter */
527 TypeInfo
|= Entry
->Type
& GDI_ENTRY_REUSE_MASK
;
529 /* we found a free entry, no need to exchange this field atomically
530 since we're holding the lock */
531 Entry
->Type
= TypeInfo
;
533 /* unlock the entry */
534 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, CurrentProcessId
);
536 GDIDBG_CAPTUREALLOCATOR(Index
);
538 if (W32Process
!= NULL
)
540 _InterlockedIncrement(&W32Process
->GDIObjects
);
542 Handle
= (HGDIOBJ
)((Index
& 0xFFFF) | (TypeInfo
<< GDI_ENTRY_UPPER_SHIFT
));
544 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle
, newObject
);
552 DPRINT1("[%d]Waiting on handle in index 0x%x\n", Attempts
, Index
);
555 /* damn, someone is trying to lock the object even though it doesn't
556 eve nexist anymore, wait a little and try again!
557 FIXME - we shouldn't loop forever! Give up after some time! */
564 if (ObjTypeInfo
[TypeIndex
].bUseLookaside
)
566 ExFreeToPagedLookasideList(LookasideList
, newObject
);
570 ExFreePool(newObject
);
572 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
573 GDIDBG_DUMPHANDLETABLE();
577 DPRINT1("Not enough memory to allocate gdi object!\n");
583 * Free memory allocated for the GDI object. For each object type this function calls the
584 * appropriate cleanup routine.
586 * \param hObj - handle of the object to be deleted.
588 * \return Returns TRUE if succesful.
589 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
590 * to the calling process.
593 GDIOBJ_FreeObj(HGDIOBJ hObj
, DWORD ExpectedType
)
595 PGDI_TABLE_ENTRY Entry
;
596 PPAGED_LOOKASIDE_LIST LookasideList
;
597 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
598 ULONG HandleType
, HandleUpper
, TypeIndex
;
604 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj
);
606 if (GDI_HANDLE_IS_STOCKOBJ(hObj
))
608 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj
);
609 GDIDBG_TRACECALLER();
613 ProcessId
= PsGetCurrentProcessId();
614 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
616 Silent
= (ExpectedType
& GDI_OBJECT_TYPE_SILENT
);
617 ExpectedType
&= ~GDI_OBJECT_TYPE_SILENT
;
619 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
620 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
622 /* Check if we have the requested type */
623 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
624 HandleType
!= ExpectedType
) ||
627 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
628 hObj
, HandleType
, ExpectedType
);
629 GDIDBG_TRACECALLER();
633 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
636 /* lock the object, we must not delete global objects, so don't exchange the locking
637 process ID to zero when attempting to lock a global object... */
638 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
639 if (PrevProcId
== ProcessId
)
641 if ( (Entry
->KernelData
!= NULL
) &&
642 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) &&
643 ((Entry
->Type
& GDI_ENTRY_BASETYPE_MASK
) == (HandleUpper
& GDI_ENTRY_BASETYPE_MASK
)) )
647 Object
= Entry
->KernelData
;
649 if (Object
->cExclusiveLock
== 0)
652 PW32PROCESS W32Process
= PsGetCurrentProcessWin32Process();
654 /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
655 Entry
->Type
= (Entry
->Type
+ GDI_ENTRY_REUSE_INC
) & ~GDI_ENTRY_BASETYPE_MASK
;
657 /* unlock the handle slot */
658 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, NULL
);
660 /* push this entry to the free list */
661 InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable
, Entry
));
663 if (W32Process
!= NULL
)
665 _InterlockedDecrement(&W32Process
->GDIObjects
);
668 /* call the cleanup routine. */
669 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(HandleType
);
670 Ret
= RunCleanupCallback(Object
, TypeIndex
);
672 /* Now it's time to free the memory */
673 if (ObjTypeInfo
[TypeIndex
].bUseLookaside
)
675 LookasideList
= FindLookasideList(TypeIndex
);
676 if (LookasideList
!= NULL
)
678 ExFreeToPagedLookasideList(LookasideList
, Object
);
691 * The object is currently locked, so freeing is forbidden!
693 DPRINT1("Object->cExclusiveLock = %d\n", Object
->cExclusiveLock
);
694 GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj
));
700 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
701 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
704 else if (PrevProcId
== LockedProcessId
)
709 DPRINT1("[%d]Waiting on 0x%x\n", Attempts
, hObj
);
712 /* the object is currently locked, wait some time and try again.
713 FIXME - we shouldn't loop forever! Give up after some time! */
722 if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
724 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
725 DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry
->Type
, Entry
->KernelData
, Entry
->ProcessId
);
729 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);
731 GDIDBG_TRACECALLER();
732 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
741 IsObjectDead(HGDIOBJ hObject
)
743 INT Index
= GDI_HANDLE_GET_INDEX(hObject
);
744 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
745 // We check to see if the objects are knocking on deaths door.
746 if ((Entry
->Type
& ~GDI_ENTRY_REUSE_MASK
) != 0 && Entry
->KernelData
!= NULL
)
750 DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject
);
751 return TRUE
; // return true and move on.
758 * \param hObject object handle
759 * \return if the function fails the returned value is FALSE.
763 NtGdiDeleteObject(HGDIOBJ hObject
)
765 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
766 if (!IsObjectDead(hObject
))
768 return NULL
!= hObject
769 ? GDIOBJ_FreeObj(hObject
, GDI_OBJECT_TYPE_DONTCARE
) : FALSE
;
773 DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject
);
774 return TRUE
; // return true and move on.
779 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
780 * \param Process - PID of the process that will be destroyed.
783 GDI_CleanupForProcess(struct _EPROCESS
*Process
)
785 PGDI_TABLE_ENTRY Entry
, End
;
786 PEPROCESS CurrentProcess
;
787 PW32PROCESS W32Process
;
789 ULONG Index
= RESERVE_ENTRIES_COUNT
;
791 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
792 CurrentProcess
= PsGetCurrentProcess();
793 if (CurrentProcess
!= Process
)
795 KeAttachProcess(&Process
->Pcb
);
797 W32Process
= (PW32PROCESS
)Process
->Win32Process
;
800 if (W32Process
->GDIObjects
> 0)
802 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
803 we should delete it directly here! */
804 ProcId
= Process
->UniqueProcessId
;
806 End
= &GdiHandleTable
->Entries
[GDI_HANDLE_COUNT
];
807 for (Entry
= &GdiHandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
811 /* ignore the lock bit */
812 if ( (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
&&
813 (Entry
->Type
& ~GDI_ENTRY_REUSE_MASK
) != 0 )
815 HGDIOBJ ObjectHandle
;
817 /* Create the object handle for the entry, the lower(!) 16 bit of the
818 Type field includes the type of the object including the stock
819 object flag - but since stock objects don't have a process id we can
820 simply ignore this fact here. */
821 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
823 if (GDIOBJ_FreeObj(ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
) &&
824 W32Process
->GDIObjects
== 0)
826 /* there are no more gdi handles for this process, bail */
833 if (CurrentProcess
!= Process
)
838 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
844 * Return pointer to the object by handle.
846 * \param hObj Object handle
847 * \return Pointer to the object.
849 * \note Process can only get pointer to the objects it created or global objects.
851 * \todo Get rid of the ExpectedType parameter!
853 PGDIOBJ INTERNAL_CALL
854 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
857 PGDI_TABLE_ENTRY Entry
;
858 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
860 ULONG HandleType
, HandleUpper
;
862 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
863 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
864 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
866 /* Check that the handle index is valid. */
867 if (HandleIndex
>= GDI_HANDLE_COUNT
)
870 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
872 /* Check if we have the requested type */
873 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
874 HandleType
!= ExpectedType
) ||
877 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
878 hObj
, HandleType
, ExpectedType
);
879 GDIDBG_TRACECALLER();
880 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
884 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
885 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
887 /* Check for invalid owner. */
888 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
890 DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj
, ProcessId
, HandleProcessId
);
891 GDIDBG_TRACECALLER();
892 GDIDBG_TRACEALLOCATOR(GDI_HANDLE_GET_INDEX(hObj
));
897 * Prevent the thread from being terminated during the locking process.
898 * It would result in undesired effects and inconsistency of the global
902 KeEnterCriticalRegion();
905 * Loop until we either successfully lock the handle entry & object or
906 * fail some of the check.
911 /* Lock the handle table entry. */
912 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
913 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
917 if (PrevProcId
== HandleProcessId
)
920 * We're locking an object that belongs to our process or it's a
921 * global object if HandleProcessId is 0 here.
924 if ( (Entry
->KernelData
!= NULL
) &&
925 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
927 PW32THREAD Thread
= PsGetCurrentThreadWin32Thread();
928 Object
= Entry
->KernelData
;
930 if (Object
->cExclusiveLock
== 0)
932 Object
->Tid
= Thread
;
933 Object
->cExclusiveLock
= 1;
934 GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj
))
938 if (Object
->Tid
!= Thread
)
940 /* Unlock the handle table entry. */
941 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
946 _InterlockedIncrement((PLONG
)&Object
->cExclusiveLock
);
952 * Debugging code. Report attempts to lock deleted handles and
953 * locking type mismatches.
955 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
958 /* Unlock the handle table entry. */
959 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
966 * The handle is currently locked, wait some time and try again.
974 KeLeaveCriticalRegion();
981 * Return pointer to the object by handle (and allow sharing of the handle
984 * \param hObj Object handle
985 * \return Pointer to the object.
987 * \note Process can only get pointer to the objects it created or global objects.
989 * \todo Get rid of the ExpectedType parameter!
991 PGDIOBJ INTERNAL_CALL
992 GDIOBJ_ShareLockObj(HGDIOBJ hObj
, DWORD ExpectedType
)
995 PGDI_TABLE_ENTRY Entry
;
996 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
998 ULONG_PTR HandleType
, HandleUpper
;
1000 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
1001 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
1002 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
1004 /* Check that the handle index is valid. */
1005 if (HandleIndex
>= GDI_HANDLE_COUNT
)
1008 /* Check if we have the requested type */
1009 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
1010 HandleType
!= ExpectedType
) ||
1013 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
1014 hObj
, HandleType
, ExpectedType
);
1018 Entry
= &GdiHandleTable
->Entries
[HandleIndex
];
1020 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
1021 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
1023 /* Check for invalid owner. */
1024 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
1030 * Prevent the thread from being terminated during the locking process.
1031 * It would result in undesired effects and inconsistency of the global
1035 KeEnterCriticalRegion();
1038 * Loop until we either successfully lock the handle entry & object or
1039 * fail some of the check.
1044 /* Lock the handle table entry. */
1045 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
1046 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
,
1050 if (PrevProcId
== HandleProcessId
)
1053 * We're locking an object that belongs to our process or it's a
1054 * global object if HandleProcessId is 0 here.
1057 if ( (Entry
->KernelData
!= NULL
) &&
1058 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
1060 Object
= (POBJ
)Entry
->KernelData
;
1063 if (_InterlockedIncrement((PLONG
)&Object
->ulShareCount
) == 1)
1065 memset(GDIHandleLocker
[HandleIndex
], 0x00, GDI_STACK_LEVELS
* sizeof(ULONG
));
1066 RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS
, (PVOID
*)GDIHandleLocker
[HandleIndex
], NULL
);
1069 _InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
1075 * Debugging code. Report attempts to lock deleted handles and
1076 * locking type mismatches.
1078 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
1081 /* Unlock the handle table entry. */
1082 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1089 * The handle is currently locked, wait some time and try again.
1097 KeLeaveCriticalRegion();
1104 * Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
1105 * as soon as you don't need to have access to it's data.
1107 * \param Object Object pointer (as returned by GDIOBJ_LockObj).
1110 GDIOBJ_UnlockObjByPtr(POBJ Object
)
1112 if (_InterlockedDecrement((PLONG
)&Object
->cExclusiveLock
) < 0)
1114 DPRINT1("Trying to unlock non-existant object\n");
1119 GDIOBJ_ShareUnlockObjByPtr(POBJ Object
)
1121 if (_InterlockedDecrement((PLONG
)&Object
->ulShareCount
) < 0)
1123 DPRINT1("Trying to unlock non-existant object\n");
1128 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
1130 PGDI_TABLE_ENTRY Entry
;
1134 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1136 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1138 ProcessId
= PsGetCurrentProcessId();
1140 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1141 Ret
= Entry
->KernelData
!= NULL
&&
1142 (Entry
->Type
& ~GDI_ENTRY_REUSE_MASK
) != 0 &&
1143 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1152 GDIOBJ_ConvertToStockObj(HGDIOBJ
*phObj
)
1155 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1156 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1158 PGDI_TABLE_ENTRY Entry
;
1159 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1169 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj
);
1171 Thread
= PsGetCurrentThreadWin32Thread();
1173 if (!GDI_HANDLE_IS_STOCKOBJ(hObj
))
1175 ProcessId
= PsGetCurrentProcessId();
1176 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1178 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, hObj
);
1181 /* lock the object, we must not convert stock objects, so don't check!!! */
1182 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1183 if (PrevProcId
== ProcessId
)
1185 LONG NewType
, PrevType
, OldType
;
1187 /* we're locking an object that belongs to our process. First calculate
1188 the new object type including the stock object flag and then try to
1190 /* On Windows the higher 16 bit of the type field don't contain the
1191 full type from the handle, but the base type.
1192 (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
1193 OldType
= ((ULONG
)hObj
& GDI_HANDLE_BASETYPE_MASK
) | ((ULONG
)hObj
>> GDI_ENTRY_UPPER_SHIFT
);
1194 /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
1195 we copy them as we can't get them from the handle */
1196 OldType
|= Entry
->Type
& GDI_ENTRY_FLAGS_MASK
;
1198 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1199 NewType
= OldType
| GDI_ENTRY_STOCK_MASK
;
1201 /* Try to exchange the type field - but only if the old (previous type) matches! */
1202 PrevType
= _InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1203 if (PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1205 PW32THREAD PrevThread
;
1208 /* We successfully set the stock object flag.
1209 KernelData should never be NULL here!!! */
1210 ASSERT(Entry
->KernelData
);
1212 Object
= Entry
->KernelData
;
1214 PrevThread
= Object
->Tid
;
1215 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1217 /* dereference the process' object counter */
1218 if (PrevProcId
!= GDI_GLOBAL_PROCESS
)
1220 PEPROCESS OldProcess
;
1221 PW32PROCESS W32Process
;
1225 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1226 if (NT_SUCCESS(Status
))
1228 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1229 if (W32Process
!= NULL
)
1231 _InterlockedDecrement(&W32Process
->GDIObjects
);
1233 ObDereferenceObject(OldProcess
);
1237 /* remove the process id lock and make it global */
1238 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1240 hObj
= (HGDIOBJ
)((ULONG
)(hObj
) | GDI_HANDLE_STOCK_MASK
);
1243 /* we're done, successfully converted the object */
1249 if (++Attempts
> 20)
1251 DPRINT1("[%d]Locked by 0x%x (we're 0x%x)\n", Attempts
, PrevThread
, Thread
);
1254 /* WTF?! The object is already locked by a different thread!
1255 Release the lock, wait a bit and try again!
1256 FIXME - we should give up after some time unless we want to wait forever! */
1257 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1265 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1266 DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType
, Entry
->Type
, NewType
, Entry
->KernelData
);
1269 else if (PrevProcId
== LockedProcessId
)
1272 if (++Attempts
> 20)
1274 DPRINT1("[%d]Waiting on 0x%x\n", Attempts
, hObj
);
1277 /* the object is currently locked, wait some time and try again.
1278 FIXME - we shouldn't loop forever! Give up after some time! */
1285 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1293 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1295 PGDI_TABLE_ENTRY Entry
;
1296 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1302 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1304 Thread
= PsGetCurrentThreadWin32Thread();
1306 if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1308 ProcessId
= PsGetCurrentProcessId();
1309 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1311 Entry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, ObjectHandle
);
1314 /* lock the object, we must not convert stock objects, so don't check!!! */
1315 PrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1316 if (PrevProcId
== ProcessId
)
1318 PW32THREAD PrevThread
;
1320 if ((Entry
->Type
& ~GDI_ENTRY_REUSE_MASK
) != 0 && Entry
->KernelData
!= NULL
)
1322 POBJ Object
= Entry
->KernelData
;
1324 PrevThread
= Object
->Tid
;
1325 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1327 PEPROCESS OldProcess
;
1328 PW32PROCESS W32Process
;
1331 /* dereference the process' object counter */
1333 if ((ULONG_PTR
)PrevProcId
& ~0x1)
1335 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1336 if (NT_SUCCESS(Status
))
1338 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1339 if (W32Process
!= NULL
)
1341 _InterlockedDecrement(&W32Process
->GDIObjects
);
1343 ObDereferenceObject(OldProcess
);
1347 if (NewOwner
!= NULL
)
1349 ProcessId
= PsGetProcessId(NewOwner
);
1351 /* Increase the new process' object counter */
1352 W32Process
= (PW32PROCESS
)NewOwner
->Win32Process
;
1353 if (W32Process
!= NULL
)
1355 _InterlockedIncrement(&W32Process
->GDIObjects
);
1361 /* remove the process id lock and change it to the new process id */
1362 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, ProcessId
);
1370 if (++Attempts
> 20)
1372 DPRINT1("[%d]Locked by 0x%x (we're 0x%x)\n", Attempts
, PrevThread
, Thread
);
1375 /* WTF?! The object is already locked by a different thread!
1376 Release the lock, wait a bit and try again! DO reset the pid lock
1377 so we make sure we don't access invalid memory in case the object is
1378 being deleted in the meantime (because we don't have aquired a reference
1380 FIXME - we should give up after some time unless we want to wait forever! */
1381 (void)_InterlockedExchangePointer((PVOID
*)&Entry
->ProcessId
, PrevProcId
);
1389 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1390 DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry
->Type
, Entry
->KernelData
);
1393 else if (PrevProcId
== LockedProcessId
)
1396 if (++Attempts
> 20)
1398 DPRINT1("[%d]Waiting on 0x%x\n", Attempts
, ObjectHandle
);
1401 /* the object is currently locked, wait some time and try again.
1402 FIXME - we shouldn't loop forever! Give up after some time! */
1407 else if (((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1409 /* allow changing ownership of global objects */
1411 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1414 else if ((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1416 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1420 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1426 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1428 PGDI_TABLE_ENTRY FromEntry
;
1430 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1435 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1437 Thread
= PsGetCurrentThreadWin32Thread();
1439 if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1441 FromEntry
= GDI_HANDLE_GET_ENTRY(GdiHandleTable
, CopyFrom
);
1443 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1444 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1447 /* lock the object, we must not convert stock objects, so don't check!!! */
1448 FromPrevProcId
= _InterlockedCompareExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1449 if (FromPrevProcId
== FromProcessId
)
1451 PW32THREAD PrevThread
;
1454 if ((FromEntry
->Type
& ~GDI_ENTRY_REUSE_MASK
) != 0 && FromEntry
->KernelData
!= NULL
)
1456 Object
= FromEntry
->KernelData
;
1458 /* save the pointer to the calling thread so we know it was this thread
1459 that locked the object */
1460 PrevThread
= Object
->Tid
;
1461 if (Object
->cExclusiveLock
== 0 || PrevThread
== Thread
)
1463 /* now let's change the ownership of the target object */
1465 if (((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1467 PEPROCESS ProcessTo
;
1469 if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1471 GDIOBJ_SetOwnership(CopyTo
, ProcessTo
);
1472 ObDereferenceObject(ProcessTo
);
1477 /* mark the object as global */
1478 GDIOBJ_SetOwnership(CopyTo
, NULL
);
1481 (void)_InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1486 if (++Attempts
> 20)
1488 DPRINT1("[%d]Locked by 0x%x (we're 0x%x)\n", Attempts
, PrevThread
, Thread
);
1491 /* WTF?! The object is already locked by a different thread!
1492 Release the lock, wait a bit and try again! DO reset the pid lock
1493 so we make sure we don't access invalid memory in case the object is
1494 being deleted in the meantime (because we don't have aquired a reference
1496 FIXME - we should give up after some time unless we want to wait forever! */
1497 (void)_InterlockedExchangePointer((PVOID
*)&FromEntry
->ProcessId
, FromPrevProcId
);
1500 goto LockHandleFrom
;
1505 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1508 else if (FromPrevProcId
== FromLockedProcessId
)
1511 if (++Attempts
> 20)
1513 DPRINT1("[%d]Waiting on 0x%x\n", Attempts
, CopyFrom
);
1516 /* the object is currently locked, wait some time and try again.
1517 FIXME - we shouldn't loop forever! Give up after some time! */
1520 goto LockHandleFrom
;
1522 else if ((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1524 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1525 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1526 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1527 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1528 goto LockHandleFrom
;
1532 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1538 GDI_MapHandleTable(PSECTION_OBJECT SectionObject
, PEPROCESS Process
)
1540 PVOID MappedView
= NULL
;
1542 LARGE_INTEGER Offset
;
1543 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1545 Offset
.QuadPart
= 0;
1547 ASSERT(SectionObject
!= NULL
);
1548 ASSERT(Process
!= NULL
);
1550 Status
= MmMapViewOfSection(SectionObject
,
1561 if (!NT_SUCCESS(Status
))
1570 NtGdiCreateClientObj(
1574 // ATM we use DC object for KernelData. I think it should be at a minimum GDIOBJEMPTYHDR.
1575 // The UserData is set in user mode, so it is always NULL.
1578 PGDI_TABLE_ENTRY Entry
;
1579 HANDLE handle
= GDIOBJ_AllocObj(GDI_OBJECT_TYPE_CLIOBJ
);
1580 // Need to change handle type based on ulType.
1581 Index
= GDI_HANDLE_GET_INDEX((HGDIOBJ
)handle
);
1582 Entry
= &GdiHandleTable
->Entries
[Index
];
1583 // mask out lower half and set the type by ulType.
1584 Entry
->Type
&= GDI_HANDLE_UPPER_MASK
;
1585 Entry
->Type
|= ulType
>> GDI_ENTRY_UPPER_SHIFT
;
1586 // mask out handle type than set it by ulType.
1587 handle
= (HANDLE
)(((ULONG_PTR
)(handle
)) & (GDI_HANDLE_REUSE_MASK
|GDI_HANDLE_STOCK_MASK
|0x0ffff));
1588 handle
= (HANDLE
)(((ULONG_PTR
)(handle
)) | ulType
);
1595 NtGdiDeleteClientObj(
1599 return GDIOBJ_FreeObj(h
, GDI_OBJECT_TYPE_CLIOBJ
);