⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gdiobj.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
  PGDI_TABLE_ENTRY Entry;
  PPAGED_LOOKASIDE_LIST LookasideList;
  HANDLE ProcessId, LockedProcessId, PrevProcId;
  LONG ExpectedType;
  BOOL Silent;
#ifdef GDI_DEBUG
  ULONG Attempts = 0;
#endif

  DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj);

  if(GDI_HANDLE_IS_STOCKOBJ(hObj))
  {
    DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj);
#ifdef GDI_DEBUG
    DPRINT1("-> called from %s:%i\n", file, line);
#endif
    return FALSE;
  }

  ProcessId = PsGetCurrentProcessId();
  LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);

  Silent = (ObjectType & GDI_OBJECT_TYPE_SILENT);
  ObjectType &= ~GDI_OBJECT_TYPE_SILENT;

  ExpectedType = ((ObjectType != GDI_OBJECT_TYPE_DONTCARE) ? ObjectType : 0);

  Entry = GDI_HANDLE_GET_ENTRY(HandleTable, hObj);

LockHandle:
  /* lock the object, we must not delete global objects, so don't exchange the locking
     process ID to zero when attempting to lock a global object... */
  PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, ProcessId);
  if(PrevProcId == ProcessId)
  {
    if(Entry->Type != 0 && Entry->KernelData != NULL &&
       (ExpectedType == 0 || ((Entry->Type << 16) == ExpectedType)) &&
       (Entry->Type & (GDI_HANDLE_TYPE_MASK | GDI_HANDLE_REUSE_MASK)) ==
       ((ULONG_PTR)hObj & (GDI_HANDLE_TYPE_MASK | GDI_HANDLE_REUSE_MASK)))
    {
      PGDIOBJHDR GdiHdr;

      GdiHdr = GDIBdyToHdr(Entry->KernelData);

      if(GdiHdr->Locks == 0)
      {
        BOOL Ret;
        PW32PROCESS W32Process = PsGetCurrentProcessWin32Process();
        ULONG Type = Entry->Type << 16;

        /* Clear the type field so when unlocking the handle it gets finally deleted and increment reuse counter */
        Entry->Type = ((Entry->Type >> GDI_HANDLE_REUSECNT_SHIFT) + 1) << GDI_HANDLE_REUSECNT_SHIFT;
        Entry->KernelData = NULL;

        /* unlock the handle slot */
        (void)InterlockedExchangePointer(&Entry->ProcessId, NULL);

        /* push this entry to the free list */
        InterlockedPushEntrySList(&HandleTable->FreeEntriesHead,
                                  &HandleTable->FreeEntries[GDI_ENTRY_TO_INDEX(HandleTable, Entry)]);

        if(W32Process != NULL)
        {
          InterlockedDecrement(&W32Process->GDIObjects);
        }

        /* call the cleanup routine. */
        Ret = RunCleanupCallback(GDIHdrToBdy(GdiHdr), Type);

        /* Now it's time to free the memory */
        LookasideList = FindLookasideList(HandleTable, Type);
        if(LookasideList != NULL)
        {
          ExFreeToPagedLookasideList(LookasideList, GdiHdr);
        }

        return Ret;
      }
      else
      {
        /*
         * The object is currently locked, so freeing is forbidden!
         */
        DPRINT1("GdiHdr->Locks: %d\n", GdiHdr->Locks);
#ifdef GDI_DEBUG
        DPRINT1("Locked from: %s:%d\n", GdiHdr->lockfile, GdiHdr->lockline);
#endif
        ASSERT(FALSE);
      }
    }
    else
    {
      if((Entry->Type & ~GDI_HANDLE_REUSE_MASK) != 0)
      {
        DPRINT1("Attempted to delete object 0x%x, type mismatch (0x%x : 0x%x)\n", hObj, ObjectType, ExpectedType);
        KeRosDumpStackFrames(NULL, 20);
      }
      else
      {
        DPRINT1("Attempted to delete object 0x%x which was already deleted!\n", hObj);
         KeRosDumpStackFrames(NULL, 20);
      }
      (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
    }
  }
  else if(PrevProcId == LockedProcessId)
  {
#ifdef GDI_DEBUG
    if(++Attempts > 20)
    {
      DPRINT1("[%d]Waiting on 0x%x\n", Attempts, hObj);
    }
#endif
    /* the object is currently locked, wait some time and try again.
       FIXME - we shouldn't loop forever! Give up after some time! */
    DelayExecution();
    /* try again */
    goto LockHandle;
  }
  else
  {
    if(!Silent)
    {
      if(((ULONG_PTR)PrevProcId & ~0x1) == 0)
      {
        DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj);
        KeRosDumpStackFrames(NULL, 20);
      }
      else
      {
        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);
        KeRosDumpStackFrames(NULL, 20);
      }
#ifdef GDI_DEBUG
      DPRINT1("-> called from %s:%i\n", file, line);
#endif
    }
  }

  return FALSE;
}

