C# 使用BitBlt進行視窗抓圖的示例
阿新 • • 發佈:2021-01-08
本文和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 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,_clientRect.Width,_clientRect.Height,_hScrDc,(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,(uint) Win32Consts.RasterOperationMode.SRCCOPY); return ret; } } }
以上就是C# 使用BitBlt進行視窗抓圖的示例的詳細內容,更多關於c# 視窗抓圖的資料請關注我們其它相關文章!