65.9K
CodeProject 正在变化。 阅读更多。
Home

捕获带有鼠标指针图像的桌面屏幕

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.58/5 (33投票s)

2006年1月27日

3分钟阅读

viewsIcon

303285

downloadIcon

16919

本文展示了如何捕获包含鼠标光标的桌面屏幕截图。

Sample Image - DesktopCaptureWithMouse.jpg

引言

本文展示了如何捕获包含鼠标光标的屏幕图像。

背景

屏幕捕获是一种非常有用的资源共享方式,例如远程桌面、虚拟网络计算 (VNC) 等应用程序,用户可以像使用自己的桌面一样访问、查看和交互远程桌面。此外,它还用于一些不道德的应用,例如黑客应用程序,黑客可以使用一些恶意服务器应用程序入侵计算机,然后服务器会频繁地截取受害者机器的屏幕截图并将其发送给客户端。您会在互联网上看到很多源代码资源讨论如何截取桌面或桌面某个区域的屏幕截图,但它们都没有讨论如何将鼠标光标位图与屏幕截图一起捕获。有时,必须捕获鼠标才能看到被黑机器的全部活动。首先,我们将在此讨论实际问题是什么。

问题

我们大多数人认为鼠标光标图像是桌面显示的一部分,但实际上它在桌面上的一个上层工作。Windows 始终使用“热点”跟踪鼠标,这是 Windows 看到的实际位置。

目前,有两种常见的方法来捕获和操作桌面图像

  1. 将桌面位图数据从视频内存复制到系统内存。进行处理,然后再次将其位图传送回视频内存。这可以使用 Win32 提供的 BitBlt()StretchBlt() API 轻松完成。
  2. 另一种方法是直接在视频内存中操作桌面位图(如果DirectDraw提供足够的内存)。

这两种方法都不能让我们捕获包含鼠标光标图像的桌面图像。

解决方案

捕获包含鼠标光标图像的桌面图像的问题的解决方案非常简单。

  1. 首先,使用 BitBlt() 获取屏幕的位图。我提供了 CaptureScreen.cs 文件中的一个名为 CaptureDesktop() 的简单函数,该函数捕获屏幕位图,几乎所有互联网上的代码都是这样做的。
  2. 然后捕获鼠标光标位图,如下所示:

    获取光标图标

    首先,使用 Win32 GetCursorInfo() 获取光标信息。该函数填充作为参数提供的 CURSORINFO 结构。在将其作为参数传递之前,不要忘记初始化该结构的 cbSize 成员。然后,通过检查已填充结构的 flags 成员是否与 CURSOR_SHOWING 常量相等,来检查光标是否可见。如果它们相等,那么我们使用 CopyIcon() 函数获取光标图标的句柄,该函数接受上述已填充结构的 hCursor 成员。

    获取光标位置

    现在,我们必须获取图标信息,以便我们可以获取热点位置。此信息可以使用 GetIconInfo() 函数轻松检索。这是鼠标捕获功能的 C# 实现

    static Bitmap CaptureCursor(ref int x, ref int y)
    {
       Bitmap bmp;
       IntPtr hicon;
       Win32Stuff.CURSORINFO ci = new Win32Stuff.CURSORINFO(); 
       Win32Stuff.ICONINFO icInfo;
       ci.cbSize = Marshal.SizeOf(ci);
       if(Win32Stuff.GetCursorInfo(out ci))
       {
           if (ci.flags == Win32Stuff.CURSOR_SHOWING)
           { 
               hicon = Win32Stuff.CopyIcon(ci.hCursor);
               if(Win32Stuff.GetIconInfo(hicon, out icInfo))
               {
                   x = ci.ptScreenPos.x - ((int)icInfo.xHotspot);
                   y = ci.ptScreenPos.y - ((int)icInfo.yHotspot);
                   Icon ic = Icon.FromHandle(hicon);
                   bmp = ic.ToBitmap(); 
    
                   return bmp;
               }
           }
       }
       return null;
    }
  3. 现在我们有了两个位图,即桌面位图和鼠标光标位图及其在屏幕上的位置。现在,是时候将鼠标光标位图放置在桌面位图上了。我提供了以下函数,该函数将鼠标光标图像覆盖到正确位置的桌面位图上
    public static Bitmap CaptureDesktopWithCursor()
    {     
       int cursorX = 0;
       int cursorY = 0;
       Bitmap desktopBMP;
       Bitmap cursorBMP;
       Bitmap finalBMP;
       Graphics g;
       Rectangle r;
       desktopBMP = CaptureDesktop();
       cursorBMP = CaptureCursor(ref cursorX, ref cursorY);
       if(desktopBMP != null)
       {
           if (cursorBMP != null)
           {
               r = new Rectangle(cursorX, cursorY, 
                       cursorBMP.Width, cursorBMP.Height);
               g = Graphics.FromImage(desktopBMP);
               g.DrawImage(cursorBMP, r);
               g.Flush();
               return desktopBMP;
           }
           else
               return desktopBMP;
       }
       return null;
    }
  4. 现在,包含光标的位图已准备好在查看器表面(此处使用 PictureBox)上呈现。由于查看器的可见区域小于桌面位图区域,因此在显示熟化桌面图像的函数中使用了缩放。
    // ssWithMouseViewer is the PictureBox control
    private void Display(Bitmap desktop)
    {
        Graphics g;
        Rectangle r;
        if(desktop != null)
        {
            r = new Rectangle(0,0,ssWithMouseViewer.Width, 
                                ssWithMouseViewer.Height);
            g = ssWithMouseViewer.CreateGraphics();
            g.DrawImage(desktop,r);
            g.Flush();
        }
    }

注意

提供的二进制图像使用 Visual Studio .NET 2005 编译,因此您必须安装 .NET Framework 2.0。

已知问题

我已经在我的机器上测试过该应用程序,没有发现已知问题,所以我希望在您的机器上也能得到相同的行为。

© . All rights reserved.