C# - 捕获鼠标光标图像

2023-11-23

背景

  • 我正在编写一个屏幕捕获应用程序
  • 我的代码基于此项目:http://www.codeproject.com/KB/cs/DesktopCaptureWithMouse.aspx?display=Print
  • 请注意,代码还捕获了鼠标光标(这对我来说是理想的)

我的问题

  • 当鼠标光标是普通指针或手形图标时,代码可以正常工作 - 鼠标在屏幕截图上正确呈现
  • 但是,当鼠标光标更改为插入点(“工字形”光标)时 - 例如在记事本中键入 - 然后代码不起作用 - 结果是我得到了光标的微弱图像 - 就像一个它的非常半透明(灰色)版本,而不是预期的空白和白色版本。

我的问题

  • 当图像是这些“I-beam”类型图像之一时,如何捕获鼠标光标图像
  • 注意:如果您点击原始文章,有人会提供建议 - 它不起作用

SOURCE

这是来自原始文章。

    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;
    }

虽然我无法准确解释为什么会发生这种情况,但我想我可以展示如何解决它。

ICONINFO 结构包含两个成员 hbmMask 和 hbmColor,它们分别包含光标的掩码和颜色位图(请参阅 MSDN 页面了解ICONINFO获取官方文档)。

当您为默认光标调用 GetIconInfo() 时,ICONINFO 结构包含有效的掩码和颜色位图,如下所示(注意:已添加红色边框以清晰显示图像边界):

Default Cursor Mask Bitmap default cursor mask bitmap image

Default Cursor Color Bitmap default cursor color bitmap image

当Windows绘制默认光标时,首先对掩码位图应用AND光栅操作,然后对颜色位图应用XOR光栅操作。这会产生不透明的光标和透明的背景。

但是,当您为 I-Beam 光标调用 GetIconInfo() 时,ICONINFO 结构仅包含有效的掩码位图,而没有颜色位图,如下所示(注意:再次添加红色边框以清楚地显示图像边界):

I-Beam Cursor Mask Bitmap ibeam cursor mask bitmap image

根据 ICONINFO 文档,I-Beam 光标是单色光标。掩码位图的上半部分是 AND 掩码,掩码位图的下半部分是 XOR 位图。当 Windows 绘制 I-Beam 光标时,首先使用 AND 光栅操作在桌面上绘制该位图的上半部分。然后通过 XOR 光栅操作将位图的下半部分绘制在顶部。在屏幕上,光标将与其后面的内容相反地显示。

中的一个comments您链接的原始文章提到了这一点。在桌面上,由于光栅操作应用于桌面内容,因此光标将显示正确。但是,当图像没有背景绘制时(如您发布的代码中所示),Windows 执行的光栅操作会导致图像褪色。

也就是说,这个更新的 CaptureCursor() 方法将处理彩色和单色光标,当光标为单色时提供纯黑色光标图像。

