为.NET应用添加截图功能

本文介绍了 .NET 实现截图功能的思路和过程,如果你仅想了解最后的解决方案,可以直接查看文章末尾。

截图的功能我们应该都经常使用,在开发软件时,我们有时也或多或少需要提供这方面的功能,无论是为用户更方便提供远程诊断,还是获取用户的选择区域,亦或是提供某些功能上的辅助。

开发截图无非就这几种选择:教用户使用截图工具、自行开发一个、使用第三方库。

教用户使用

教的成本无疑是最低的,但是不知道用户那边会发生什么,存在很大的不确定性。截图软件除了我们经常用的聊天工具和系统自带的 Win + Ctrl + S外,我用起来感觉最好的还是 C++ 写的开源软件 flameshot[1] ,功能非常强大。

9111b79689336215ce3788d3d670fb33.png
flameshot

使用的第三方的截图软件,不仅有教的成本,还会打断用户对本身软件的一个使用体验。教用户使用最好还是用系统自带的 Win + Ctrl + S截图,已经可以满足基本的截图需求。

自行开发

自行开发的原理也非常简单:创建一个半透明的全屏无边框窗体,记录鼠标在窗体上的框选矩形位置,使用CopyFromScreen获取该位置的屏幕图片即可。

以上只是针对单个显示器的情况,若有多个显示器,则需要增加鼠标所在显示器的逻辑。

虽然听起来不难,但代码实现起来还是有许多要注意的细节。简单的矩形截图实现不难,难得是让用户易用,易接受,毕竟聊天软件已经帮你培养了用户习惯。

使用第三方库

CSkin[2] 是我在 2012 年就在使用的一款界面库,在 WinForm 无疑是软件 UI 美化的王者,可以直接作出和 PC 端 QQ 一样的界面体验。库里也提供了截图工具 FrmCapture,没中不足的是,在多显示器场景下会报错,无法正常使用,代码库也有 4 年没有更新了。

private FrmCapture m_frmCapture;
if (m_frmCapture == null || m_frmCapture.IsDisposed)
{m_frmCapture = new FrmCapture();
}
m_frmCapture.IsCaptureCursor = false;
// 截图结束事件
m_frmCapture.Disposed += M_frmCapture_Disposed;
m_frmCapture.Show();

HandyControl[3] 和在 nuget 上搜索到的 ScreenCapturerSharp[4] 虽然也可以实现截图功能,但都无法处理多显示器的场景。HandyControl 社区活跃,其使用体验会比较好。ScreenCapturerSharp 提供了类似 QQ 的截图工具库,在 UI 上稍差一些。

如何又快又好又容易

如果只是获取截图,有没有更简单的方式呢?我们只需要模拟按键 Win + Ctrl + S 就可以了呀,然后通过剪贴板获取到截图。说起来容易,但是事情其实并没有那么简单。

首先 SendKeys 就不支持发送 Windows 徽标按键,我们需要通过 WinAPI keybd_event 来替代实现,然后还要获取到截图结束的事件。

