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 */
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
), GDI_OBJECT_TAG_DC
, DC_Cleanup
}, /* 01 DC */
73 {1, sizeof(DD_DIRECTDRAW
), GDI_OBJECT_TAG_DDRAW
, DD_Cleanup
}, /* 02 DD_DDRAW, should be moved away from gdi objects */
74 {1, sizeof(DD_SURFACE
), GDI_OBJECT_TAG_DDSURF
, DDSURF_Cleanup
}, /* 03 DD_SURFACE, should be moved away from gdi objects */
75 {1, sizeof(ROSRGNDATA
), GDI_OBJECT_TAG_REGION
, RGNDATA_Cleanup
}, /* 04 REGION */
76 {1, sizeof(BITMAPOBJ
), GDI_OBJECT_TAG_BITMAP
, BITMAP_Cleanup
}, /* 05 BITMAP */
77 {0, sizeof(DC
), GDI_OBJECT_TAG_CLIOBJ
, GDI_CleanupDummy
}, /* 06 CLIOBJ: METADC,... FIXME: don't use DC struct */
78 {0, 0, GDI_OBJECT_TAG_PATH
, NULL
}, /* 07 PATH, unused */
79 {1, sizeof(PALGDI
), GDI_OBJECT_TAG_PALETTE
, PALETTE_Cleanup
}, /* 08 PALETTE */
80 {0, 0, GDI_OBJECT_TAG_COLSPC
, NULL
}, /* 09 COLORSPACE, unused */
81 {1, sizeof(TEXTOBJ
), GDI_OBJECT_TAG_FONT
, GDI_CleanupDummy
}, /* 0a FONT */
82 {0, 0, 0, NULL
}, /* 0b RFONT, unused */
83 {0, 0, 0, NULL
}, /* 0c PFE, unused */
84 {0, 0, 0, NULL
}, /* 0d PFT, unused */
85 {0, 0, 0, NULL
}, /* 0e ICMCXF, unused */
86 {0, 0, 0, NULL
}, /* 0f ICMDLL, unused */
87 {1, sizeof(GDIBRUSHOBJ
), GDI_OBJECT_TAG_BRUSH
, BRUSH_Cleanup
}, /* 10 BRUSH, PEN, EXTPEN */
88 {0, 0, 0, NULL
}, /* 11 D3D_HANDLE, unused */
89 {0, 0, 0, NULL
}, /* 12 DD_VPORT, unused */
90 {0, 0, 0, NULL
}, /* 13 SPACE, unused */
91 {0, 0, 0, NULL
}, /* 14 DD_MOTION, unused */
92 {0, 0, 0, NULL
}, /* 15 META, unused */
93 {0, 0, 0, NULL
}, /* 16 ENUMFONT, unused */
94 {0, 0, 0, NULL
}, /* 18 VTFD, unused */
95 {0, 0, 0, NULL
}, /* 19 TTFD, unused */
96 {0, 0, 0, NULL
}, /* 1a RC, unused */
97 {0, 0, 0, NULL
}, /* 1b TEMP, unused */
98 {0, 0, 0, NULL
}, /* 1c DRVOBJ, unused */
99 {0, 0, 0, NULL
}, /* 1d DCIOBJ, unused */
100 {0, 0, 0, NULL
}, /* 1e SPOOL, unused */
103 #define BASE_OBJTYPE_COUNT (sizeof(ObjTypeInfo) / sizeof(ObjTypeInfo[0]))
105 static LARGE_INTEGER ShortDelay
;
107 #define DelayExecution() \
108 DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
109 KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
112 BOOLEAN STDCALL
KiRosPrintAddress(PVOID Address
);
113 VOID STDCALL
KeRosDumpStackFrames(PULONG Frame
, ULONG FrameCount
);
114 ULONG STDCALL
KeRosGetStackFrames(PULONG Frames
, ULONG FrameCount
);
118 * Allocate GDI object table.
119 * \param Size - number of entries in the object table.
121 PGDI_HANDLE_TABLE INTERNAL_CALL
122 GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT
*SectionObject
)
124 PGDI_HANDLE_TABLE HandleTable
= NULL
;
125 LARGE_INTEGER htSize
;
129 PGDI_TABLE_ENTRY Entry
;
132 ASSERT(SectionObject
!= NULL
);
134 htSize
.QuadPart
= sizeof(GDI_HANDLE_TABLE
);
136 Status
= MmCreateSection((PVOID
*)SectionObject
,
144 if (!NT_SUCCESS(Status
))
147 /* FIXME - use MmMapViewInSessionSpace once available! */
148 Status
= MmMapViewInSystemSpace(*SectionObject
,
149 (PVOID
*)&HandleTable
,
151 if (!NT_SUCCESS(Status
))
153 ObDereferenceObject(*SectionObject
);
154 *SectionObject
= NULL
;
158 RtlZeroMemory(HandleTable
, sizeof(GDI_HANDLE_TABLE
));
161 * initialize the free entry cache
163 InitializeSListHead(&HandleTable
->FreeEntriesHead
);
164 Entry
= &HandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
165 for(i
= GDI_HANDLE_COUNT
- 1; i
>= RESERVE_ENTRIES_COUNT
; i
--)
167 InterlockedPushEntrySList(&HandleTable
->FreeEntriesHead
, &HandleTable
->FreeEntries
[i
]);
170 HandleTable
->LookasideLists
= ExAllocatePoolWithTag(NonPagedPool
,
171 BASE_OBJTYPE_COUNT
* sizeof(PAGED_LOOKASIDE_LIST
),
173 if(HandleTable
->LookasideLists
== NULL
)
175 MmUnmapViewInSystemSpace(HandleTable
);
176 ObDereferenceObject(*SectionObject
);
177 *SectionObject
= NULL
;
181 for(ObjType
= 0; ObjType
< BASE_OBJTYPE_COUNT
; ObjType
++)
183 if (ObjTypeInfo
[ObjType
].bUseLookaside
)
185 ExInitializePagedLookasideList(HandleTable
->LookasideLists
+ ObjType
, NULL
, NULL
, 0,
186 ObjTypeInfo
[ObjType
].ulBodySize
+ sizeof(GDIOBJHDR
), ObjTypeInfo
[ObjType
].Tag
, 0);
190 ShortDelay
.QuadPart
= -5000LL; /* FIXME - 0.5 ms? */
195 static __inline PPAGED_LOOKASIDE_LIST
196 FindLookasideList(PGDI_HANDLE_TABLE HandleTable
,
199 return HandleTable
->LookasideLists
+ TypeIndex
;
203 RunCleanupCallback(PGDIOBJ pObj
, ULONG TypeIndex
)
205 return ((GDICLEANUPPROC
)ObjTypeInfo
[TypeIndex
].CleanupProc
)(pObj
);
208 static __inline ULONG
209 GetObjectSize(ULONG TypeIndex
)
211 return ObjTypeInfo
[TypeIndex
].ulBodySize
;
216 static int leak_reported
= 0;
217 #define GDI_STACK_LEVELS 12
218 static ULONG GDIHandleAllocator
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
];
219 struct DbgOpenGDIHandle
225 static struct DbgOpenGDIHandle h
[H
];
227 void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable
)
229 int i
, n
= 0, j
, k
, J
;
233 DPRINT1("gdi handle abusers already reported!\n");
238 DPRINT1("reporting gdi handle abusers:\n");
240 /* step through GDI handle table and find out who our culprit is... */
241 for ( i
= RESERVE_ENTRIES_COUNT
; i
< GDI_HANDLE_COUNT
; i
++ )
243 for ( j
= 0; j
< n
; j
++ )
247 for ( k
= 0; k
< GDI_STACK_LEVELS
; k
++ )
249 if ( GDIHandleAllocator
[i
][k
]
250 != GDIHandleAllocator
[J
][k
] )
273 /* bubble sort time! weeeeee!! */
274 for ( i
= 0; i
< n
-1; i
++ )
276 if ( h
[i
].count
< h
[i
+1].count
)
278 struct DbgOpenGDIHandle t
;
282 while ( j
> 0 && h
[j
-1].count
< t
.count
)
287 /* print the worst offenders... */
288 DbgPrint ( "Worst GDI Handle leak offenders (out of %i unique locations):\n", n
);
289 for ( i
= 0; i
< n
&& h
[i
].count
> 1; i
++ )
292 DbgPrint ( " %i allocs: ", h
[i
].count
);
293 for ( j
= 0; j
< GDI_STACK_LEVELS
; j
++ )
295 ULONG Addr
= GDIHandleAllocator
[h
[i
].idx
][j
];
296 if ( !KiRosPrintAddress ( (PVOID
)Addr
) )
297 DbgPrint ( "<%X>", Addr
);
301 if ( i
< n
&& h
[i
].count
== 1 )
302 DbgPrint ( "(list terminated - the remaining entries have 1 allocation only)\n" );
304 #endif /* GDI_DEBUG */
308 LockErrorDebugOutput(HGDIOBJ hObj
, PGDI_TABLE_ENTRY Entry
, LPSTR Function
)
310 if (Entry
->KernelData
== NULL
)
312 DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function
, hObj
);
314 else if (GDI_HANDLE_GET_REUSECNT(hObj
) != GDI_ENTRY_GET_REUSECNT(Entry
->Type
))
316 DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
317 Function
, hObj
, GDI_HANDLE_GET_REUSECNT(hObj
), GDI_ENTRY_GET_REUSECNT(Entry
->Type
));
319 else if (GDI_HANDLE_GET_TYPE(hObj
) != GDI_HANDLE_GET_TYPE(Entry
->Type
))
321 DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
322 Function
, hObj
, GDI_HANDLE_GET_TYPE(hObj
), GDI_HANDLE_GET_TYPE(Entry
->Type
));
326 DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
327 Function
, hObj
, Entry
->Type
);
329 KeRosDumpStackFrames(NULL
, 20);
334 * Allocate memory for GDI object and return handle to it.
336 * \param ObjectType - type of object \ref GDI object types
338 * \return Handle of the allocated object.
340 * \note Use GDIOBJ_Lock() to obtain pointer to the new object.
341 * \todo return the object pointer and lock it by default.
343 HGDIOBJ INTERNAL_CALL
345 GDIOBJ_AllocObjDbg(PGDI_HANDLE_TABLE HandleTable
, const char* file
, int line
, ULONG ObjectType
)
346 #else /* !GDI_DEBUG */
347 GDIOBJ_AllocObj(PGDI_HANDLE_TABLE HandleTable
, ULONG ObjectType
)
348 #endif /* GDI_DEBUG */
350 PW32PROCESS W32Process
;
351 PGDIOBJHDR newObject
= NULL
;
352 PPAGED_LOOKASIDE_LIST LookasideList
= NULL
;
353 HANDLE CurrentProcessId
, LockedProcessId
;
359 W32Process
= PsGetCurrentProcessWin32Process();
360 /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
361 to take too many GDI objects, itself. */
362 if ( W32Process
&& W32Process
->GDIObjects
>= 0x2710 )
365 ASSERT(ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
);
367 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(ObjectType
);
368 if (ObjTypeInfo
[TypeIndex
].bUseLookaside
)
370 LookasideList
= FindLookasideList(HandleTable
, TypeIndex
);
371 if(LookasideList
!= NULL
)
373 newObject
= ExAllocateFromPagedLookasideList(LookasideList
);
378 newObject
= ExAllocatePoolWithTag(PagedPool
,
379 ObjTypeInfo
[TypeIndex
].ulBodySize
+ sizeof(GDIOBJHDR
),
380 ObjTypeInfo
[TypeIndex
].Tag
);
382 if(newObject
!= NULL
)
384 PSLIST_ENTRY FreeEntry
;
385 PGDI_TABLE_ENTRY Entry
;
389 CurrentProcessId
= PsGetCurrentProcessId();
390 LockedProcessId
= (HANDLE
)((ULONG_PTR
)CurrentProcessId
| 0x1);
392 newObject
->LockingThread
= NULL
;
393 newObject
->Locks
= 0;
396 newObject
->createdfile
= file
;
397 newObject
->createdline
= line
;
398 newObject
->lockfile
= NULL
;
399 newObject
->lockline
= 0;
402 ObjectBody
= GDIHdrToBdy(newObject
);
404 RtlZeroMemory(ObjectBody
, GetObjectSize(TypeIndex
));
406 /* FIXME: On Windows the higher 16 bit of the type field don't always match
407 the type from the handle, it is probably a storage type
408 (type = pen, storage = brush) */
409 TypeInfo
= (ObjectType
& GDI_HANDLE_TYPE_MASK
) | (ObjectType
>> GDI_ENTRY_UPPER_SHIFT
);
411 FreeEntry
= InterlockedPopEntrySList(&HandleTable
->FreeEntriesHead
);
412 if(FreeEntry
!= NULL
)
417 /* calculate the entry from the address of the entry in the free slot array */
418 Index
= ((ULONG_PTR
)FreeEntry
- (ULONG_PTR
)&HandleTable
->FreeEntries
[0]) /
419 sizeof(HandleTable
->FreeEntries
[0]);
420 Entry
= &HandleTable
->Entries
[Index
];
423 PrevProcId
= InterlockedCompareExchangePointer(&Entry
->ProcessId
, LockedProcessId
, 0);
424 if(PrevProcId
== NULL
)
428 ASSERT(Entry
->KernelData
== NULL
);
430 Entry
->KernelData
= ObjectBody
;
432 /* copy the reuse-counter */
433 TypeInfo
|= Entry
->Type
& GDI_ENTRY_REUSE_MASK
;
435 /* we found a free entry, no need to exchange this field atomically
436 since we're holding the lock */
437 Entry
->Type
= TypeInfo
;
439 /* unlock the entry */
440 (void)InterlockedExchangePointer(&Entry
->ProcessId
, CurrentProcessId
);
443 memset ( GDIHandleAllocator
[Index
], 0xcd, GDI_STACK_LEVELS
* sizeof(ULONG
) );
444 KeRosGetStackFrames ( GDIHandleAllocator
[Index
], GDI_STACK_LEVELS
);
445 #endif /* GDI_DEBUG */
447 if(W32Process
!= NULL
)
449 InterlockedIncrement(&W32Process
->GDIObjects
);
451 Handle
= (HGDIOBJ
)((Index
& 0xFFFF) | (TypeInfo
<< GDI_ENTRY_UPPER_SHIFT
));
453 DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle
, ObjectBody
);
461 DPRINT1("[%d]Waiting on handle in index 0x%x\n", Attempts
, Index
);
464 /* damn, someone is trying to lock the object even though it doesn't
465 eve nexist anymore, wait a little and try again!
466 FIXME - we shouldn't loop forever! Give up after some time! */
473 if (ObjTypeInfo
[TypeIndex
].bUseLookaside
)
475 ExFreeToPagedLookasideList(LookasideList
, newObject
);
479 ExFreePool(newObject
);
481 DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
483 IntDumpHandleTable(HandleTable
);
484 #endif /* GDI_DEBUG */
488 DPRINT1("Not enough memory to allocate gdi object!\n");
494 * Free memory allocated for the GDI object. For each object type this function calls the
495 * appropriate cleanup routine.
497 * \param hObj - handle of the object to be deleted.
499 * \return Returns TRUE if succesful.
500 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
501 * to the calling process.
505 GDIOBJ_FreeObjDbg(PGDI_HANDLE_TABLE HandleTable
, const char* file
, int line
, HGDIOBJ hObj
, DWORD ExpectedType
)
506 #else /* !GDI_DEBUG */
507 GDIOBJ_FreeObj(PGDI_HANDLE_TABLE HandleTable
, HGDIOBJ hObj
, DWORD ExpectedType
)
508 #endif /* GDI_DEBUG */
510 PGDI_TABLE_ENTRY Entry
;
511 PPAGED_LOOKASIDE_LIST LookasideList
;
512 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
513 ULONG HandleType
, HandleUpper
, TypeIndex
;
519 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj
);
521 if(GDI_HANDLE_IS_STOCKOBJ(hObj
))
523 DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj
);
525 DPRINT1("-> called from %s:%i\n", file
, line
);
530 ProcessId
= PsGetCurrentProcessId();
531 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
533 Silent
= (ExpectedType
& GDI_OBJECT_TYPE_SILENT
);
534 ExpectedType
&= ~GDI_OBJECT_TYPE_SILENT
;
536 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
537 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
539 /* Check if we have the requested type */
540 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
541 HandleType
!= ExpectedType
) ||
544 DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
545 hObj
, HandleType
, ExpectedType
);
549 Entry
= GDI_HANDLE_GET_ENTRY(HandleTable
, hObj
);
552 /* lock the object, we must not delete global objects, so don't exchange the locking
553 process ID to zero when attempting to lock a global object... */
554 PrevProcId
= InterlockedCompareExchangePointer(&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
555 if(PrevProcId
== ProcessId
)
557 if( (Entry
->KernelData
!= NULL
) &&
558 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
562 GdiHdr
= GDIBdyToHdr(Entry
->KernelData
);
564 if(GdiHdr
->Locks
== 0)
567 PW32PROCESS W32Process
= PsGetCurrentProcessWin32Process();
569 /* Clear the type field so when unlocking the handle it gets finally deleted and increment reuse counter */
570 Entry
->Type
= (Entry
->Type
+ GDI_ENTRY_REUSE_INC
) & GDI_ENTRY_REUSE_MASK
;
571 Entry
->KernelData
= NULL
;
573 /* unlock the handle slot */
574 (void)InterlockedExchangePointer(&Entry
->ProcessId
, NULL
);
576 /* push this entry to the free list */
577 InterlockedPushEntrySList(&HandleTable
->FreeEntriesHead
,
578 &HandleTable
->FreeEntries
[GDI_ENTRY_TO_INDEX(HandleTable
, Entry
)]);
580 if(W32Process
!= NULL
)
582 InterlockedDecrement(&W32Process
->GDIObjects
);
585 /* call the cleanup routine. */
586 TypeIndex
= GDI_OBJECT_GET_TYPE_INDEX(HandleType
);
587 Ret
= RunCleanupCallback(GDIHdrToBdy(GdiHdr
), TypeIndex
);
589 /* Now it's time to free the memory */
590 if (ObjTypeInfo
[TypeIndex
].bUseLookaside
)
592 LookasideList
= FindLookasideList(HandleTable
, TypeIndex
);
593 if(LookasideList
!= NULL
)
595 ExFreeToPagedLookasideList(LookasideList
, GdiHdr
);
608 * The object is currently locked, so freeing is forbidden!
610 DPRINT1("GdiHdr->Locks: %d\n", GdiHdr
->Locks
);
612 DPRINT1("Locked from: %s:%d\n", GdiHdr
->lockfile
, GdiHdr
->lockline
);
619 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_FreeObj");
620 (void)InterlockedExchangePointer(&Entry
->ProcessId
, PrevProcId
);
623 else if(PrevProcId
== LockedProcessId
)
628 DPRINT1("[%d]Waiting on 0x%x\n", Attempts
, hObj
);
631 /* the object is currently locked, wait some time and try again.
632 FIXME - we shouldn't loop forever! Give up after some time! */
641 if(((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
643 DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj
);
644 KeRosDumpStackFrames(NULL
, 20);
648 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);
649 KeRosDumpStackFrames(NULL
, 20);
652 DPRINT1("-> called from %s:%i\n", file
, line
);
662 * \param hObject object handle
663 * \return if the function fails the returned value is FALSE.
666 NtGdiDeleteObject(HGDIOBJ hObject
)
668 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
670 return NULL
!= hObject
671 ? GDIOBJ_FreeObj(GdiHandleTable
, hObject
, GDI_OBJECT_TYPE_DONTCARE
) : FALSE
;
675 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
676 * \param Process - PID of the process that will be destroyed.
679 GDI_CleanupForProcess (PGDI_HANDLE_TABLE HandleTable
, struct _EPROCESS
*Process
)
681 PGDI_TABLE_ENTRY Entry
, End
;
682 PEPROCESS CurrentProcess
;
683 PW32PROCESS W32Process
;
685 ULONG Index
= RESERVE_ENTRIES_COUNT
;
687 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Process
->UniqueProcessId
);
688 CurrentProcess
= PsGetCurrentProcess();
689 if (CurrentProcess
!= Process
)
691 KeAttachProcess(&Process
->Pcb
);
693 W32Process
= (PW32PROCESS
)Process
->Win32Process
;
696 if(W32Process
->GDIObjects
> 0)
698 /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
699 we should delete it directly here! */
700 ProcId
= Process
->UniqueProcessId
;
702 End
= &HandleTable
->Entries
[GDI_HANDLE_COUNT
];
703 for(Entry
= &HandleTable
->Entries
[RESERVE_ENTRIES_COUNT
];
707 /* ignore the lock bit */
708 if((HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcId
&& (Entry
->Type
& ~GDI_HANDLE_REUSE_MASK
) != 0)
710 HGDIOBJ ObjectHandle
;
712 /* Create the object handle for the entry, the lower(!) 16 bit of the
713 Type field includes the type of the object including the stock
714 object flag - but since stock objects don't have a process id we can
715 simply ignore this fact here. */
716 ObjectHandle
= (HGDIOBJ
)(Index
| (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
));
718 if(GDIOBJ_FreeObj(HandleTable
, ObjectHandle
, GDI_OBJECT_TYPE_DONTCARE
) &&
719 W32Process
->GDIObjects
== 0)
721 /* there are no more gdi handles for this process, bail */
728 if (CurrentProcess
!= Process
)
733 DPRINT("Completed cleanup for process %d\n", Process
->UniqueProcessId
);
739 * Return pointer to the object by handle.
741 * \param hObj Object handle
742 * \return Pointer to the object.
744 * \note Process can only get pointer to the objects it created or global objects.
746 * \todo Get rid of the ExpectedType parameter!
748 PGDIOBJ INTERNAL_CALL
750 GDIOBJ_LockObjDbg (PGDI_HANDLE_TABLE HandleTable
, const char* file
, int line
, HGDIOBJ hObj
, DWORD ExpectedType
)
751 #else /* !GDI_DEBUG */
752 GDIOBJ_LockObj (PGDI_HANDLE_TABLE HandleTable
, HGDIOBJ hObj
, DWORD ExpectedType
)
753 #endif /* GDI_DEBUG */
756 PGDI_TABLE_ENTRY Entry
;
757 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
758 PGDIOBJ Object
= NULL
;
759 ULONG HandleType
, HandleUpper
;
761 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
762 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
763 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
765 /* Check that the handle index is valid. */
766 if (HandleIndex
>= GDI_HANDLE_COUNT
)
769 Entry
= &HandleTable
->Entries
[HandleIndex
];
771 /* Check if we have the requested type */
772 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
773 HandleType
!= ExpectedType
) ||
776 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
777 hObj
, HandleType
, ExpectedType
);
781 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
782 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
784 /* Check for invalid owner. */
785 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
791 * Prevent the thread from being terminated during the locking process.
792 * It would result in undesired effects and inconsistency of the global
796 KeEnterCriticalRegion();
799 * Loop until we either successfully lock the handle entry & object or
800 * fail some of the check.
805 /* Lock the handle table entry. */
806 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
807 PrevProcId
= InterlockedCompareExchangePointer(&Entry
->ProcessId
,
811 if (PrevProcId
== HandleProcessId
)
814 * We're locking an object that belongs to our process or it's a
815 * global object if HandleProcessId is 0 here.
818 if ( (Entry
->KernelData
!= NULL
) &&
819 ((Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
) == HandleUpper
) )
821 PGDIOBJHDR GdiHdr
= GDIBdyToHdr(Entry
->KernelData
);
822 PETHREAD Thread
= PsGetCurrentThread();
824 if (GdiHdr
->Locks
== 0)
826 GdiHdr
->LockingThread
= Thread
;
829 GdiHdr
->lockfile
= file
;
830 GdiHdr
->lockline
= line
;
832 Object
= Entry
->KernelData
;
836 InterlockedIncrement((PLONG
)&GdiHdr
->Locks
);
837 if (GdiHdr
->LockingThread
!= Thread
)
839 InterlockedDecrement((PLONG
)&GdiHdr
->Locks
);
841 /* Unlock the handle table entry. */
842 (void)InterlockedExchangePointer(&Entry
->ProcessId
, PrevProcId
);
847 Object
= Entry
->KernelData
;
853 * Debugging code. Report attempts to lock deleted handles and
854 * locking type mismatches.
856 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_LockObj");
859 DPRINT1("-> called from %s:%i\n", file
, line
);
863 /* Unlock the handle table entry. */
864 (void)InterlockedExchangePointer(&Entry
->ProcessId
, PrevProcId
);
871 * The handle is currently locked, wait some time and try again.
879 KeLeaveCriticalRegion();
886 * Return pointer to the object by handle (and allow sharing of the handle
889 * \param hObj Object handle
890 * \return Pointer to the object.
892 * \note Process can only get pointer to the objects it created or global objects.
894 * \todo Get rid of the ExpectedType parameter!
896 PGDIOBJ INTERNAL_CALL
898 GDIOBJ_ShareLockObjDbg (PGDI_HANDLE_TABLE HandleTable
, const char* file
, int line
, HGDIOBJ hObj
, DWORD ExpectedType
)
899 #else /* !GDI_DEBUG */
900 GDIOBJ_ShareLockObj (PGDI_HANDLE_TABLE HandleTable
, HGDIOBJ hObj
, DWORD ExpectedType
)
901 #endif /* GDI_DEBUG */
904 PGDI_TABLE_ENTRY Entry
;
905 HANDLE ProcessId
, HandleProcessId
, LockedProcessId
, PrevProcId
;
906 PGDIOBJ Object
= NULL
;
907 ULONG_PTR HandleType
, HandleUpper
;
909 HandleIndex
= GDI_HANDLE_GET_INDEX(hObj
);
910 HandleType
= GDI_HANDLE_GET_TYPE(hObj
);
911 HandleUpper
= GDI_HANDLE_GET_UPPER(hObj
);
913 /* Check that the handle index is valid. */
914 if (HandleIndex
>= GDI_HANDLE_COUNT
)
917 /* Check if we have the requested type */
918 if ( (ExpectedType
!= GDI_OBJECT_TYPE_DONTCARE
&&
919 HandleType
!= ExpectedType
) ||
922 DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
923 hObj
, HandleType
, ExpectedType
);
927 Entry
= &HandleTable
->Entries
[HandleIndex
];
929 ProcessId
= (HANDLE
)((ULONG_PTR
)PsGetCurrentProcessId() & ~1);
930 HandleProcessId
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~1);
932 /* Check for invalid owner. */
933 if (ProcessId
!= HandleProcessId
&& HandleProcessId
!= NULL
)
939 * Prevent the thread from being terminated during the locking process.
940 * It would result in undesired effects and inconsistency of the global
944 KeEnterCriticalRegion();
947 * Loop until we either successfully lock the handle entry & object or
948 * fail some of the check.
953 /* Lock the handle table entry. */
954 LockedProcessId
= (HANDLE
)((ULONG_PTR
)HandleProcessId
| 0x1);
955 PrevProcId
= InterlockedCompareExchangePointer(&Entry
->ProcessId
,
959 if (PrevProcId
== HandleProcessId
)
962 * We're locking an object that belongs to our process or it's a
963 * global object if HandleProcessId is 0 here.
966 if ( (Entry
->KernelData
!= NULL
) &&
967 (HandleUpper
== (Entry
->Type
<< GDI_ENTRY_UPPER_SHIFT
)) )
969 PGDIOBJHDR GdiHdr
= GDIBdyToHdr(Entry
->KernelData
);
972 if (InterlockedIncrement((PLONG
)&GdiHdr
->Locks
) == 1)
974 GdiHdr
->lockfile
= file
;
975 GdiHdr
->lockline
= line
;
978 InterlockedIncrement((PLONG
)&GdiHdr
->Locks
);
980 Object
= Entry
->KernelData
;
985 * Debugging code. Report attempts to lock deleted handles and
986 * locking type mismatches.
988 LockErrorDebugOutput(hObj
, Entry
, "GDIOBJ_ShareLockObj");
991 DPRINT1("-> called from %s:%i\n", file
, line
);
995 /* Unlock the handle table entry. */
996 (void)InterlockedExchangePointer(&Entry
->ProcessId
, PrevProcId
);
1003 * The handle is currently locked, wait some time and try again.
1011 KeLeaveCriticalRegion();
1018 * Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
1019 * as soon as you don't need to have access to it's data.
1021 * \param Object Object pointer (as returned by GDIOBJ_LockObj).
1024 GDIOBJ_UnlockObjByPtr(PGDI_HANDLE_TABLE HandleTable
, PGDIOBJ Object
)
1026 PGDIOBJHDR GdiHdr
= GDIBdyToHdr(Object
);
1028 if (InterlockedDecrement((PLONG
)&GdiHdr
->Locks
) == 0)
1030 GdiHdr
->lockfile
= NULL
;
1031 GdiHdr
->lockline
= 0;
1034 InterlockedDecrement((PLONG
)&GdiHdr
->Locks
);
1039 GDIOBJ_OwnedByCurrentProcess(PGDI_HANDLE_TABLE HandleTable
, HGDIOBJ ObjectHandle
)
1041 PGDI_TABLE_ENTRY Entry
;
1045 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
1047 if(!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1049 ProcessId
= PsGetCurrentProcessId();
1051 Entry
= GDI_HANDLE_GET_ENTRY(HandleTable
, ObjectHandle
);
1052 Ret
= Entry
->KernelData
!= NULL
&&
1053 (Entry
->Type
& ~GDI_HANDLE_REUSE_MASK
) != 0 &&
1054 (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1) == ProcessId
;
1063 GDIOBJ_ConvertToStockObj(PGDI_HANDLE_TABLE HandleTable
, HGDIOBJ
*hObj
)
1066 * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
1067 * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
1069 PGDI_TABLE_ENTRY Entry
;
1070 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1078 DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", *hObj
);
1080 Thread
= PsGetCurrentThread();
1082 if(!GDI_HANDLE_IS_STOCKOBJ(*hObj
))
1084 ProcessId
= PsGetCurrentProcessId();
1085 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1087 Entry
= GDI_HANDLE_GET_ENTRY(HandleTable
, *hObj
);
1090 /* lock the object, we must not convert stock objects, so don't check!!! */
1091 PrevProcId
= InterlockedCompareExchangePointer(&Entry
->ProcessId
, LockedProcessId
, ProcessId
);
1092 if(PrevProcId
== ProcessId
)
1094 LONG NewType
, PrevType
, OldType
;
1096 /* we're locking an object that belongs to our process. First calculate
1097 the new object type including the stock object flag and then try to
1099 /* FIXME: On Windows the higher 16 bit of the type field don't always match
1100 the type from the handle, it is probably a storage type
1101 (type = pen, storage = brush) */
1102 NewType
= GDI_HANDLE_GET_TYPE(*hObj
);
1103 NewType
|= GDI_HANDLE_GET_UPPER(*hObj
) >> GDI_ENTRY_UPPER_SHIFT
;
1105 /* This is the type that the object should have right now, save it */
1107 /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
1108 NewType
|= GDI_ENTRY_STOCK_MASK
;
1110 /* Try to exchange the type field - but only if the old (previous type) matches! */
1111 PrevType
= InterlockedCompareExchange(&Entry
->Type
, NewType
, OldType
);
1112 if(PrevType
== OldType
&& Entry
->KernelData
!= NULL
)
1114 PETHREAD PrevThread
;
1117 /* We successfully set the stock object flag.
1118 KernelData should never be NULL here!!! */
1119 ASSERT(Entry
->KernelData
);
1121 GdiHdr
= GDIBdyToHdr(Entry
->KernelData
);
1123 PrevThread
= GdiHdr
->LockingThread
;
1124 if(GdiHdr
->Locks
== 0 || PrevThread
== Thread
)
1126 /* dereference the process' object counter */
1127 if(PrevProcId
!= GDI_GLOBAL_PROCESS
)
1129 PEPROCESS OldProcess
;
1130 PW32PROCESS W32Process
;
1134 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1135 if(NT_SUCCESS(Status
))
1137 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1138 if(W32Process
!= NULL
)
1140 InterlockedDecrement(&W32Process
->GDIObjects
);
1142 ObDereferenceObject(OldProcess
);
1146 /* remove the process id lock and make it global */
1147 (void)InterlockedExchangePointer(&Entry
->ProcessId
, GDI_GLOBAL_PROCESS
);
1149 *hObj
= (HGDIOBJ
)((ULONG
)(*hObj
) | GDI_HANDLE_STOCK_MASK
);
1151 /* we're done, successfully converted the object */
1159 if(GdiHdr
->lockfile
!= NULL
)
1161 DPRINT1("[%d]Locked %s:%i by 0x%x (we're 0x%x)\n", Attempts
, GdiHdr
->lockfile
, GdiHdr
->lockline
, PrevThread
, Thread
);
1165 /* WTF?! The object is already locked by a different thread!
1166 Release the lock, wait a bit and try again!
1167 FIXME - we should give up after some time unless we want to wait forever! */
1168 (void)InterlockedExchangePointer(&Entry
->ProcessId
, PrevProcId
);
1176 DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj
);
1179 else if(PrevProcId
== LockedProcessId
)
1184 DPRINT1("[%d]Waiting on 0x%x\n", Attempts
, hObj
);
1187 /* the object is currently locked, wait some time and try again.
1188 FIXME - we shouldn't loop forever! Give up after some time! */
1195 DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj
);
1203 GDIOBJ_SetOwnership(PGDI_HANDLE_TABLE HandleTable
, HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
1205 PGDI_TABLE_ENTRY Entry
;
1206 HANDLE ProcessId
, LockedProcessId
, PrevProcId
;
1212 DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle
, (NewOwner
? PsGetProcessId(NewOwner
) : 0));
1214 Thread
= PsGetCurrentThread();
1216 if(!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle
))
1218 ProcessId
= PsGetCurrentProcessId();
1219 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1221 Entry
= GDI_HANDLE_GET_ENTRY(HandleTable
, ObjectHandle
);
1224 /* lock the object, we must not convert stock objects, so don't check!!! */
1225 PrevProcId
= InterlockedCompareExchangePointer(&Entry
->ProcessId
, ProcessId
, LockedProcessId
);
1226 if(PrevProcId
== ProcessId
)
1228 PETHREAD PrevThread
;
1230 if((Entry
->Type
& ~GDI_ENTRY_REUSE_MASK
) != 0 && Entry
->KernelData
!= NULL
)
1232 PGDIOBJHDR GdiHdr
= GDIBdyToHdr(Entry
->KernelData
);
1234 PrevThread
= GdiHdr
->LockingThread
;
1235 if(GdiHdr
->Locks
== 0 || PrevThread
== Thread
)
1237 PEPROCESS OldProcess
;
1238 PW32PROCESS W32Process
;
1241 /* dereference the process' object counter */
1243 if((ULONG_PTR
)PrevProcId
& ~0x1)
1245 Status
= PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1), &OldProcess
);
1246 if(NT_SUCCESS(Status
))
1248 W32Process
= (PW32PROCESS
)OldProcess
->Win32Process
;
1249 if(W32Process
!= NULL
)
1251 InterlockedDecrement(&W32Process
->GDIObjects
);
1253 ObDereferenceObject(OldProcess
);
1257 if(NewOwner
!= NULL
)
1259 ProcessId
= PsGetProcessId(NewOwner
);
1261 /* Increase the new process' object counter */
1262 W32Process
= (PW32PROCESS
)NewOwner
->Win32Process
;
1263 if(W32Process
!= NULL
)
1265 InterlockedIncrement(&W32Process
->GDIObjects
);
1271 /* remove the process id lock and change it to the new process id */
1272 (void)InterlockedExchangePointer(&Entry
->ProcessId
, ProcessId
);
1282 if(GdiHdr
->lockfile
!= NULL
)
1284 DPRINT1("[%d]Locked from %s:%i by 0x%x (we're 0x%x)\n", Attempts
, GdiHdr
->lockfile
, GdiHdr
->lockline
, PrevThread
, Thread
);
1288 /* WTF?! The object is already locked by a different thread!
1289 Release the lock, wait a bit and try again! DO reset the pid lock
1290 so we make sure we don't access invalid memory in case the object is
1291 being deleted in the meantime (because we don't have aquired a reference
1293 FIXME - we should give up after some time unless we want to wait forever! */
1294 (void)InterlockedExchangePointer(&Entry
->ProcessId
, PrevProcId
);
1302 DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle
);
1305 else if(PrevProcId
== LockedProcessId
)
1310 DPRINT1("[%d]Waiting on 0x%x\n", Attempts
, ObjectHandle
);
1313 /* the object is currently locked, wait some time and try again.
1314 FIXME - we shouldn't loop forever! Give up after some time! */
1319 else if(((ULONG_PTR
)PrevProcId
& ~0x1) == 0)
1321 /* allow changing ownership of global objects */
1323 LockedProcessId
= (HANDLE
)((ULONG_PTR
)ProcessId
| 0x1);
1326 else if((HANDLE
)((ULONG_PTR
)PrevProcId
& ~0x1) != PsGetCurrentProcessId())
1328 DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle
, (ULONG_PTR
)PrevProcId
& ~0x1, PsGetCurrentProcessId());
1332 DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle
);
1338 GDIOBJ_CopyOwnership(PGDI_HANDLE_TABLE HandleTable
, HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
1340 PGDI_TABLE_ENTRY FromEntry
;
1342 HANDLE FromProcessId
, FromLockedProcessId
, FromPrevProcId
;
1347 DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom
, CopyTo
);
1349 Thread
= PsGetCurrentThread();
1351 if(!GDI_HANDLE_IS_STOCKOBJ(CopyFrom
) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo
))
1353 FromEntry
= GDI_HANDLE_GET_ENTRY(HandleTable
, CopyFrom
);
1355 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromEntry
->ProcessId
& ~0x1);
1356 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1359 /* lock the object, we must not convert stock objects, so don't check!!! */
1360 FromPrevProcId
= InterlockedCompareExchangePointer(&FromEntry
->ProcessId
, FromProcessId
, FromLockedProcessId
);
1361 if(FromPrevProcId
== FromProcessId
)
1363 PETHREAD PrevThread
;
1366 if((FromEntry
->Type
& ~GDI_ENTRY_REUSE_MASK
) != 0 && FromEntry
->KernelData
!= NULL
)
1368 GdiHdr
= GDIBdyToHdr(FromEntry
->KernelData
);
1370 /* save the pointer to the calling thread so we know it was this thread
1371 that locked the object */
1372 PrevThread
= GdiHdr
->LockingThread
;
1373 if(GdiHdr
->Locks
== 0 || PrevThread
== Thread
)
1375 /* now let's change the ownership of the target object */
1377 if(((ULONG_PTR
)FromPrevProcId
& ~0x1) != 0)
1379 PEPROCESS ProcessTo
;
1381 if(NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1), &ProcessTo
)))
1383 GDIOBJ_SetOwnership(HandleTable
, CopyTo
, ProcessTo
);
1384 ObDereferenceObject(ProcessTo
);
1389 /* mark the object as global */
1390 GDIOBJ_SetOwnership(HandleTable
, CopyTo
, NULL
);
1393 (void)InterlockedExchangePointer(&FromEntry
->ProcessId
, FromPrevProcId
);
1400 if(GdiHdr
->lockfile
!= NULL
)
1402 DPRINT1("[%d]Locked from %s:%i by 0x%x (we're 0x%x)\n", Attempts
, GdiHdr
->lockfile
, GdiHdr
->lockline
, PrevThread
, Thread
);
1406 /* WTF?! The object is already locked by a different thread!
1407 Release the lock, wait a bit and try again! DO reset the pid lock
1408 so we make sure we don't access invalid memory in case the object is
1409 being deleted in the meantime (because we don't have aquired a reference
1411 FIXME - we should give up after some time unless we want to wait forever! */
1412 (void)InterlockedExchangePointer(&FromEntry
->ProcessId
, FromPrevProcId
);
1415 goto LockHandleFrom
;
1420 DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom
);
1423 else if(FromPrevProcId
== FromLockedProcessId
)
1428 DPRINT1("[%d]Waiting on 0x%x\n", Attempts
, CopyFrom
);
1431 /* the object is currently locked, wait some time and try again.
1432 FIXME - we shouldn't loop forever! Give up after some time! */
1435 goto LockHandleFrom
;
1437 else if((HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1) != PsGetCurrentProcessId())
1439 /* FIXME - should we really allow copying ownership from objects that we don't even own? */
1440 DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom
, (ULONG_PTR
)FromPrevProcId
& ~0x1, PsGetCurrentProcessId());
1441 FromProcessId
= (HANDLE
)((ULONG_PTR
)FromPrevProcId
& ~0x1);
1442 FromLockedProcessId
= (HANDLE
)((ULONG_PTR
)FromProcessId
| 0x1);
1443 goto LockHandleFrom
;
1447 DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom
);
1453 GDI_MapHandleTable(PSECTION_OBJECT SectionObject
, PEPROCESS Process
)
1455 PVOID MappedView
= NULL
;
1457 LARGE_INTEGER Offset
;
1458 ULONG ViewSize
= sizeof(GDI_HANDLE_TABLE
);
1460 Offset
.QuadPart
= 0;
1462 ASSERT(SectionObject
!= NULL
);
1463 ASSERT(Process
!= NULL
);
1465 Status
= MmMapViewOfSection(SectionObject
,
1476 if (!NT_SUCCESS(Status
))
1485 NtGdiCreateClientObj(
1496 NtGdiDeleteClientObj(