/*!
 * Delete GDI object
 * \param	hObject object handle
 * \return	if the function fails the returned value is FALSE.
*/
BOOL STDCALL
NtGdiDeleteObject(HGDIOBJ hObject)
{
  DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);

  return NULL != hObject
         ? GDIOBJ_FreeObj(GdiHandleTable, hObject, GDI_OBJECT_TYPE_DONTCARE) : FALSE;
}

/*!
 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
 * \param	Process - PID of the process that will be destroyed.
*/
BOOL INTERNAL_CALL
GDI_CleanupForProcess (PGDI_HANDLE_TABLE HandleTable, struct _EPROCESS *Process)
{
  PGDI_TABLE_ENTRY Entry, End;
  PEPROCESS CurrentProcess;
  PW32PROCESS W32Process;
  HANDLE ProcId;
  ULONG Index = RESERVE_ENTRIES_COUNT;

  DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId);
  CurrentProcess = PsGetCurrentProcess();
  if (CurrentProcess != Process)
    {
      KeAttachProcess(&Process->Pcb);
    }
  W32Process = (PW32PROCESS)Process->Win32Process;
  ASSERT(W32Process);

  if(W32Process->GDIObjects > 0)
  {
    /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
               we should delete it directly here! */
    ProcId = Process->UniqueProcessId;

    End = &HandleTable->Entries[GDI_HANDLE_COUNT];
    for(Entry = &HandleTable->Entries[RESERVE_ENTRIES_COUNT];
        Entry != End;
        Entry++, Index++)
    {
      /* ignore the lock bit */
      if((HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId && (Entry->Type & ~GDI_HANDLE_REUSE_MASK) != 0)
      {
        HGDIOBJ ObjectHandle;

        /* Create the object handle for the entry, the upper 16 bit of the
           Type field includes the type of the object including the stock
           object flag - but since stock objects don't have a process id we can
           simply ignore this fact here. */
        ObjectHandle = (HGDIOBJ)(Index | (Entry->Type & 0xFFFF0000));

        if(GDIOBJ_FreeObj(HandleTable, ObjectHandle, GDI_OBJECT_TYPE_DONTCARE) &&
           W32Process->GDIObjects == 0)
        {
          /* there are no more gdi handles for this process, bail */
          break;
        }
      }
    }
  }

  if (CurrentProcess != Process)
    {
      KeDetachProcess();
    }

  DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);

  return TRUE;
}