static Bitmap CaptureCursor(ref int x, ref int y)
{
  Win32Stuff.CURSORINFO cursorInfo = new Win32Stuff.CURSORINFO();
  cursorInfo.cbSize = Marshal.SizeOf(cursorInfo);
  if (!Win32Stuff.GetCursorInfo(out cursorInfo))
    return null;

  if (cursorInfo.flags != Win32Stuff.CURSOR_SHOWING)
    return null;

  IntPtr hicon = Win32Stuff.CopyIcon(cursorInfo.hCursor);
  if (hicon == IntPtr.Zero)
    return null;

  Win32Stuff.ICONINFO iconInfo;
  if (!Win32Stuff.GetIconInfo(hicon, out iconInfo))
    return null;

  x = cursorInfo.ptScreenPos.x - ((int)iconInfo.xHotspot);
  y = cursorInfo.ptScreenPos.y - ((int)iconInfo.yHotspot);

  using (Bitmap maskBitmap = Bitmap.FromHbitmap(iconInfo.hbmMask))
  {
    // Is this a monochrome cursor?
    if (maskBitmap.Height == maskBitmap.Width * 2)
    {
      Bitmap resultBitmap = new Bitmap(maskBitmap.Width, maskBitmap.Width);

      Graphics desktopGraphics = Graphics.FromHwnd(Win32Stuff.GetDesktopWindow());
      IntPtr desktopHdc = desktopGraphics.GetHdc();

      IntPtr maskHdc = Win32Stuff.CreateCompatibleDC(desktopHdc);
      IntPtr oldPtr = Win32Stuff.SelectObject(maskHdc, maskBitmap.GetHbitmap());

      using (Graphics resultGraphics = Graphics.FromImage(resultBitmap))
      {
        IntPtr resultHdc = resultGraphics.GetHdc();

        // These two operation will result in a black cursor over a white background.
        // Later in the code, a call to MakeTransparent() will get rid of the white background.
        Win32Stuff.BitBlt(resultHdc, 0, 0, 32, 32, maskHdc, 0, 32, Win32Stuff.TernaryRasterOperations.SRCCOPY);
        Win32Stuff.BitBlt(resultHdc, 0, 0, 32, 32, maskHdc, 0, 0, Win32Stuff.TernaryRasterOperations.SRCINVERT);

        resultGraphics.ReleaseHdc(resultHdc);
      }

      IntPtr newPtr = Win32Stuff.SelectObject(maskHdc, oldPtr);
      Win32Stuff.DeleteObject(newPtr);
      Win32Stuff.DeleteDC(maskHdc);
      desktopGraphics.ReleaseHdc(desktopHdc);

      // Remove the white background from the BitBlt calls,
      // resulting in a black cursor over a transparent background.
      resultBitmap.MakeTransparent(Color.White);
      return resultBitmap;
    }
  }

  Icon icon = Icon.FromHandle(hicon);
  return icon.ToBitmap();
}

代码中存在一些问题,这些问题可能是问题,也可能不是问题。

  1. 对单色光标的检查只是测试高度是否是宽度的两倍。虽然这看起来合乎逻辑,但 ICONINFO 文档并不强制要求仅由此定义单色光标。
  2. 可能有一种更好的方法来呈现光标,即我使用的 BitBlt() - BitBlt() - MakeTransparent() 方法调用组合。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# - 捕获鼠标光标图像 的相关文章

随机推荐

  • 如何使用 jQuery.Ajax 访问 400 错误的 JSON 响应?

    在 jQuery 中 我将表单提交到服务器 当出现验证错误时 我会从服务器收到 400 错误 并且文档正文是有效的 JSON 我想知道如何访问从服务器返回的数据 我的 jQuery Ajax 对象上的 error 回调函数从未被调用 因此我
  • 使用 Android 应用程序更改网络运营商

    我正在尝试开发一个Android应用程序 它可以在地图上显示各个网络运营商的信号强度 问题是改变网络运营商的唯一方法是手动操作 关于如何在不手动更改的情况下获取此信息的任何想法 我认为有内部 私有 Android 类可以做到这一点 您将需要
  • Laravel 中的多线程

    我遇到了一个问题 我的数据库调用显着减慢了页面加载速度 我正在从选举数据填充多个图表 我的表包含大约 100 万行 我必须在每个方法中多次查询这些数据getCharts method I am 使用这个将返回数据传递给 JavaScript
  • Log4J2 AppenderLoggingException NoSuchMethodError StackLocatorUtil.getCurrentStackTrace()

    一旦发生异常 错误并且应该被记录 我就会收到以下错误 堆栈跟踪 org apache logging log4j core appender AppenderLoggingException java lang NoSuchMethodEr
  • iPhone 应用程序中的密码加密

    我需要将用户的密码存储在我的 iPhone 应用程序中 当将应用程序发布到应用程序商店时 我必须告诉Apple该应用程序中是否有出于导出目的的加密 我不希望我的应用程序仅限于美国 但我也不希望以明文形式通过网络存储或发送密码 所以基本上问题
  • v6 中可选参数的替代方法

    在 v5 中 我们可以添加尾随 路由可选参数 但与 v6 一样 对相同参数的支持已被删除 那么编写以下代码的替代方法是什么
  • 如何使用Log4Net实现日志文件自动归档

    我想以这样的方式配置 log4net 以便自动归档前一天的所有日志 是否有可能在 Log4Net 中自动存档以前的日志 我只想使用配置来执行此操作 而不使用任何第三方库 如 Sharplibzip 编写任何代码来创建存档 通过归档还要添加一
  • C# 正确格式化(缩进、对齐)C#

    我们有一个代码生成器munges给定数据库的模式 用于自动化我们内部的 n 层架构 输出是各种 C 部分类 每个文件一个 在处理所有字符串的代码中 我们尝试尽可能地控制缩进和格式 但当您在 Visual Studio 中打开文件时 格式总是
  • 逐行读取文件并分割值

    我需要读取一个txt文件 其组成如下 AA 1000 AA 320009 999999 AA 1011 AA 320303 111111 对于每个读取的行 我需要用 将其分割以到达第一回合 test 0 AA 1000 AA 320009
  • 调用 savechanges 时实体框架复制

    我首先使用entityframework 5代码 我有一个这样的模型 class Product public Product Fabrics new BindingList
  • 如何在Spring 3.0应用程序中配置Hibernate统计信息?

    我们如何配置以便在基于 Spring MVC 的 Web 应用程序中通过 JMX 获取 Hibernate 统计信息 有没有更好的方法来跟踪 Hibernate 性能 Set hibernate generate statistics to
  • Cakephp 2.0 使用电子邮件而不是用户名进行身份验证

    在我看来我有 在我的应用程序控制器中 public components array
  • ZF2中同一模块下的多个命名空间

    我在同一模块下配置多个命名空间 类时遇到问题 例如 我有一个名为 Account 的模块 其中我想包含所有与帐户相关的类 公司 accounts 用户 users 外部 api api 等 模块结构看起来像这样 Account Module
  • Base64 图像不显示在 RDLC 报告的渲染 PDF 上

    我正在尝试使用参数 CustomerSign 在 RDLC 报告中 我正在从报告中渲染 PDF 文件 并且看到 PDF 文件 我已配置图像属性如下 选择图像源 Database 使用该字段 Convert FromBase64String
  • 为什么 Objects.hash() 对于相同的输入返回不同的值?

    我运行了以下脚本 java 它给了我奇怪的结果 有谁可以帮忙解释一下吗 import java util Objects import org apache log4j Logger public class CacheTester pri
  • -D MACRO 和 #define MACRO 的优先级

    如果我有一个C文件 foo c 虽然我已经给出了 DMACRO 1作为编译的命令行选项 但是 如果在头文件中我也有 define MACRO 2 其中哪一个会优先 我正在假设您正在做什么 但是如果您想从命令行为该宏提供非默认值 请尝试对宏定
  • 多线程访问文件

    我们有一个多线程java程序 多个线程将写入一个文件 一个线程将从该文件中读取 我正在寻找一些设计想法 是否需要同步 文件通道理论上是线程安全的 来自javadoc 文件通道可供多个并发线程安全使用 这 close 方法可以随时调用 具体由
  • 读取套接字时Java中断线程[重复]

    这个问题在这里已经有答案了 可能的重复 如何立即终止阻塞在套接字IO操作上的线程 我有一个客户端在线程中运行 想要从 Java 中的套接字读取数据 但在阅读时 也许我想杀死线程 所以我interrupt它 但是套接字的读取方法会抛出异常吗I
  • 如何在 jQuery 中循环遍历数组?

    我正在尝试循环遍历一个数组 我有以下代码 var currnt image list 21 32 234 223 var substr currnt image list split array here 我正在尝试从数组中获取所有数据 有
  • C# - 捕获鼠标光标图像

    背景 我正在编写一个屏幕捕获应用程序 我的代码基于此项目 http www codeproject com KB cs DesktopCaptureWithMouse aspx display Print 请注意 代码还捕获了鼠标光标 这对