C#使用PrintWindow进行窗口抓图

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

Win32封装同C#使用BitBlt进行窗口抓图

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

参见:C#抓图服务

PrintCaptureHelper.cs

复制代码
using System;

namespace CaptureSharp
{
    internal class PrintCaptureHelper
    {
        public IntPtr BitmapPtr => _hBitmap;
        public Win32Types.BitmapInfo BitmapInfo { get; } = new Win32Types.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 Win32Types.Rect _windowRect;
        private Win32Types.Rect _clientRect;
        private int _bmpDataSize;

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

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

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

            _hScrDc = Win32Funcs.GetWindowDC(_hWnd);
            _hBitmap = Win32Funcs.CreateCompatibleBitmap(_hScrDc, _windowRect.Width, _windowRect.Height);
            _hMemDc = Win32Funcs.CreateCompatibleDC(_hScrDc);
            _hOldBitmap = Win32Funcs.SelectObject(_hMemDc, _hBitmap);

            return true;
        }

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

            return Init(handle);
        }

        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;
        }

        public bool RefreshWindow()
        {
            return ChangeWindowHandle(_hWnd);
        }

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

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

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

            var ret = Win32Funcs.PrintWindow(_hWnd, _hMemDc,
                (uint) Win32Consts.PrintWindowMode.PW_CLIENTONLY |
                (uint) Win32Consts.PrintWindowMode.PW_RENDERFULLCONTENT);
            return ret ? _hBitmap : IntPtr.Zero;
        }

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

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

            var ret = Win32Funcs.PrintWindow(_hWnd, _hMemDc,
                (uint) Win32Consts.PrintWindowMode.PW_CLIENTONLY |
                (uint) Win32Consts.PrintWindowMode.PW_RENDERFULLCONTENT);

            return ret;
        }
    }
}
复制代码

 

posted @   xhubobo  阅读(2355)  评论(0编辑  收藏  举报
编辑推荐:
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
点击右上角即可分享
微信分享提示