C# 使用BitBlt进行窗口抓图的示例

本文和C++使用BitBlt进行窗口抓图对应,使用C#实现。

这种方式对1920*1080大小的窗口,一次抓图的时间参考(VS2015+i5 9400F):低至2~3ms(平均4.3ms)。

参见:C#抓图服务。

1、Win32封装

Win32Consts

using System.ComponentModel;

namespace CaptureSharp
{
 public sealed class Win32Consts
 {
 public enum DibColorMode : uint
 {
  DIB_RGB_COLORS = 0x00,
  DIB_PAL_COLORS = 0x01,
  DIB_PAL_INDICES = 0x02
 }

 public enum BitmapCompressionMode : uint
 {
  BI_RGB = 0,
  BI_RLE8 = 1,
  BI_RLE4 = 2,
  BI_BITFIELDS = 3,
  BI_JPEG = 4,
  BI_PNG = 5
 }

 public enum RasterOperationMode : uint
 {
  SRCCOPY = 0x00CC0020,
  SRCPAINT = 0x00EE0086,
  SRCAND = 0x008800C6,
  SRCINVERT = 0x00660046,
  SRCERASE = 0x00440328,
  NOTSRCCOPY = 0x00330008,
  NOTSRCERASE = 0x001100A6,
  MERGECOPY = 0x00C000CA,
  MERGEPAINT = 0x00BB0226,
  PATCOPY = 0x00F00021,
  PATPAINT = 0x00FB0A09,
  PATINVERT = 0x005A0049,
  DSTINVERT = 0x00550009,
  BLACKNESS = 0x00000042,
  WHITENESS = 0x00FF0062,
  CAPTUREBLT = 0x40000000 //only if WinVer >= 5.0.0 (see wingdi.h)
 }

 public enum PrintWindowMode : uint
 {
  [Description(
  "Only the client area of the window is copied to hdcBlt. By default, the entire window is copied.")]
  PW_CLIENTONLY = 0x00000001,

  [Description("works on windows that use DirectX or DirectComposition")]
  PW_RENDERFULLCONTENT = 0x00000002
 }
 }
}

Win32Types

using System.Runtime.InteropServices;

namespace CaptureSharp
{
 public sealed class Win32Types
 {
 [StructLayout(LayoutKind.Sequential)]
 public struct Point
 {
  public int x;
  public int y;

  public Point(int x, int y)
  {
  this.x = x;
  this.y = y;
  }
 }

 [StructLayout(LayoutKind.Sequential)]
 public struct Rect
 {
  public int Left; //最左坐标
  public int Top; //最上坐标
  public int Right; //最右坐标
  public int Bottom; //最下坐标

  public int Width => Right - Left;
  public int Height => Bottom - Top;
 }

 [StructLayout(LayoutKind.Sequential, Pack = 2)]
 public struct BitmapFileHeader
 {
  public ushort bfType;
  public uint bfSize;
  public ushort bfReserved1;
  public ushort bfReserved2;
  public uint bfOffBits;
 }

 [StructLayout(LayoutKind.Sequential)]
 public struct BitmapInfoHeader
 {
  public uint biSize;
  public int biWidth;
  public int biHeight;
  public ushort biPlanes;
  public ushort biBitCount;
  public uint biCompression;
  public uint biSizeImage;
  public int biXPelsPerMeter;
  public int biYPelsPerMeter;
  public uint biClrUsed;
  public uint biClrImportant;

  public void Init()
  {
  biSize = (uint)Marshal.SizeOf(this);
  }
 }

 [StructLayout(LayoutKind.Sequential, Pack = 1)]
 public struct RgbQuad
 {
  public byte rgbBlue;
  public byte rgbGreen;
  public byte rgbRed;
  public byte rgbReserved;
 }

 [StructLayout(LayoutKind.Sequential, Pack = 1)]
 public struct BitmapInfo
 {
  public BitmapInfoHeader bmiHeader;
  public RgbQuad bmiColors;
 }
 }
}

Win32Funcs

using System;
using System.Runtime.InteropServices;

