C#实现带光标的截图

1,目的:

  • 可通过热键实现带光标与不带光标两种模式的截图。

2,知识点:

  • 快捷键的注册与注销。
 [DllImport("user32.dll", SetLastError = true)]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, Keys vk);[DllImport("user32.dll", SetLastError = true)]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
  • 光标信息的获取,光标图标的复制。
[DllImport("user32.dll")]
public static extern IntPtr CopyIcon(IntPtr hIcon);
[DllImport("user32.dll", EntryPoint = "GetCursorInfo")]
public static extern bool GetCursorInfo(ref CURSORINFO cInfo);
[DllImport("user32.dll", EntryPoint = "GetIconInfo")]
public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO iInfo);
  • 对配置文件(ini文件)的读写。
[DllImport("kernel32")]
public static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
[DllImport("kernel32")]
public static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retval, int size, string filePath);
  • 系统消息的重写。(Message相关链接:Message类的Msg属性所关联的所有ID_msg=0x001a-CSDN博客)
protected override void WndProc(ref Message m)
{//WM_HOTKEY=0x0312,热键关联的消息IDconst int WM_HOTKEY = 0x0312;//按快捷键     switch (m.Msg){case WM_HOTKEY:switch (m.WParam.ToInt32()){case 81:    //按下的是Shift+F   string ss = "";CaptureImage(ref ss);break;}break;}base.WndProc(ref m);
}

3,效果展示:

  • 带图标效果:

  • 无图标效果

4代码:

