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

📄 gdiobj.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
   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 + -