namespace CaptureSharp
{
 public sealed class Win32Funcs
 {
 [DllImport("User32.dll", SetLastError = true)]
 public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

 [DllImport("user32.dll")]
 [return: MarshalAs(UnmanagedType.Bool)]
 public static extern bool GetWindowRect(IntPtr hWnd, out Win32Types.Rect lpRect);

 [DllImport("user32.dll")]
 public static extern bool GetClientRect(IntPtr hWnd, out Win32Types.Rect lpRect);

 [DllImport("user32.dll", EntryPoint = "GetWindowDC")]
 public static extern IntPtr GetWindowDC(IntPtr hWnd);

 [DllImport("gdi32.dll")]
 public static extern IntPtr CreateCompatibleDC(IntPtr hDc);

 [DllImport("gdi32.dll")]
 public static extern IntPtr CreateCompatibleBitmap(IntPtr hDc, int nWidth, int nHeight);

 [DllImport("gdi32.dll")]
 public static extern bool DeleteDC(IntPtr hDc);

 [DllImport("user32.dll")]
 public static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc);

 [DllImport("gdi32.dll")]
 public static extern IntPtr CreateDIBSection(IntPtr hdc, ref Win32Types.BitmapInfo bmi,
  uint usage, out IntPtr ppvBits, IntPtr hSection, uint dwOffset);

 [DllImport("gdi32.dll")]
 public static extern IntPtr SelectObject(IntPtr hDc, IntPtr hObject);

 [DllImport("gdi32.dll")]
 public static extern bool DeleteObject(IntPtr hObject);

 [DllImport("gdi32.dll", SetLastError = true)]
 public static extern bool BitBlt(
  IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight,
  IntPtr hObjectSource, int nXSrc, int nYSrc, uint dwRop);

 [DllImport("user32.dll")]
 public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
 }
}

2、DibCaptureHelper.cs

using System;

namespace CaptureSharp
{
 internal class DibCaptureHelper
 {
 public IntPtr BitmapPtr => _hBitmap;
 public Win32Types.BitmapInfo BitmapInfo => _bitmapInfo;
 public Win32Types.Rect WindowRect => _windowRect;
 public Win32Types.Rect ClientRect => _clientRect;
 public int BitmapDataSize => _bmpDataSize;

 private IntPtr _hWnd = IntPtr.Zero;
 private IntPtr _hScrDc = IntPtr.Zero;
 private IntPtr _hMemDc = IntPtr.Zero;
 private IntPtr _hBitmap = IntPtr.Zero;
 private IntPtr _hOldBitmap = IntPtr.Zero;
 private IntPtr _bitsPtr = IntPtr.Zero;

 private Win32Types.BitmapInfo _bitmapInfo;
 private Win32Types.Rect _windowRect;
 private Win32Types.Rect _clientRect;
 private int _bmpDataSize;

 public bool Init(string windowName)
 {
  var handle = Win32Funcs.FindWindow(null, windowName);
  if (handle.Equals(IntPtr.Zero))
  {
  return false;
  }

  return Init(handle);
 }

 public bool Init(IntPtr handle)
 {
  _hWnd = handle;

  //获取窗口大小
  if (!Win32Funcs.GetWindowRect(_hWnd, out _windowRect)
  || !Win32Funcs.GetClientRect(_hWnd, out _clientRect))
  {
  return false;
  }

  _bmpDataSize = _clientRect.Width * _clientRect.Height * 3;

  //位图信息
  _bitmapInfo = new Win32Types.BitmapInfo {bmiHeader = new Win32Types.BitmapInfoHeader()};
  _bitmapInfo.bmiHeader.Init();
  _bitmapInfo.bmiHeader.biWidth = _clientRect.Width;
  _bitmapInfo.bmiHeader.biHeight = _clientRect.Height;
  _bitmapInfo.bmiHeader.biPlanes = 1;
  _bitmapInfo.bmiHeader.biBitCount = 24;
  _bitmapInfo.bmiHeader.biSizeImage = (uint) (_clientRect.Width * _clientRect.Height);
  _bitmapInfo.bmiHeader.biCompression = (uint) Win32Consts.BitmapCompressionMode.BI_RGB;

  _hScrDc = Win32Funcs.GetWindowDC(_hWnd);
  _hMemDc = Win32Funcs.CreateCompatibleDC(_hScrDc);
  _hBitmap = Win32Funcs.CreateDIBSection(_hMemDc, ref _bitmapInfo,
  (uint) Win32Consts.DibColorMode.DIB_RGB_COLORS,
  out _bitsPtr, IntPtr.Zero, 0);
  _hOldBitmap = Win32Funcs.SelectObject(_hMemDc, _hBitmap);

  return true;
 }

