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

📄 cursoricon.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 *  ReactOS W32 Subsystem
 *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * We handle two types of cursors/icons:
 * - Private
 *   Loaded without LR_SHARED flag
 *   Private to a process
 *   Can be deleted by calling NtDestroyCursorIcon()
 *   CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
 * - Shared
 *   Loaded with LR_SHARED flag
 *   Possibly shared by multiple processes
 *   Immune to NtDestroyCursorIcon()
 *   CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
 * There's a M:N relationship between processes and (shared) cursor/icons.
 * A process can have multiple cursor/icons and a cursor/icon can be used
 * by multiple processes. To keep track of this we keep a list of all
 * cursor/icons (CurIconList) and per cursor/icon we keep a list of
 * CURICON_PROCESS structs starting at CurIcon->ProcessList.
 */

#include <w32k.h>

#define NDEBUG
#include <debug.h>

static PAGED_LOOKASIDE_LIST gProcessLookasideList;
static LIST_ENTRY gCurIconList;

/* Look up the location of the cursor in the GDIDEVICE structure
 * when all we know is the window station object
 * Actually doesn't use the window station, but should... */
BOOL FASTCALL
IntGetCursorLocation(PWINSTATION_OBJECT WinSta, POINT *loc)
{
   HDC hDC;
   PDC dc;
   GDIDEVICE *GDIDevice;

#if 1
   /* FIXME - get the screen dc from the window station or desktop */
   if (!(hDC = IntGetScreenDC()))
      return FALSE;
#endif

   if (!(dc = DC_LockDc(hDC)))
      return FALSE;
   GDIDevice = (GDIDEVICE *)dc->GDIDevice;
   DC_UnlockDc(dc);

   loc->x = GDIDevice->Pointer.Pos.x;
   loc->y = GDIDevice->Pointer.Pos.y;

   return TRUE;
}


PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
{
   PCURICON_OBJECT CurIcon;
   
   if (!hCurIcon)
   {
      SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
      return NULL;
   }
   
   CurIcon = (PCURICON_OBJECT)UserGetObject(gHandleTable, hCurIcon, otCursorIcon);
   if (!CurIcon)
   {
      /* we never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
      SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
      return NULL;
   }

   ASSERT(USER_BODY_TO_HEADER(CurIcon)->RefCount >= 0);
   return CurIcon;
}


#define COLORCURSORS_ALLOWED FALSE
HCURSOR FASTCALL
IntSetCursor(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT NewCursor,
             BOOL ForceChange)
{
   BITMAPOBJ *BitmapObj;
   SURFOBJ *SurfObj;
   PDEVINFO DevInfo;
   PBITMAPOBJ MaskBmpObj = NULL;
   PSYSTEM_CURSORINFO CurInfo;
   PCURICON_OBJECT OldCursor;
   HCURSOR Ret = (HCURSOR)0;
   HBITMAP dcbmp, hColor = (HBITMAP)0;
   HBITMAP hMask = 0;
   SURFOBJ *soMask = NULL, *soColor = NULL;
   XLATEOBJ *XlateObj = NULL;
   HDC Screen;
   PDC dc;

   CurInfo = IntGetSysCursorInfo(WinSta);
   OldCursor = CurInfo->CurrentCursorObject;
   if (OldCursor)
   {
      Ret = (HCURSOR)OldCursor->Self;
   }

   if (!ForceChange && OldCursor == NewCursor)
   {
      return Ret;
   }
   else
   {
      if(!(Screen = IntGetScreenDC()))
      {
         return (HCURSOR)0;
      }
      /* FIXME use the desktop's HDC instead of using ScreenDeviceContext */
      dc = DC_LockDc(Screen);

      if (!dc)
      {
         return Ret;
      }
      dcbmp = dc->w.hBitmap;
      DevInfo = dc->DevInfo;
      DC_UnlockDc(dc);

      BitmapObj = BITMAPOBJ_LockBitmap(dcbmp);
      if ( !BitmapObj )
         return (HCURSOR)0;
      SurfObj = &BitmapObj->SurfObj;
      ASSERT(SurfObj);
   }

   if (!NewCursor && (CurInfo->CurrentCursorObject || ForceChange))
   {
      if (NULL != CurInfo->CurrentCursorObject && CurInfo->ShowingCursor)
      {
         /* Remove the cursor if it was displayed */
         IntEngMovePointer(SurfObj, -1, -1, &GDIDEV(SurfObj)->Pointer.Exclude);
      }

      GDIDEV(SurfObj)->Pointer.Status = SPS_ACCEPT_NOEXCLUDE;

      CurInfo->CurrentCursorObject = NewCursor; /* i.e. CurrentCursorObject = NULL */
      CurInfo->ShowingCursor = 0;
      BITMAPOBJ_UnlockBitmap(BitmapObj);
      return Ret;
   }

   if (!NewCursor)
   {
      BITMAPOBJ_UnlockBitmap(BitmapObj);
      return Ret;
   }

   /* TODO: Fixme. Logic is screwed above */

   ASSERT(NewCursor);
   MaskBmpObj = BITMAPOBJ_LockBitmap(NewCursor->IconInfo.hbmMask);
   if (MaskBmpObj)
   {
      const int maskBpp = BitsPerFormat(MaskBmpObj->SurfObj.iBitmapFormat);
      BITMAPOBJ_UnlockBitmap(MaskBmpObj);
      if (maskBpp != 1)
      {
         DPRINT1("SetCursor: The Mask bitmap must have 1BPP!\n");
         BITMAPOBJ_UnlockBitmap(BitmapObj);
         return Ret;
      }

      if ((DevInfo->flGraphicsCaps2 & GCAPS2_ALPHACURSOR) &&
            SurfObj->iBitmapFormat >= BMF_16BPP &&
            SurfObj->iBitmapFormat <= BMF_32BPP &&
            NewCursor->Shadow && COLORCURSORS_ALLOWED)
      {
         /* FIXME - Create a color pointer, only 32bit bitmap, set alpha bits!
                    Do not pass a mask bitmap to DrvSetPointerShape()!
                    Create a XLATEOBJ that describes the colors of the bitmap. */
         DPRINT1("SetCursor: (Colored) alpha cursors are not supported!\n");
      }
      else
      {
         if(NewCursor->IconInfo.hbmColor
               && COLORCURSORS_ALLOWED)
         {
            /* FIXME - Create a color pointer, create only one 32bit bitmap!
                       Do not pass a mask bitmap to DrvSetPointerShape()!
                       Create a XLATEOBJ that describes the colors of the bitmap.
                       (16bit bitmaps are propably allowed) */
            DPRINT1("SetCursor: Cursors with colors are not supported!\n");
         }
         else
         {
            MaskBmpObj = BITMAPOBJ_LockBitmap(NewCursor->IconInfo.hbmMask);
            if(MaskBmpObj)
            {
               RECTL DestRect = {0, 0, MaskBmpObj->SurfObj.sizlBitmap.cx, MaskBmpObj->SurfObj.sizlBitmap.cy};
               POINTL SourcePoint = {0, 0};

               /*
                * NOTE: For now we create the cursor in top-down bitmap,
                * because VMware driver rejects it otherwise. This should
                * be fixed later.
                */
               hMask = EngCreateBitmap(
                          MaskBmpObj->SurfObj.sizlBitmap, abs(MaskBmpObj->SurfObj.lDelta),
                          MaskBmpObj->SurfObj.iBitmapFormat, BMF_TOPDOWN,
                          NULL);
               if ( !hMask )
               {
                  BITMAPOBJ_UnlockBitmap(MaskBmpObj);
                  BITMAPOBJ_UnlockBitmap(BitmapObj);
                  return (HCURSOR)0;
               }
               soMask = EngLockSurface((HSURF)hMask);
               EngCopyBits(soMask, &MaskBmpObj->SurfObj, NULL, NULL,
                           &DestRect, &SourcePoint);
               BITMAPOBJ_UnlockBitmap(MaskBmpObj);
            }
         }
      }
      CurInfo->ShowingCursor = CURSOR_SHOWING;
      CurInfo->CurrentCursorObject = NewCursor;
   }
   else
   {
      CurInfo->ShowingCursor = 0;
      CurInfo->CurrentCursorObject = NULL;
   }

   if (GDIDEVFUNCS(SurfObj).SetPointerShape)
   {
      GDIDEV(SurfObj)->Pointer.Status =
         GDIDEVFUNCS(SurfObj).SetPointerShape(
            SurfObj, soMask, soColor, XlateObj,
            NewCursor->IconInfo.xHotspot,
            NewCursor->IconInfo.yHotspot,
            GDIDEV(SurfObj)->Pointer.Pos.x,
            GDIDEV(SurfObj)->Pointer.Pos.y,
            &(GDIDEV(SurfObj)->Pointer.Exclude),
            SPS_CHANGE);
      DPRINT("SetCursor: DrvSetPointerShape() returned %x\n",
             GDIDEV(SurfObj)->Pointer.Status);
   }
   else
   {
      GDIDEV(SurfObj)->Pointer.Status = SPS_DECLINE;
   }

   if(GDIDEV(SurfObj)->Pointer.Status == SPS_DECLINE)
   {
      GDIDEV(SurfObj)->Pointer.Status = EngSetPointerShape(
                                           SurfObj, soMask, soColor, XlateObj,
                                           NewCursor->IconInfo.xHotspot,
                                           NewCursor->IconInfo.yHotspot,
                                           GDIDEV(SurfObj)->Pointer.Pos.x,
                                           GDIDEV(SurfObj)->Pointer.Pos.y,
                                           &(GDIDEV(SurfObj)->Pointer.Exclude),
                                           SPS_CHANGE);
      GDIDEV(SurfObj)->Pointer.MovePointer = NULL;
   }
   else
   {
      GDIDEV(SurfObj)->Pointer.MovePointer = GDIDEVFUNCS(SurfObj).MovePointer;
   }

   BITMAPOBJ_UnlockBitmap(BitmapObj);
   if(hMask)
   {
      EngUnlockSurface(soMask);
      EngDeleteSurface((HSURF)hMask);
   }
   if(hColor)
   {
      EngDeleteSurface((HSURF)hColor);
   }
   if(XlateObj)
   {
      EngDeleteXlate(XlateObj);
   }

   if(GDIDEV(SurfObj)->Pointer.Status == SPS_ERROR)
      DPRINT1("SetCursor: DrvSetPointerShape() returned SPS_ERROR\n");

   return Ret;
}