/*!
 * Return pointer to the object by handle.
 *
 * \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 ObjectType parameter!
*/
PGDIOBJ INTERNAL_CALL
#ifdef GDI_DEBUG
GDIOBJ_LockObjDbg (PGDI_HANDLE_TABLE HandleTable, const char* file, int line, HGDIOBJ hObj, DWORD ObjectType)
#else /* !GDI_DEBUG */
GDIOBJ_LockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ObjectType)
#endif /* GDI_DEBUG */
{
   USHORT HandleIndex;
   PGDI_TABLE_ENTRY HandleEntry;
   HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
   PGDIOBJ Object = NULL;

   HandleIndex = GDI_HANDLE_GET_INDEX(hObj);

   /* Check that the handle index is valid. */
   if (HandleIndex >= GDI_HANDLE_COUNT)
      return NULL;

   HandleEntry = &HandleTable->Entries[HandleIndex];

   ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
   HandleProcessId = (HANDLE)((ULONG_PTR)HandleEntry->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(&HandleEntry->ProcessId, 
                                                     LockedProcessId,
                                                     HandleProcessId);

      if (PrevProcId == HandleProcessId)
      {
         LONG HandleType = HandleEntry->Type << 16;

         /*
          * We're locking an object that belongs to our process or it's a
          * global object if HandleProcessId is 0 here.
          */

         /* FIXME: Check the upper 16-bits of handle number! */
         if (HandleType != 0 && HandleEntry->KernelData != NULL &&
             (ObjectType == GDI_OBJECT_TYPE_DONTCARE ||
              HandleType == ObjectType))
         {
            PGDIOBJHDR GdiHdr = GDIBdyToHdr(HandleEntry->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 = HandleEntry->KernelData;
            }
            else
            {
               InterlockedIncrement((PLONG)&GdiHdr->Locks);
               if (GdiHdr->LockingThread != Thread)
               {
                  InterlockedDecrement((PLONG)&GdiHdr->Locks);

                  /* Unlock the handle table entry. */
                  (void)InterlockedExchangePointer(&HandleEntry->ProcessId, PrevProcId);

                  DelayExecution();
                  continue;
               }
               Object = HandleEntry->KernelData;
            }
         }
         else
         {
            /*
             * Debugging code. Report attempts to lock deleted handles and
             * locking type mismatches.
             */

            if ((HandleType & ~GDI_HANDLE_REUSE_MASK) == 0)
            {
               DPRINT1("Attempted to lock object 0x%x that is deleted!\n", hObj);
               KeRosDumpStackFrames(NULL, 20);
            }
            else
            {
               DPRINT1("Attempted to lock object 0x%x, type mismatch (0x%x : 0x%x)\n",
                  hObj, HandleType & ~GDI_HANDLE_REUSE_MASK, ObjectType & ~GDI_HANDLE_REUSE_MASK);

               KeRosDumpStackFrames(NULL, 20);
            }
#ifdef GDI_DEBUG
            DPRINT1("-> called from %s:%i\n", file, line);
#endif
         }

         /* Unlock the handle table entry. */
         (void)InterlockedExchangePointer(&HandleEntry->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 ObjectType parameter!
*/
PGDIOBJ INTERNAL_CALL
#ifdef GDI_DEBUG
GDIOBJ_ShareLockObjDbg (PGDI_HANDLE_TABLE HandleTable, const char* file, int line, HGDIOBJ hObj, DWORD ObjectType)
#else /* !GDI_DEBUG */
GDIOBJ_ShareLockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ObjectType)
#endif /* GDI_DEBUG */
{
   USHORT HandleIndex;
   PGDI_TABLE_ENTRY HandleEntry;
   HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
   PGDIOBJ Object = NULL;

   HandleIndex = GDI_HANDLE_GET_INDEX(hObj);

   /* Check that the handle index is valid. */
   if (HandleIndex >= GDI_HANDLE_COUNT)
      return NULL;

   HandleEntry = &HandleTable->Entries[HandleIndex];

   ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
   HandleProcessId = (HANDLE)((ULONG_PTR)HandleEntry->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(&HandleEntry->ProcessId, 
                                                     LockedProcessId,
                                                     HandleProcessId);

      if (PrevProcId == HandleProcessId)
      {
         LONG HandleType = HandleEntry->Type << 16;

         /*
          * We're locking an object that belongs to our process or it's a
          * global object if HandleProcessId is 0 here.
          */

         /* FIXME: Check the upper 16-bits of handle number! */
         if (HandleType != 0 && HandleEntry->KernelData != NULL &&
             (ObjectType == GDI_OBJECT_TYPE_DONTCARE ||
              HandleType == ObjectType))
         {
            PGDIOBJHDR GdiHdr = GDIBdyToHdr(HandleEntry->KernelData);

#ifdef GDI_DEBUG
            if (InterlockedIncrement((PLONG)&GdiHdr->Locks) == 1)
            {
               GdiHdr->lockfile = file;
               GdiHdr->lockline = line;
            }
#else
            InterlockedIncrement((PLONG)&GdiHdr->Locks);
#endif
            Object = HandleEntry->KernelData;
         }
         else
         {
            /*
             * Debugging code. Report attempts to lock deleted handles and
             * locking type mismatches.
             */

            if ((HandleType & ~GDI_HANDLE_REUSE_MASK) == 0)
            {
               DPRINT1("Attempted to lock object 0x%x that is deleted!\n", hObj);
               KeRosDumpStackFrames(NULL, 20);
            }
            else
            {
               DPRINT1("Attempted to lock object 0x%x, type mismatch (0x%x : 0x%x)\n",
                  hObj, HandleType & ~GDI_HANDLE_REUSE_MASK, ObjectType & ~GDI_HANDLE_REUSE_MASK);

               KeRosDumpStackFrames(NULL, 20);
            }
#ifdef GDI_DEBUG
            DPRINT1("-> called from %s:%i\n", file, line);
#endif
         }

         /* Unlock the handle table entry. */
         (void)InterlockedExchangePointer(&HandleEntry->ProcessId, PrevProcId);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -