C鶼BitBltを用いたウィンドウキャプチャの例
本明細書はC++はBitBltを使ってウィンドウキャプチャーを行います。に対応し、C〓を用いて実現される。
この方式は1920×1080サイズのウィンドウに対して、一回のキャプチャーの時間を参照する(VVS 2015+i 5 9400 F):2~3 ms(平均4.3 ms)まで低い。
参照:C〓〓〓キャプチャーサービス。
1、Win 32パッケージ
Win 32 Conss
この方式は1920×1080サイズのウィンドウに対して、一回のキャプチャーの時間を参照する(VVS 2015+i 5 9400 F):2~3 ms(平均4.3 ms)まで低い。
参照:C〓〓〓キャプチャーサービス。
1、Win 32パッケージ
Win 32 Conss
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
}
}
}
Win 32 Type
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;
}
}
}
Win 32 Funncs
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;
}
}
}
以上はBitBltを使ってウィンドウキャプチャーを行ったC菗の例の詳細です。c菗ウインドウキャプチャーに関する資料は他の関連記事に注目してください。