BOOL FASTCALL
IntSetupCurIconHandles(PWINSTATION_OBJECT WinSta)
{
   ExInitializePagedLookasideList(&gProcessLookasideList,
                                  NULL,
                                  NULL,
                                  0,
                                  sizeof(CURICON_PROCESS),
                                  0,
                                  128);
   InitializeListHead(&gCurIconList);

   return TRUE;
}

/*
 * We have to register that this object is in use by the current
 * process. The only way to do that seems to be to walk the list
 * of cursor/icon objects starting at W32Process->CursorIconListHead.
 * If the object is already present in the list, we don't have to do
 * anything, if it's not present we add it and inc the ProcessCount
 * in the object. Having to walk the list kind of sucks, but that's
 * life...
 */
static BOOLEAN FASTCALL
ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
{
   PW32PROCESS Win32Process;
   PCURICON_PROCESS Current;

   Win32Process = PsGetCurrentProcessWin32Process();

   LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
   {
      if (Current->Process == Win32Process)
      {
         /* Already registered for this process */
         return TRUE;
      }
   }

   /* Not registered yet */
   Current = ExAllocateFromPagedLookasideList(&gProcessLookasideList);
   if (NULL == Current)
   {
      return FALSE;
   }
   InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
   Current->Process = Win32Process;

   return TRUE;
}