 public void Cleanup()
 {
  if (_hBitmap.Equals(IntPtr.Zero))
  {
  return;
  }

  //删除用过的对象
  Win32Funcs.SelectObject(_hMemDc, _hOldBitmap);
  Win32Funcs.DeleteObject(_hBitmap);
  Win32Funcs.DeleteDC(_hMemDc);
  Win32Funcs.ReleaseDC(_hWnd, _hScrDc);

  _hWnd = IntPtr.Zero;
  _hScrDc = IntPtr.Zero;
  _hMemDc = IntPtr.Zero;
  _hBitmap = IntPtr.Zero;
  _hOldBitmap = IntPtr.Zero;
  _bitsPtr = IntPtr.Zero;
 }

 public bool RefreshWindow()
 {
  var hWnd = _hWnd;
  Cleanup();
  return Init(hWnd);
 }

 public bool ChangeWindowHandle(string windowName)
 {
  Cleanup();
  return Init(windowName);
 }

 public bool ChangeWindowHandle(IntPtr handle)
 {
  Cleanup();
  return Init(handle);
 }

 public IntPtr Capture()
 {
  if (_hBitmap.Equals(IntPtr.Zero) || _hMemDc.Equals(IntPtr.Zero) || _hScrDc.Equals(IntPtr.Zero))
  {
  return IntPtr.Zero;
  }

  var ret = Win32Funcs.BitBlt(
  _hMemDc, 0, 0, _clientRect.Width, _clientRect.Height,
  _hScrDc, 0, 0,
  (uint) Win32Consts.RasterOperationMode.SRCCOPY);

  return ret ? _bitsPtr : IntPtr.Zero;
 }

 public bool Capture(out IntPtr bitsPtr, out int bufferSize, out Win32Types.Rect rect)
 {
  bitsPtr = _bitsPtr;
  bufferSize = _bmpDataSize;
  rect = _clientRect;

  if (_hBitmap.Equals(IntPtr.Zero) || _hMemDc.Equals(IntPtr.Zero) || _hScrDc.Equals(IntPtr.Zero))
  {
  return false;
  }

  var ret = Win32Funcs.BitBlt(
  _hMemDc, 0, 0, _clientRect.Width, _clientRect.Height,
  _hScrDc, 0, 0,
  (uint) Win32Consts.RasterOperationMode.SRCCOPY);

  return ret;
 }
 }
}

以上就是C# 使用BitBlt进行窗口抓图的示例的详细内容,更多关于c# 窗口抓图的资料请关注我们其它相关文章!

(0)