[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

其实上面是一个保底的通用方案,我们可以自行启动截图软件,启动截图软件读取剪贴板Clipboard.GetImage() 一套结束,无缝无感,堪称完美:

Process snippingToolProcess = new Process()
{StartInfo = new ProcessStartInfo("C:\\Windows\\system32\\SnippingTool.exe", "/clip"),EnableRaisingEvents = true,
};
snippingToolProcess.Exited += SnippingToolProcess_Exited;
snippingToolProcess.Start();

事情其实远没有那么简单,直到我在 Win11 用了我的软件。才意识到,这只是可以在 Win10 的 64 位操作系统使用。SnippingTool /clip 这样带参数启动在 Win11 不支持了,这个路径下的 exe 还被删除了。

虽然你可以在 Win11 通过控制台使用SnippingTool /clip启动截图软件,但是并不会直接进入截图流程,而是打开软件主界面。

仔细研究你会发现,Win11 的截图其实已经是 UWP 应用了,就算你吧 Win10 的 SnippingTool.exe 复制到 Win11 也是报错,无法使用的,所以你也不可能在自己的软件打包带上它。

经过几番折腾,我在微软社区提问和提交反馈( Win + F 的时候我觉得这个软件是不是这样启动直接就先截了个屏 ),但是没有找到新版本截图的启动参数。最后直到我前几天发现 Microsoft Learn 的文章 启动屏幕截取 - UWP applications[5]。在 UWP 里使用这么简单嘛,使用 LaunchUriAsync 就可以了。

bool result = await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-screenclip:"));

有了 URI 的方式,一切就变简单了,你甚至可以在浏览器里调用截图,放一个超链接,或者直接在浏览器地址栏粘贴ms-screenclip:后回车打开截图。

之后我们只需要监听进程结束就可以了,这里需要说明的是,不是启动的进程,而是截图的进程,下面直接上在 WinForm 中使用的代码:

var psi = new ProcessStartInfo()
{UseShellExecute = true,FileName = "ms-screenclip:"
};
Process.Start(psi);// 获取 ScreenClippingHost 这个截图进程的结束事件
var snippingToolProcess = Process.GetProcessesByName("ScreenClippingHost")[0];
snippingToolProcess.EnableRaisingEvents = true;
snippingToolProcess.Exited += SnippingToolProcess_Exited;

SnippingToolProcess_Exited 事件:

private void SnippingToolProcess_Exited(object? sender, EventArgs e)
{this.BeginInvoke(new Action(() =>{var img = Clipboard.GetImage();}));
}

References

[1] flameshot: https://github.com/flameshot-org/flameshot
[2] CSkin: http://www.cskin.net/
[3] HandyControl: https://handyorg.github.io/handycontrol/extend_controls/screenshot/
[4] ScreenCapturerSharp: https://www.nuget.org/packages/ScreenCapturerSharp
[5] 启动屏幕截取 - UWP applications: https://learn.microsoft.com/zh-cn/windows/uwp/launch-resume/launch-screen-snipping

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

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

相关文章

K8S集群Master高可用实践

本文将在前文基础上介绍k8s集群的高可用实践,一般来讲,k8s集群高可用主要包含以下几个内容:1、etcd集群高可用2、集群dns服务高可用3、kube-apiserver、kube-controller-manager、kube-scheduler等master组件的高可用 其中etcd实现的办法较为…

[转载]智能科普:VR、AR、MR的区别

智能科普:VR、AR、MR的区别 http://news.zol.com.cn/553/5534833.html news.zol.com.cn 2015-11-23 16:00近日, 获得谷歌5亿美元融资的技术公司Magic Leap在WSJD展会中放出了一段实录视频,引起不小骚动。如今,也有媒体称他们为MR公…

PHP项目中,记录错误日志

一、场景介绍: 环境:LNMP 我们通常是通过nginx的错误日志来分析分错的,也就是我们在各个server中定义的error_log。 比如下面这样,就是将错误日志定义在/etc/nginx/logs/error/www.xiaobudiu.top.log,发生错误&#xf…

持续集成指南:GitLab 的 CI/CD 工具配置与使用

1前言写代码这项工作,本质就是将工作自动化,减少手工操作提供效率,因为人的本质都是懒狗,程序员也不能例外,为了各种意义的效率提升(懒),我们需要持续集成工具,将代码测试…

php 错误日志 redis' already loaded in Unknown on line 0

环境介绍:LNMP 报错信息:注:这个php_errors.log 是我在php.ini 中定义的错误日志路径 问题原因: 报错信息给出的意思是:redis和memcache 模块已经加载过问题解决: php加载模块有两种方式,一种是…

第一周作业

我的Git账号:AI1452349541 和代码图 这是我在电脑和手机上下的网易有道词典 , C也下了。 ***学习内容总结*** 感觉任务并不是很难,有些任务没完成是 因为还没买电脑不好弄,下周电脑一定到位。 ***遇到的问题…

升级MariaDB为10.1版本

2019独角兽企业重金招聘Python工程师标准>>> CentOS中升级mariadb为10.1GA版本。 1、如果有,停止服务 systemctl stop mariadb 2、卸载原来的数据库服务 yum -y remove mari* 3、删除数据库文件 rm -rf /var/lib/mysql/* 4.创建/etc/yum.repos.d/MariaDB…

第一篇文章

第一次写博客。欢迎各位大牛捧场转载于:https://www.cnblogs.com/clnchanpin/p/6753665.html

羊了个羊的Ignite大会又来啦

据说最近羊了个羊非常火啊~可惜没有时间精力研究。不过,薅微软羊毛的机会我是一定不会错过的,这不,薅羊毛的机会来了,哈哈哈。作为经常薅微软羊毛的老司机,今天收到了微软的邮件,告知有新的羊毛…

清除谷歌浏览器的dns缓存

谷歌地址栏输入: chrome://net-internals/#dns出现下面界面:找到DNS选项,选择clear host cache即可效果:这样,谷歌浏览器上的dns缓存就清理掉了。应用场景: 本地环境和线上环境用的是一个host,这…

什么样的代码称得上是好代码?

“软件自有其美感所在” --《重构》图片:崇礼瀚海梁的山花 拍摄于2022年8月13日 摄影师:刘先生这篇内容写作于4年前(2018年),是自己多年软件开发工作的一点感悟,现在看来虽有偏颇,但总体思想方…

Coding and Paper Letter(十四)

2019独角兽企业重金招聘Python工程师标准>>> 资源整理。 1 Coding: 1.R语言包ungeviz,ggplot2的拓展包,专门用来作不确定性的可视化。 ungeviz 2.计算机图形学相关开源项目。 计算机图形学光线追踪开源项目C源码。 computer graphics ray tra…

eclipse安装反编译插件

一、下载插件 1、官方地址:http://jd.benow.ca/ 2、百度网盘:http://pan.baidu.com/s/1eSJ7Tiq 密码:sr6p 二、打开eclipse,点击“Help > Install New Software” 三、Name填:JD-Eclipse Update Site(可…

PHP 项目中缓存的多种应用实现

一、CDN缓存原理和介绍 1、各地部署多套静态存储服务,本质上是空间成本换时间 2、CDN是域名和真实服务器中间的一个环节,添加cdn节点后,用户访问时,自动选择最近的节点内容,不存在再请求原始服务器 3、CDN本质上是一种…

【tomcat】servlet原理及其生命周期

1.什么是servlet? Servlet(Servlet Applet),全称Java Servlet,是用Java编写的服务器端程序。而这些Servlet都要实现Servlet这个接口。其主要功能在于交互式的浏览和修改数据,生成动态Web内容。Servlet运行于支持Java的…

实现一个监控 IP 的 windows 服务

实现一个监控 IP 的 windows 服务Intro我们公司的 VPN 用自己的电脑连公司的台式机的时候需要用 IP 地址,有一次尝试去连的时候发现连不上,第二天到公司发现 IP 变掉了,不是之前连的 IP 了,于是就想写一个简单 Windows 服务来监控…

微信企业号开发:启用回调模式

微信企业号开发怎样启用回调模式?就是简单的登陆PC版微信,点击应用中心,选择须要应用,再点击回调模式启用?似乎不是这么简单。!能够看到核心的仅仅有三个URL。Token,EncodingAESKey这三个參数能…

MVC中提交表单的4种方式

一,MVC HtmlHelper方法 Html.BeginForm(actionName,controllerName,method,htmlAttributes){} BeginRouteForm 方法 (HtmlHelper, String, Object, FormMethod) 二,传统Form表单Aciton属性提交 三,JqueryAjax 提交表单 四,MVC C…

photoshop制作网站圆形图标ico

1、选择左侧工具栏中的椭圆工具2、鼠标直接在图片上选择区域3、在图片上鼠标右键建立选区,在弹出的对话框直接点确定变成这样:4、点击选择,然后点击反选变成这样5、图层栏,在图片上右键复制图层,弹出对话框直接确定即可…

WPF 窗体设置亚克力效果

WPF 窗体设置亚克力效果控件名:WindowAcrylicBlur作者: WPFDevelopersOrg - 吴锋原文链接: https://github.com/WPFDevelopersOrg/WPFDevelopers框架使用大于等于.NET40。Visual Studio 2022。项目使用 MIT 开源许可协议。WindowAcrylicB…