少侠学截屏-C#屏幕捕捉的方式
本篇主要介绍如何通过C#代码来获得Windows操作系统的桌面位图。
当然,不仅仅是截屏。主要是受园子里的朋友我不是圣人的激发,勾起了继续探究一下Windows屏幕捕捉和网络传输的欲望。
以前也搞过一阵子,不过都是浅尝一下。最近几天搞了点眉目出来,这里就先发第一块出来分享一下。
后续的还要等我调试完成,想清楚了再发。
截屏的结果就是要获得一个位图
主要方式有两个:
1、C#类库
2、Windows32API
先介绍使用C#类库的方式
主要使用Screen类
http://msdn.microsoft.com/zh-cn/library/system.windows.forms.screen.aspx
表示单个系统上的一个或多个显示设备。
命名空间: System.Windows.Forms
程序集: System.Windows.Forms(在 System.Windows.Forms.dll 中)
代码:
Image img = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics g = Graphics.FromImage(img);
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), Screen.PrimaryScreen.Bounds.Size);
通过这3行,img已经获得了对一个位图的引用了。
简单得很哦
第二种:使用Win32API
主要参考这个版本的代码
http://www.csharphelp.com/2006/11/capturing-the-screen-image-using-c/
具体不想多做介绍了
简单说明,Windows操作系统本身拥有丰富的代码,能完成很多系统级功能,并且非常高效。
而C#以及各种.net程序,以及其他高级语言完成类似功能时都需要程序员为之编码,且运行效率多数是不行的。
所以干吗要重复造轮子呢
在.net这里可以使用上述的方式来引用Windows的系统函数来完成我们需要的功能
探讨的部分是,在很多Win32调用的程序中,释放句柄一直是非常要紧的一件事
但是在我实际使用中发现不是必须如此的
原始代码:
public static Bitmap GetDesktopImage()
{
//Variable to keep the handle of the btimap.
IntPtr m_HBitmap=null;
//Variable to keep the refrence to the desktop bitmap.
System.Drawing.Bitmap bmp=null;
//In size variable we shall keep the size of the screen.
SIZE size;
//Here we get the handle to the desktop device context.
IntPtr hDC = PlatformInvokeUSER32.GetDC(PlatformInvokeUSER32.GetDesktopWindow());
//Here we make a compatible device context in memory for screen device context.
IntPtr hMemDC = PlatformInvokeGDI32.CreateCompatibleDC(hDC);
//We pass SM_CXSCREEN constant to GetSystemMetrics to get the X coordinates of screen.
size.cx = PlatformInvokeUSER32.GetSystemMetrics (PlatformInvokeUSER32.SM_CXSCREEN);
//We pass SM_CYSCREEN constant to GetSystemMetrics to get the Y coordinates of screen.
size.cy = PlatformInvokeUSER32.GetSystemMetrics(PlatformInvokeUSER32.SM_CYSCREEN);
//We create a compatible bitmap of screen size and using screen device context.
m_HBitmap = PlatformInvokeGDI32.CreateCompatibleBitmap(hDC, size.cx, size.cy);
//As m_HBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
if (m_HBitmap!=IntPtr.Zero)
{
//Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
IntPtr hOld = (IntPtr) PlatformInvokeGDI32.SelectObject(hMemDC, m_HBitmap);
//We copy the Bitmap to the memory device context.
PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0,size.cx,size.cy, hDC, 0, 0,PlatformInvokeGDI32.SRCCOPY);
//We select the old bitmap back to the memory device context.
PlatformInvokeGDI32.SelectObject(hMemDC, hOld);
//We delete the memory device context.
PlatformInvokeGDI32.DeleteDC(hMemDC);
//We release the screen device context.
PlatformInvokeUSER32.ReleaseDC(PlatformInvokeUSER32.GetDesktopWindow(), hDC);
//Image is created by Image bitmap handle and assigned to Bitmap variable.
bmp=System.Drawing.Image.FromHbitmap(m_HBitmap);
//Delete the compatible bitmap object.
PlatformInvokeGDI32.DeleteObject(m_HBitmap);
return bmp;
}
//If m_HBitmap is null retunrn null.
return null;
}
对比代码:
public static Bitmap GetDesktopImage()
{
//As m_HBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
if (m_HBitmap!=IntPtr.Zero)
{
//Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
IntPtr hOld = (IntPtr) PlatformInvokeGDI32.SelectObject(hMemDC, m_HBitmap);
//We copy the Bitmap to the memory device context.
PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0,size.cx,size.cy, hDC, 0, 0, PlatformInvokeGDI32.SRCCOPY);
//We select the old bitmap back to the memory device context.
PlatformInvokeGDI32.SelectObject(hMemDC, hOld);
//老外的原始代码中,静态构造里是没东西的。所有那些都是在本函数中声明、使用并且销毁的。
//如果有喜欢销毁东西癖好的,可以在这里销毁hDC、hMemDC以及m_HBitmap
//不过我觉得没有这个必要,并且不销毁能提高点点速度
return System.Drawing.Image.FromHbitmap(m_HBitmap);
}
//If m_HBitmap is null retunrn null.
return null;
}
因为我觉得hDC在本程序使用中永远是指向桌面窗口的句柄,简单说这个指针的值是永远不变的。除非桌面窗口被释放、重建。
同理hMemDC也是一样和桌面窗口关联的
m_HBitmap则是一个位图对象的引用,也就是申请了一块内存。
反复多次对同一片内存写入数据是不会有问题的
因此我在代码中把这几个的初始化都转移到了静态构造里,只运行一次。实际看速度是快了一点的。
由于对C/C++的理解不是很深(本人本质是VB5.0+VBA office程序员出身),希望有关达人能指点一下上述理由是否成立。
小结:
C#类库方式:代码简洁、学习代价低
Win32API方式:代码复杂、学习难度高
一般而言用C#方式,并且执行效率上看,在我的机器上两者区别不大。Win32API方式略有优势。
关键点:鼠标呢?
上面两个代码其实都没有捕捉到鼠标,很不爽的一个地方
通过网络搜索和试验,在Win32API方式下我完成了对鼠标形状及位置的捕获。Win32API在win平台上应该是万能的,呵呵。
总体思路是在捕获全屏后,单独获取鼠标位置及形状。然后“画”到先前捕获的位图上
public static Bitmap GetDesktopImage()
{
//As m_HBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
if (m_HBitmap!=IntPtr.Zero)
{
//Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
IntPtr hOld = (IntPtr) PlatformInvokeGDI32.SelectObject(hMemDC, m_HBitmap);
//We copy the Bitmap to the memory device context.
PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0,size.cx,size.cy, hDC, 0, 0, PlatformInvokeGDI32.SRCCOPY);
#region 绘制鼠标
PlatformInvokeUSER32.CURSORINFO pci = new PlatformInvokeUSER32.CURSORINFO();
pci.cbSize = Marshal.SizeOf(pci);
PlatformInvokeUSER32.GetCursorInfo(out pci);
IntPtr dc = hMemDC;
//这个偏移量是我在使用时发现的问题,不一定是10,没有精确论证过。只是目前看起来位置正确。
PlatformInvokeUSER32.DrawIconEx(dc, pci.ptScreenPos.X-10, pci.ptScreenPos.Y-10, pci.hCursor, 32, 32, 1, IntPtr.Zero, PlatformInvokeUSER32.DI_NORMAL);
#endregion
//We select the old bitmap back to the memory device context.
PlatformInvokeGDI32.SelectObject(hMemDC, hOld);
//老外的原始代码中,静态构造里是没东西的。所有那些都是在本函数中声明、使用并且销毁的。
//如果有喜欢销毁东西癖好的,可以在这里销毁hDC、hMemDC以及m_HBitmap
//不过我觉得没有这个必要,并且不销毁能提高点点速度
return System.Drawing.Image.FromHbitmap(m_HBitmap);
}
//If m_HBitmap is null retunrn null.
return null;
}
经使用,完美解决问题。
最后把完整的抓屏解决方案的代码打包放这里带鼠标的全屏抓图
谢谢观赏
出处:http://www.cnblogs.com/Chinese-xu/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
如有问题,可以通过 Chinese_Xu@126.com 联系我,非常感谢。
少侠学截屏-C#屏幕捕捉的方式相关推荐
- iOS中的截屏(屏幕截屏及scrollView或tableView的全部截屏)
iOS中的截屏(屏幕截屏及scrollView或tableView的全部截屏) 2017.03.16 12:18* 字数 52 阅读 563评论 4喜欢 2 1. 截取屏幕尺寸大小的图片并保存至相册 ...
- 安卓 多条通知_安卓11第一版发布:原生滚动截屏、屏幕录像、抄国内ROM这么多...
自2008年第一部Android智能手机HTC G1发布,安卓手机系统已经走过十几个年头.虽然系统存在一些大家吐槽较多的问题,但安卓一直活跃在智能手机系统前沿,不断发展完善着. 昨天谷歌刚刚发布了全新 ...
- drm android 截屏,DRM-X4.0新增防盗录功能Windows智能防录屏,全面防止截屏和屏幕录制...
据国家版权局网络版权产业研究基地研究调查显示,2018年中国网络版权产业规模达7423亿元,相比2017年6364.5亿元增长了16.6%,成为中国经济增长的新动能.随着互联网技术的急速发展,尤其是在 ...
- 电脑捕捉android 屏幕,Android屏幕捕捉
Android 基于4.4系统截屏的三指截屏 Android5.0屏幕截屏与屏幕录制 Android多媒体二:Android 5.0新增的屏幕捕捉 系统级实时传输Android屏幕截图(实时抓图)并实 ...
- android平板电脑截屏,平板电脑怎样截图(iPad手机截图的3种方法)
想要在新的iPad Pro上截屏吗?鉴于最新的iPad Pro型号不再具有Home按钮人工智能高中版下载,因此在iPad上截取屏幕截图的旧方法不再有效,因为在iPad Pro上没有按下Home按钮来截 ...
- 如何在Mac上截屏?在Mac上截屏的几种不同方法
当您想在Mac上截图时,您既可以使用本机工具也可以使用第三方工具.因此,让我们看看如何充分利用Mac上的屏幕截图选项,并探索一些有用的技巧.一起了解在Mac上截屏的几种不同方法,包括一些第三方应用推荐 ...
- 如何以编程方式在Android上截屏?
如何通过代码而不是通过任何程序来截屏电话屏幕的选定区域? #1楼 Mualig的回答很好,但是我遇到了Ewoks描述的相同问题,但我没有得到背景知识. 因此,有时足够好,有时我会在黑色背景上出现黑色文 ...
- Android rom开发:最完整的截屏方案(支持全屏截屏+区域截屏)
网上很多资料都是说使用View的getDrawingCache接口,这种方式有一个问题,无法截取到状态栏,因此个人不推荐. View view = getWindow().getDecorView() ...
- 滚动截屏苹果_电脑手机技巧:苹果手机滚动截屏最优解
苹果手机有许多地方不如安卓手机方便,比如截长图啊.双开啊.应用锁啊,但这不是本文要讨论的问题. 今天要说的是:如何最大限度地做到像安卓手机那样截图(非safari页面). 苹果本身没有截长图功能,只能 ...
最新文章
- 马莉 - 人神共愤的处女座
- Effective Java(1)-创建和销毁对象
- 笔记本电脑关机快捷键_2020年双十一值得入手的高性价比笔记本电脑外设推荐...
- 团队第一阶段冲刺——第七天
- FPDF中文应用攻略
- 手机照片×××作:千里走单骑
- css网页favicon_自用代码css获取任意网址的/favicon.ico的方法教程
- MongoDBTool-最新进展报告
- CSDN APP又出错了,看不到博文
- Eclipse创建并运行Java程序输出Hello World
- 华电C语言题库(循环中等难度)
- [黑群晖经典教程] 一步一步建立自己的黑群晖
- 学习记录 - - 准备APS
- python恶搞代码打开对方摄像头_Python 3 利用 Dlib 实现摄像头实时人脸检测和平铺显示...
- 【阿里云】阿里云跨账号内网互通
- 各个版本的python在windows上如何安装pywin32
- jquery实现字数限制,超过部分...代替,后缀点击展开,点击后展开全文
- python爬取网站m3u8视频,将ts解密成mp4,合并成整体视频
- 解决mac idea2020打开闪退问题
- 一次惊心动魄的服务器误删文件恢复过程