public partial class Form1 : Form{public Form1(){InitializeComponent();}bool isCaptureIcon = false;string savePath;private void Form1_Load(object sender, EventArgs e){//判断是否存在配置文件如果不存在则创建,如果存在则读取string configPath = Path.GetFullPath("../../config.ini");if (File.Exists(configPath)){savePath = ReadFromINI(configPath, "Configuration", "Location");string str = ReadFromINI(configPath, "Configuration", "CaptureIcon");bool result;if (bool.TryParse(str, out result)){isCaptureIcon = result;}else{isCaptureIcon = false;}}else{File.Create(configPath);isCaptureIcon = false;}if (string.IsNullOrEmpty(savePath)){//获取当前启动位置的盘string startLocation = Application.StartupPath;string defaultLocation = Directory.GetDirectoryRoot(startLocation);savePath = defaultLocation;}textBox1.Text = savePath;checkBox1.Checked = isCaptureIcon;//进行热键注册APIHelper.RegisterHotKey(this.Handle, 81, KeyModifiers.Shift, Keys.C);}//设置截图存储路径private void btnOpenF_Click(object sender, EventArgs e){using (FolderBrowserDialog fbd = new FolderBrowserDialog()){if (fbd.ShowDialog() == DialogResult.OK){savePath = textBox1.Text = fbd.SelectedPath;}}}//保存配置private void btnSave_Click(object sender, EventArgs e){string iniPath = Path.GetFullPath("../../config.ini");if (!File.Exists(iniPath)){File.Create(iniPath);}WriteToINI(iniPath, "Configuration", "Location", textBox1.Text);WriteToINI(iniPath, "Configuration", "CaptureIcon", isCaptureIcon.ToString());MessageBox.Show("已保存", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);}private void checkBox1_CheckedChanged(object sender, EventArgs e){isCaptureIcon = checkBox1.Checked;}private void Form1_FormClosing(object sender, FormClosingEventArgs e){//热键注销APIHelper.UnregisterHotKey(this.Handle, 81);}//隐藏窗口private void btnHide_Click(object sender, EventArgs e){this.Hide();}private void btnCapture_Click(object sender, EventArgs e){string filePath = "";if (CaptureImage(ref filePath)){MessageBox.Show("已截图:" + filePath);}else{MessageBox.Show("截图失败");}}//双击图标显示窗口private void notifyIcon1_DoubleClick(object sender, EventArgs e){this.Show();this.WindowState = FormWindowState.Normal;this.Activate();}private void toolStripExit_Click(object sender, EventArgs e){APIHelper.UnregisterHotKey(this.Handle, 81);Application.Exit();}private void toolStripShow_Click(object sender, EventArgs e){this.Visible = true;}//对接收的消息进行重写protected override void WndProc(ref Message m){//WM_HOTKEY=0x0312,热键关联的消息IDconst int WM_HOTKEY = 0x0312;//按快捷键     switch (m.Msg){case WM_HOTKEY:switch (m.WParam.ToInt32()){case 81:    //按下的是Shift+F   string ss = "";CaptureImage(ref ss);break;}break;}base.WndProc(ref m);}bool CaptureImage(ref string filePath){Bitmap img;if (!isCaptureIcon){img = CaptureNoCursor();string imgDir = Path.Combine(savePath, "Image", "NoCursor");if (!Directory.Exists(imgDir)){Directory.CreateDirectory(imgDir);}string fileName = "IMG_" + DateTime.Now.ToString("HHmmss") + ".png";filePath = Path.Combine(imgDir, fileName);}else{img = CaptureCursor();string imgDir = Path.Combine(savePath, "Image", "Cursor");if (!Directory.Exists(imgDir)){Directory.CreateDirectory(imgDir);}string fileName = "IMG_" + DateTime.Now.ToString("HHmmss") + ".png";filePath = Path.Combine(imgDir, fileName);}if (img != null){img.Save(filePath, System.Drawing.Imaging.ImageFormat.Png);return true;}else{return false;}}/// <summary>/// 不含光标的截图/// </summary>/// <returns></returns>Bitmap CaptureNoCursor(){//获取屏幕尺寸int width = APIHelper.GetSystemMetrics(0);int height = APIHelper.GetSystemMetrics(1);//创建图片Bitmap img = new Bitmap(width, height);using (Graphics g = Graphics.FromImage(img)){g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(width, height));}return img;}/// <summary>/// 包含光标的截图/// </summary>/// <returns></returns>Bitmap CaptureCursor(){//获取光标信息CURSORINFO cursor = new CURSORINFO();cursor.cbSize = Marshal.SizeOf(cursor);if (APIHelper.GetCursorInfo(ref cursor)){//flags==1时光标处于显示中if (cursor.flags == 1){ICONINFO iconinfo;//复制光标IntPtr hwn = APIHelper.CopyIcon(cursor.hCursor);//获取光标信息if (APIHelper.GetIconInfo(hwn, out iconinfo)){Icon icon = Icon.FromHandle(hwn);Point iconScreenPoint = new Point(cursor.ptScreenPos.X - iconinfo.xHotspot, cursor.ptScreenPos.Y - iconinfo.yHotspot);//获取屏幕尺寸int width = Screen.PrimaryScreen.Bounds.Width;int height = Screen.PrimaryScreen.Bounds.Height;//创建图片Bitmap img = new Bitmap(width, height);using (Graphics g = Graphics.FromImage(img)){g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(width, height));g.DrawIcon(icon, iconScreenPoint.X, iconScreenPoint.Y);}return img;}}}return null;}public static string ReadFromINI(string filePath, string rootValue, string key, string defValue = ""){StringBuilder sb = new StringBuilder(1024);APIHelper.GetPrivateProfileString(rootValue, key, defValue, sb, 1024, filePath);return sb.ToString();}public static void WriteToINI(string filePath, string rootValue, string key, string newVal){APIHelper.WritePrivateProfileString(rootValue, key, newVal, filePath);}}/// <summary>/// 有关图标或光标的信息/// </summary>[StructLayout(LayoutKind.Sequential)]struct ICONINFO{/// <summary>/// 指定此结构是定义图标还是游标。 值为 TRUE 指定图标; FALSE 指定游标。/// </summary>public bool fIcon;/// <summary>/// 光标热点的 x 坐标。 如果此结构定义了图标,则热点始终位于图标的中心,并且忽略此成员。/// </summary>public Int32 xHotspot;/// <summary>/// 光标热点的 y 坐标。 如果此结构定义了图标,则热点始终位于图标的中心,并且忽略此成员。/// </summary>public Int32 yHotspot;/// <summary>/// 单色掩码 位图图标的句柄。/// </summary>public IntPtr hbmMask;/// <summary>/// 图标颜色 位图的句柄。/// </summary>public IntPtr hbmColor;}/// <summary>/// 全局游标信息/// </summary>[StructLayout(LayoutKind.Sequential)]struct CURSORINFO{/// <summary>/// 结构大小(以字节为单位)。 调用方必须将此设置为 sizeof(CURSORINFO)。/// </summary>public Int32 cbSize;/// <summary>/// 游标状态。 此参数的取值可为下列值之一:0:光标处于隐藏。1:光标处于显示。2:Windows 8:取消光标。 此标志指示系统未绘制光标,因为用户是通过触摸或笔而不是鼠标提供输入。/// </summary>public Int32 flags;/// <summary>/// 光标的句柄。/// </summary>public IntPtr hCursor;/// <summary>/// 接收光标的屏幕坐标的结构。/// </summary>public Point ptScreenPos;}[Flags()]public enum KeyModifiers{None = 0,Alt = 1,Ctrl = 2,Shift = 4,WindowsKey = 8}class APIHelper{/// <summary>/// 获取与windows环境有关的信息/// </summary>/// <param name="mVal">指定获取信息</param>/// <returns></returns>[DllImport("user32.dll")]public static extern int GetSystemMetrics(int mVal);/// <summary>/// 获取指定图标或者鼠标的一个副本/// </summary>/// <param name="hIcon">欲复制的图标或指针的句柄</param>/// <returns></returns>[DllImport("user32.dll")]public static extern IntPtr CopyIcon(IntPtr hIcon);[DllImport("user32.dll", EntryPoint = "GetCursorInfo")]public static extern bool GetCursorInfo(ref CURSORINFO cInfo);[DllImport("user32.dll", EntryPoint = "GetIconInfo")]public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO iInfo);[DllImport("kernel32")]public static extern long WritePrivateProfileString(string section, string key, string val, string filePath);[DllImport("kernel32")]public static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retval, int size, string filePath);/// <summary>/// 热键注册/// </summary>/// <param name="hWnd">要定义热键的窗口的句柄 </param>/// <param name="id">定义热键ID(不能与其它ID重复) </param>/// <param name="fsModifiers">标识热键是否在按Alt、Ctrl、Shift、Windows等键时才会生效 </param>/// <param name="vk">定义热键的内容 </param>/// <returns>如果函数执行成功,返回值不为0。如果函数执行失败,返回值为0。要得到扩展错误信息,调用GetLastError。</returns>[DllImport("user32.dll", SetLastError = true)]public static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, Keys vk);/// <summary>/// 热键注销/// </summary>/// <param name="hWnd">要取消热键的窗口的句柄  </param>/// <param name="id">要取消热键的ID </param>/// <returns></returns>[DllImport("user32.dll", SetLastError = true)]public static extern bool UnregisterHotKey(IntPtr hWnd, int id);/// <summary>/// 从INI文件中读取数据/// </summary>/// <param name="filePath">INI文件的全路径</param>/// <param name="rootValue">根节点值,例如根节点[ConnectString]的值为:ConnectString</param>/// <param name="key">根节点下的键</param>/// <param name="defValue">当标记值未设定或不存在时的默认值</param>/// <returns></returns>}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/653460.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法与数据结构】139、LeetCode单词拆分

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题可以看做一个动态规划问题。其中&#xff0c;字符串s是背包&#xff0c;而字典中的单词就是物品。…

Dubbo框架注册中心-Zookeeper搭建

Dubbo 是阿里巴巴公司开源的高性能、轻量级的Java RPC框架&#xff0c;致力于提供高性能。 Dubbo官网 本篇开始dubbo的第一篇&#xff0c;注册中心 ZooKeeper 环境搭建。 环境前置&#xff1a;由于Zookeeper是基于Java环境&#xff0c;必须安装有JDK。查看命令 java -version。…

服务端开发小记01——Tomcat

Tomcat Tomcat简介Tomcat在Linux下的安装Tomcat验证Tomcat常用命令&#xff08;Linux下&#xff09; Tomcat简介 Tomcat是一个Web容器&#xff0c;JavaEE程序可以在此运行。Tomcat是一个中间件&#xff0c;在B/S架构中&#xff0c;浏览器发出的http请求经过tpmcat中间件&#…

降压模块LM2596S的操作使用

一、技术参数 二、使用说明 1.引脚说明&#xff1a; IN输入正极 IN-输入负极 OUT输出正极 OUT-输出负极 2.输入电压范围&#xff1a;直流3.2V 至 46V (输入的电压必须比要输出的电压高1.5V以上。不能升压) 3.输出电压范围&#xff1a;直流 1.25V至 35V 电压连续可调&#…

SBDD的节点选择(Node selection)和树的扩展(Tree expansion)的操作是怎么进行的?

Node selection: 1&#xff09;选择规则&#xff1a; “focus atom”是从生成的原子中选出的&#xff0c;如果一个原子没有“capped”&#xff0c;那么它就可以被选为“focus atom”。 一个原子被“capped”是因为它的化合价约束&#xff08;valency constraint&#xff09;…

内网安全:NTLM-Relay

目录 NTLM认证过程以及攻击面 NTLM Relay攻击 NTLM攻击总结 实验环境说明 域横向移动&#xff1a;NTLM中继攻击 攻击条件 实战一&#xff1a;NTLM中继攻击-CS转发上线MSF 原理示意图 一. CS代理转发 二. MSF架设路由 三. 适用smb_relay模块进行中继攻击 域横向移动…

【李宏毅机器学习】Transformer 内容补充

视频来源&#xff1a;10.【李宏毅机器学习2021】自注意力机制 (Self-attention) (上)_哔哩哔哩_bilibili 发现一个奇怪的地方&#xff0c;如果直接看ML/DL的课程的话&#xff0c;有很多都是不完整的。开始思考是不是要科学上网。 本文用作Transformer - Attention is all you…

ASP.NET Core基础之用扩展方法封装服务配置

阅读本文你的收获 了解C#中的扩展方法机制学会在ASP.NET Core 中&#xff0c;用扩展方法封装服务配置&#xff0c;使得代码更加简洁 一、什么是扩展方法 扩展方法使能够向现有类型添加方法&#xff0c;而无需创建新的派生类型、重新编译或以其他方式修改原始类型。 扩展方法…

Python笔记12-多线程、网络编程、正则表达式

文章目录 多线程网络编程正则表达式 多线程 现代操作系统比如Mac OS X&#xff0c;UNIX&#xff0c;Linux&#xff0c;Windows等&#xff0c;都是支持“多任务”的操作系统。 进程&#xff1a; 就是一个程序&#xff0c;运行在系统之上&#xff0c;那么便称之这个程序为一个运…

CTF CRYPTO 密码学-7

题目名称&#xff1a;敲击 题目描述&#xff1a; 让我们回到最开始的地方 0110011001101100011000010110011101111011011000110110010100110011011001010011010100110000001100100110001100101101001101000011100001100011001110010010110100110100011001000011010100110000…

微搭低代码从入门到精通01应用介绍

目录 1 学习路线图2 应用介绍3 编辑器介绍总结 低代码的概念于2014年由 Forrester 首次正式提出。其将低代码定义为&#xff1a;能够以“最少的手写代码”和设置快速开发应用、配置和部署业务应用程序。 不同应用厂商的解法不一样&#xff0c;Gartner评估了400多款低代码/无代码…

Spark Exchange节点和Partitioning

​Exchange 在explain时&#xff0c;常看到Exchange节点&#xff0c;这个节点其实就是发生了数据交换 此图片来自于网络截取 BroadcastExchangeExec 主要是用来广播的 ShuffleExchangeExec 里面决定了数据分布的方式和采用哪种shuffle 在这里可以看到好几种不同的分区器 shuf…

Android 13.0 SystemUI下拉状态栏定制二 锁屏页面横竖屏时钟都居中功能实现二

1.前言 在13.0的系统rom定制化开发中,在关于systemui的锁屏页面功能定制中,由于在平板横屏锁屏功能中,时钟显示的很大,并且是在左旁边居中显示的, 由于需要和竖屏显示一样,所以就需要用到小时钟显示,然后同样需要居中,所以就来分析下相关的源码,来实现具体的功能 如图…

Spring 事务原理二

该说些什么呢&#xff1f;一连几天&#xff0c;我都沉溺在孤芳自赏的思维中无法自拔。不知道自己为什么会有这种令人不齿的表现&#xff0c;更不知道这颗定时炸弹何时会将人炸的粉身碎骨。好在儒派宗师曾老夫子“吾日三省吾身”的名言警醒了我。遂潜心自省&#xff0c;溯源头以…

条件变量、线程池以及线程的GDB调试学习笔记

目录 一、条件变量 二、线程池概念和实现 三、线程的GDB调试 一、条件变量 应用场景&#xff1a;生产者消费者问题&#xff0c;是线程同步的一种手段。 必要性&#xff1a;为了实现等待某个资源&#xff0c;让线程休眠&#xff0c;提高运行效率 使用步骤&#xff1a; 初始…

深入理解C语言(3):自定义类型详解

文章主题&#xff1a;结构体类型详解&#x1f30f;所属专栏&#xff1a;深入理解C语言&#x1f4d4;作者简介&#xff1a;更新有关深入理解C语言知识的博主一枚&#xff0c;记录分享自己对C语言的深入解读。&#x1f606;个人主页&#xff1a;[₽]的个人主页&#x1f3c4;&…

前端使用阿里Oss

前言&#xff1a;有时候为了减少宽带和服务器压力等等&#xff0c;就直接给前端操作oss实习文件上传了官方文档 安装 npm i ali-oss 因为我们是js可以使用node jdkconst OSS require(ali-oss);// 初始化OSS客户端。请将以下参数替换为您自己的配置信息。 const client new O…

Rust循环和函数

下面聊聊以下主题&#xff1a; 基于条件的分支循环函数属性测试 基于条件的分支 基于条件的分支&#xff0c;可以通过常见的 if、if else 或 if else if else 构造来完成&#xff0c;例如下面的示例&#xff1a; fn main() { let dead false; let health 48; if dead { p…

《汇编语言:基于linux环境》补码研究

刚开始我使用&#xff0c;如下命令编译&#xff0c;链接程序。 nasm -f elf64 -g -F stabs sandbox.asmld -o sandbox sandbox.ogdb sandbox当我运行 sandbox 时&#xff0c;它会正常运行&#xff0c;但 gdb 无法显示任何源代码。为什么&#xff1f;当我在 gdb 中尝试 run 时&a…

鸿蒙(ArkUI)开发:实现二级联动

场景介绍 列表的二级联动&#xff08;Cascading List&#xff09;是指根据一个列表&#xff08;一级列表&#xff09;的选择结果&#xff0c;来更新另一个列表&#xff08;二级列表&#xff09;的选项。这种联动可以使用户根据实际需求&#xff0c;快速定位到想要的选项&#…