PCURICON_OBJECT FASTCALL
IntFindExistingCurIconObject(PWINSTATION_OBJECT WinSta, HMODULE hModule,
                             HRSRC hRsrc, LONG cx, LONG cy)
{
   PCURICON_OBJECT CurIcon;

   LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
   {

      //    if(NT_SUCCESS(ObmReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
//      ObmReferenceObject(  CurIcon);
//      {
      if((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
      {
         if(cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
         {
//               ObmDereferenceObject(CurIcon);
            continue;
         }
         if (! ReferenceCurIconByProcess(CurIcon))
         {
            return NULL;
         }

         return CurIcon;
      }
//      }
//      ObmDereferenceObject(CurIcon);

   }

   return NULL;
}

PCURICON_OBJECT FASTCALL
IntCreateCurIconHandle(PWINSTATION_OBJECT WinSta)
{
   PCURICON_OBJECT CurIcon;
   HANDLE hCurIcon;

   CurIcon = ObmCreateObject(gHandleTable, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));

   if(!CurIcon)
   {
      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
      return FALSE;
   }

   CurIcon->Self = hCurIcon;
   InitializeListHead(&CurIcon->ProcessList);

   if (! ReferenceCurIconByProcess(CurIcon))
   {
      DPRINT1("Failed to add process\n");
      ObmDeleteObject(hCurIcon, otCursorIcon);
      ObmDereferenceObject(CurIcon);
      return NULL;
   }

   InsertHeadList(&gCurIconList, &CurIcon->ListEntry);

   ObmDereferenceObject(CurIcon);

   return CurIcon;
}

BOOLEAN FASTCALL
IntDestroyCurIconObject(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT CurIcon, BOOL ProcessCleanup)
{
   PSYSTEM_CURSORINFO CurInfo;
   HBITMAP bmpMask, bmpColor;
   BOOLEAN Ret;
   PCURICON_PROCESS Current = NULL;
   PW32PROCESS W32Process = PsGetCurrentProcessWin32Process();

   /* Private objects can only be destroyed by their own process */
   if (NULL == CurIcon->hModule)
   {
      ASSERT(CurIcon->ProcessList.Flink->Flink == &CurIcon->ProcessList);
      Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
      if (Current->Process != W32Process)
      {
         DPRINT1("Trying to destroy private icon/cursor of another process\n");
         return FALSE;
      }
   }
   else if (! ProcessCleanup)
   {
      DPRINT("Trying to destroy shared icon/cursor\n");
      return FALSE;
   }

   /* Now find this process in the list of processes referencing this object and
      remove it from that list */
   LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
   {
      if (Current->Process == W32Process)
      {
         RemoveEntryList(&Current->ListEntry);
         break;
      }
   }
   
   ExFreeToPagedLookasideList(&gProcessLookasideList, Current);

   /* If there are still processes referencing this object we can't destroy it yet */
   if (! IsListEmpty(&CurIcon->ProcessList))
   {
      return TRUE;
   }


   if (! ProcessCleanup)
   {
      RemoveEntryList(&CurIcon->ListEntry);
   }

   CurInfo = IntGetSysCursorInfo(WinSta);

   if (CurInfo->CurrentCursorObject == CurIcon)
   {
      /* Hide the cursor if we're destroying the current cursor */
      IntSetCursor(WinSta, NULL, TRUE);
   }

   bmpMask = CurIcon->IconInfo.hbmMask;
   bmpColor = CurIcon->IconInfo.hbmColor;

   Ret = ObmDeleteObject(CurIcon->Self, otCursorIcon);

   /* delete bitmaps */
   if(bmpMask)
   {
      GDIOBJ_SetOwnership(GdiHandleTable, bmpMask, PsGetCurrentProcess());
      NtGdiDeleteObject(bmpMask);
   }
   if(bmpColor)
   {
      GDIOBJ_SetOwnership(GdiHandleTable, bmpColor, PsGetCurrentProcess());
      NtGdiDeleteObject(bmpColor);
   }

   return Ret;
}

VOID FASTCALL
IntCleanupCurIcons(struct _EPROCESS *Process, PW32PROCESS Win32Process)
{
   PWINSTATION_OBJECT WinSta;
   PCURICON_OBJECT CurIcon, tmp;
   PCURICON_PROCESS ProcessData;

   WinSta = IntGetWinStaObj();
   if(WinSta == NULL)
   {
      return;
   }

   LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
   {
//      ObmReferenceObject(CurIcon);
      //    if(NT_SUCCESS(ObmReferenceObjectByPointer(Object, otCursorIcon)))
      {
         LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
         {
            if (Win32Process == ProcessData->Process)
            {
               RemoveEntryList(&CurIcon->ListEntry);
               IntDestroyCurIconObject(WinSta, CurIcon, TRUE);
               break;
            }
         }

//         ObmDereferenceObject(Object);
      }


   }

   ObDereferenceObject(WinSta);
}

/*
 * @implemented
 */
HANDLE
STDCALL
NtUserCreateCursorIconHandle(PICONINFO IconInfo OPTIONAL, BOOL Indirect)
{
   PCURICON_OBJECT CurIcon;
   PWINSTATION_OBJECT WinSta;
   PBITMAPOBJ bmp;
   NTSTATUS Status;
   HANDLE Ret;
   DECLARE_RETURN(HANDLE);

   DPRINT("Enter NtUserCreateCursorIconHandle\n");
   UserEnterExclusive();

⌨️ 快捷键说明

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