相关推荐

  • C# 抓图服务的实现

    C#抓图服务首先抽象出抓图接口,然后对接口做基于公共操作的抽象类封装,之后针对不同的抓图方式做差异化处理,最后根据接口实现抓图服务. 注意:Win32封装实现参考C#使用BitBlt进行窗口抓图. Github示例工程:SimpleWindowCapture. 1.抓图接口 using System; using Win32Proxy; namespace CaptureProxy { internal interface ICaptureHelper { bool Init(string wi

  • C# 实现QQ式截图功能实例代码

    这个功能一共有两部分组成,第一部分是窗体代码,另外的一部分是一个辅助方法.直接贴出代码,以供大家参考: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.D

  • C# 实现SDL2进行视频播放窗口截图和字幕添加

    使用SDL2进行视频播放窗口截图和字幕添加操作 SDL API查看:https://wiki.libsdl.org/APIByCategory 视频截图 我就废话不多说了,大家还是直接看代码吧~ /// <summary> /// SDL2截图操作类 /// </summary> public unsafe class SDLScreenshot { IntPtr window;// 窗口对象 IntPtr renderer;// 播放窗口的渲染器(来自于已初始化的播放窗口渲染器)

  • c#实现winform屏幕截图并保存的示例

    复制代码 代码如下: using System.Runtime.InteropServices;using System.Drawing.Imaging;    [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]    private static extern bool BitBlt( IntPtr hdcDest,   //   目标   DC的句柄                       int n

  • C#实现的滚动网页截图功能示例

    本文实例讲述了C#实现的滚动网页截图功能.分享给大家供大家参考,具体如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WindowsFormsApplic

  • C# 实现截图软件功能实例代码

    本文是利用C# 开发截图软件的小例子,以供学习分享使用. 思路: 截取屏幕图片. 获取要截取的范围,即左上角,右下角坐标 填充到PictureBox中. 笔触功能,荧光笔,矩形,橡皮擦,复制,保存功能 涉及的知识点: MenuStrip:为窗体提供菜单系统.以ToolStripMenuItem为菜单子选项 ToolStrip:为 Windows 工具栏对象提供容器.以ToolStripButton[表示包含文本和图像的可选]为工具栏子元素 PictureBox:表示用于显示图像的 Windows

  • C#实现网页截图功能

    网页截图是很常见的实用功能,今天就为大家共享一个实现浏览器截图的代码,主要程序代码如下所示: private void Form_Load(object sender, EventArgs e) { //接收web url string colle = string.Empty; string url = string.Empty; //获取进程调用传入的命令 string[] args = Environment.GetCommandLineArgs(); string[] args = ne

  • C#实现QQ截图功能及相关问题

    对于QQ截图,肯定是早就有认识了,只是一直没有去认真观察这个操作的具体实现步骤.所以这里将自己的记忆中的步骤简单的写一下: 习惯性用QQ或者TIM的人,一般是使用Ctrl+Alt+A  快捷键(热键)快速实现截图. Ctrl+Alt+A  进入截图模式 鼠标左键点击 鼠标拖动对截图去进行选取 鼠标左键弹起 双击截图区域  保存图片到剪贴板 鼠标右键点击 退出截图模式 因为考虑到截图模式的时候  一般只能显示一个窗体  所以就考虑使用单例模式  在ScreenBody窗体中实现以下代码 1:创建单

  • C#实现在网页中根据url截图并输出到网页的方法

    本文实例讲述了C#实现在网页中根据url截图并输出到网页的方法.分享给大家供大家参考,具体如下: 网页截图是很多站点的一个小需求,这段代码实现的是如何根据url获得网页截图并输出到网页中. using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Thr

  • C#实现属于自己的QQ截图工具

    下面就具体介绍下实现截图工具的实现思路. 为了让大家更清楚地知道如何去实现自己的截图工具,首先我来描述下截图的一个过程--我们使用QQ的截图工具和Windows 自带的截图工具都可以发现,当我们点击QQ窗体中的截图按钮时,此时我们将看到一个全屏图片,然后我们可以在其上截图,当鼠标左键按下时,即代表开始截图,并我们可以移动鼠标来改变截图的大小,鼠标弹起时即代表结束截图,此时我们可以双击矩形区域完全截图,并且可以通过粘贴操作把截取的图片粘贴到聊天窗口的发送区,鼠标右键点击则是退出截图.这样我们截图的

  • C#实现通过ffmpeg从flv视频文件中截图的方法

    本文实例讲述了C#实现通过ffmpeg从flv视频文件中截图的方法.分享给大家供大家参考.具体分析如下: 需要先下载ffmpeg,这是开源的,代码如下所示: 复制代码 代码如下: using System; using System.Configuration; public class PublicMethod:System.Web.UI.Page {     public PublicMethod()     {     }     //文件路径     public static stri

随机推荐