📄 gdiobj.c
字号:
HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
PGDIOBJ Object = NULL;
ULONG HandleType, HandleUpper;
HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
HandleType = GDI_HANDLE_GET_TYPE(hObj);
HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
/* Check that the handle index is valid. */
if (HandleIndex >= GDI_HANDLE_COUNT)
return NULL;
Entry = &HandleTable->Entries[HandleIndex];
/* Check if we have the requested type */
if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
HandleType != ExpectedType) ||
HandleType == 0 )
{
DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
hObj, HandleType, ExpectedType);
return NULL;
}
ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
/* Check for invalid owner. */
if (ProcessId != HandleProcessId && HandleProcessId != NULL)
{
return NULL;
}
/*
* Prevent the thread from being terminated during the locking process.
* It would result in undesired effects and inconsistency of the global
* handle table.
*/
KeEnterCriticalRegion();
/*
* Loop until we either successfully lock the handle entry & object or
* fail some of the check.
*/
for (;;)
{
/* Lock the handle table entry. */
LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId,
LockedProcessId,
HandleProcessId);
if (PrevProcId == HandleProcessId)
{
/*
* We're locking an object that belongs to our process or it's a
* global object if HandleProcessId is 0 here.
*/
if ( (Entry->KernelData != NULL) &&
((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
{
PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
PETHREAD Thread = PsGetCurrentThread();
if (GdiHdr->Locks == 0)
{
GdiHdr->LockingThread = Thread;
GdiHdr->Locks = 1;
#ifdef GDI_DEBUG
GdiHdr->lockfile = file;
GdiHdr->lockline = line;
#endif
Object = Entry->KernelData;
}
else
{
InterlockedIncrement((PLONG)&GdiHdr->Locks);
if (GdiHdr->LockingThread != Thread)
{
InterlockedDecrement((PLONG)&GdiHdr->Locks);
/* Unlock the handle table entry. */
(void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
DelayExecution();
continue;
}
Object = Entry->KernelData;
}
}
else
{
/*
* Debugging code. Report attempts to lock deleted handles and
* locking type mismatches.
*/
LockErrorDebugOutput(hObj, Entry, "GDIOBJ_LockObj");
#ifdef GDI_DEBUG
DPRINT1("-> called from %s:%i\n", file, line);
#endif
}
/* Unlock the handle table entry. */
(void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
break;
}
else
{
/*
* The handle is currently locked, wait some time and try again.
*/
DelayExecution();
continue;
}
}
KeLeaveCriticalRegion();
return Object;
}
/*!
* Return pointer to the object by handle (and allow sharing of the handle
* across threads).
*
* \param hObj Object handle
* \return Pointer to the object.
*
* \note Process can only get pointer to the objects it created or global objects.
*
* \todo Get rid of the ExpectedType parameter!
*/
PGDIOBJ INTERNAL_CALL
#ifdef GDI_DEBUG
GDIOBJ_ShareLockObjDbg (PGDI_HANDLE_TABLE HandleTable, const char* file, int line, HGDIOBJ hObj, DWORD ExpectedType)
#else /* !GDI_DEBUG */
GDIOBJ_ShareLockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
#endif /* GDI_DEBUG */
{
USHORT HandleIndex;
PGDI_TABLE_ENTRY Entry;
HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
PGDIOBJ Object = NULL;
ULONG_PTR HandleType, HandleUpper;
HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
HandleType = GDI_HANDLE_GET_TYPE(hObj);
HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
/* Check that the handle index is valid. */
if (HandleIndex >= GDI_HANDLE_COUNT)
return NULL;
/* Check if we have the requested type */
if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
HandleType != ExpectedType) ||
HandleType == 0 )
{
DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
hObj, HandleType, ExpectedType);
return NULL;
}
Entry = &HandleTable->Entries[HandleIndex];
ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
/* Check for invalid owner. */
if (ProcessId != HandleProcessId && HandleProcessId != NULL)
{
return NULL;
}
/*
* Prevent the thread from being terminated during the locking process.
* It would result in undesired effects and inconsistency of the global
* handle table.
*/
KeEnterCriticalRegion();
/*
* Loop until we either successfully lock the handle entry & object or
* fail some of the check.
*/
for (;;)
{
/* Lock the handle table entry. */
LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId,
LockedProcessId,
HandleProcessId);
if (PrevProcId == HandleProcessId)
{
/*
* We're locking an object that belongs to our process or it's a
* global object if HandleProcessId is 0 here.
*/
if ( (Entry->KernelData != NULL) &&
(HandleUpper == (Entry->Type << GDI_ENTRY_UPPER_SHIFT)) )
{
PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
#ifdef GDI_DEBUG
if (InterlockedIncrement((PLONG)&GdiHdr->Locks) == 1)
{
GdiHdr->lockfile = file;
GdiHdr->lockline = line;
}
#else
InterlockedIncrement((PLONG)&GdiHdr->Locks);
#endif
Object = Entry->KernelData;
}
else
{
/*
* Debugging code. Report attempts to lock deleted handles and
* locking type mismatches.
*/
LockErrorDebugOutput(hObj, Entry, "GDIOBJ_ShareLockObj");
#ifdef GDI_DEBUG
DPRINT1("-> called from %s:%i\n", file, line);
#endif
}
/* Unlock the handle table entry. */
(void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
break;
}
else
{
/*
* The handle is currently locked, wait some time and try again.
*/
DelayExecution();
continue;
}
}
KeLeaveCriticalRegion();
return Object;
}
/*!
* Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
* as soon as you don't need to have access to it's data.
* \param Object Object pointer (as returned by GDIOBJ_LockObj).
*/
VOID INTERNAL_CALL
GDIOBJ_UnlockObjByPtr(PGDI_HANDLE_TABLE HandleTable, PGDIOBJ Object)
{
PGDIOBJHDR GdiHdr = GDIBdyToHdr(Object);
#ifdef GDI_DEBUG
if (InterlockedDecrement((PLONG)&GdiHdr->Locks) == 0)
{
GdiHdr->lockfile = NULL;
GdiHdr->lockline = 0;
}
#else
InterlockedDecrement((PLONG)&GdiHdr->Locks);
#endif
}
BOOL INTERNAL_CALL
GDIOBJ_OwnedByCurrentProcess(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ ObjectHandle)
{
PGDI_TABLE_ENTRY Entry;
HANDLE ProcessId;
BOOL Ret;
DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
if(!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
{
ProcessId = PsGetCurrentProcessId();
Entry = GDI_HANDLE_GET_ENTRY(HandleTable, ObjectHandle);
Ret = Entry->KernelData != NULL &&
(Entry->Type & ~GDI_HANDLE_REUSE_MASK) != 0 &&
(HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcessId;
return Ret;
}
return FALSE;
}
BOOL INTERNAL_CALL
GDIOBJ_ConvertToStockObj(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ *hObj)
{
/*
* FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
* MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
*/
PGDI_TABLE_ENTRY Entry;
HANDLE ProcessId, LockedProcessId, PrevProcId;
PETHREAD Thread;
#ifdef GDI_DEBUG
ULONG Attempts = 0;
#endif
ASSERT(hObj);
DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", *hObj);
Thread = PsGetCurrentThread();
if(!GDI_HANDLE_IS_STOCKOBJ(*hObj))
{
ProcessId = PsGetCurrentProcessId();
LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
Entry = GDI_HANDLE_GET_ENTRY(HandleTable, *hObj);
LockHandle:
/* lock the object, we must not convert stock objects, so don't check!!! */
PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, ProcessId);
if(PrevProcId == ProcessId)
{
LONG NewType, PrevType, OldType;
/* we're locking an object that belongs to our process. First calculate
the new object type including the stock object flag and then try to
exchange it.*/
/* FIXME: On Windows the higher 16 bit of the type field don't always match
the type from the handle, it is probably a storage type
(type = pen, storage = brush) */
NewType = GDI_HANDLE_GET_TYPE(*hObj);
NewType |= GDI_HANDLE_GET_UPPER(*hObj) >> GDI_ENTRY_UPPER_SHIFT;
/* This is the type that the object should have right now, save it */
OldType = NewType;
/* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
NewType |= GDI_ENTRY_STOCK_MASK;
/* Try to exchange the type field - but only if the old (previous type) matches! */
PrevType = InterlockedCompareExchange(&Entry->Type, NewType, OldType);
if(PrevType == OldType && Entry->KernelData != NULL)
{
PETHREAD PrevThread;
PGDIOBJHDR GdiHdr;
/* We successfully set the stock object flag.
KernelData should never be NULL here!!! */
ASSERT(Entry->KernelData);
GdiHdr = GDIBdyToHdr(Entry->KernelData);
PrevThread = GdiHdr->LockingThread;
if(GdiHdr->Locks == 0 || PrevThread == Thread)
{
/* dereference the process' object counter */
if(PrevProcId != GDI_GLOBAL_PROCESS)
{
PEPROCESS OldProcess;
PW32PROCESS W32Process;
NTSTATUS Status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -