You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中截取含滚动区域的完整活动窗口截图

解决C# .NET捕获活动窗口完整滚动区域截图的问题

我明白你的需求——要截的不只是窗口当前显示的部分,而是包括滚动条后面藏着的所有内容对吧?你现在的代码用PrintWindow结合GetWindowRect只能拿到窗口的可见区域,要搞定完整滚动内容的截图,我们得调整一下获取尺寸的方式,并且确保窗口把全部内容都渲染到Bitmap上。

问题分析

你当前代码里的GetWindowRect(hwnd, out rc)获取的是窗口在屏幕上的可见边界,而不是窗口内部可滚动区域的完整大小。所以即使你用这个尺寸创建Bitmap,PrintWindow也只会绘制可见的那部分。

解决方案思路

我们需要:

  1. 获取窗口客户区的完整可滚动尺寸(通过滚动条信息计算)
  2. 创建对应大小的Bitmap来容纳全部内容
  3. 让窗口把整个可滚动区域绘制到这个Bitmap的设备上下文(DC)上

完整实现代码

首先要补充必要的P/Invoke声明,然后修改截图方法:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

public class FullWindowScreenshot
{
    // P/Invoke 声明
    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

    [DllImport("user32.dll")]
    private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

    [DllImport("user32.dll")]
    private static extern int GetScrollInfo(IntPtr hWnd, int fnBar, ref SCROLLINFO lpsi);

    [DllImport("user32.dll")]
    private static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, uint nFlags);

    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();

    // 常量定义
    private const int SB_HORZ = 0;
    private const int SB_VERT = 1;
    private const int SIF_ALL = 0x00000003;
    private const uint WM_PRINT = 0x0031;
    private const uint PRF_CLIENT = 0x00000004;
    private const uint PRF_NONCLIENT = 0x00000002;
    private const uint PRF_OWNED = 0x00000010;
    private const uint PW_CLIENTONLY = 0x00000002;

    // 结构体定义
    [StructLayout(LayoutKind.Sequential)]
    private 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)]
    private struct SCROLLINFO
    {
        public int cbSize;
        public int fMask;
        public int nMin;
        public int nMax;
        public int nPage;
        public int nPos;
        public int nTrackPos;
    }

    public static void CaptureFullWindow(IntPtr hwnd)
    {
        try
        {
            // 获取客户区可见尺寸
            GetClientRect(hwnd, out RECT clientRect);
            int visibleWidth = clientRect.Width;
            int visibleHeight = clientRect.Height;

            // 获取水平滚动条信息,计算完整宽度
            SCROLLINFO scrollInfoH = new SCROLLINFO { cbSize = Marshal.SizeOf<SCROLLINFO>(), fMask = SIF_ALL };
            GetScrollInfo(hwnd, SB_HORZ, ref scrollInfoH);
            int fullWidth = scrollInfoH.nMax > 0 ? scrollInfoH.nMax + scrollInfoH.nPage : visibleWidth;

            // 获取垂直滚动条信息,计算完整高度
            SCROLLINFO scrollInfoV = new SCROLLINFO { cbSize = Marshal.SizeOf<SCROLLINFO>(), fMask = SIF_ALL };
            GetScrollInfo(hwnd, SB_VERT, ref scrollInfoV);
            int fullHeight = scrollInfoV.nMax > 0 ? scrollInfoV.nMax + scrollInfoV.nPage : visibleHeight;

            // 创建足够大的Bitmap
            using (Bitmap bmp = new Bitmap(fullWidth, fullHeight, PixelFormat.Format32bppArgb))
            {
                using (Graphics gfx = Graphics.FromImage(bmp))
                {
                    IntPtr hdc = gfx.GetHdc();

                    // 优先用WM_PRINT让窗口绘制全部内容,兼容更多控件
                    SendMessage(hwnd, WM_PRINT, hdc, (IntPtr)(PRF_CLIENT | PRF_NONCLIENT | PRF_OWNED));

                    // 如果WM_PRINT无效,尝试PrintWindow的客户端专属标志
                    // PrintWindow(hwnd, hdc, PW_CLIENTONLY);

                    gfx.ReleaseHdc(hdc);
                }

                // 保存截图(替换成你的目标路径)
                string savePath = $@"C:\Users\Dhibi\Desktop\{Guid.NewGuid().ToString()}.png";
                if (!IsAllOneColor(bmp))
                {
                    bmp.Save(savePath, ImageFormat.Png);
                }
            }
        }
        catch (Exception ex)
        {
            // 这里可以添加错误处理,比如日志或弹窗提示
            // MessageBox.Show($"截图失败:{ex.Message}");
        }
    }

    // 你原有的AllOneColor方法,用来判断截图是否有效
    private static bool IsAllOneColor(Bitmap bmp)
    {
        Color firstColor = bmp.GetPixel(0, 0);
        for (int x = 0; x < bmp.Width; x++)
        {
            for (int y = 0; y < bmp.Height; y++)
            {
                if (bmp.GetPixel(x, y) != firstColor)
                {
                    return false;
                }
            }
        }
        return true;
    }

    // 快捷方法:捕获当前活动窗口
    public static void CaptureActiveWindow()
    {
        IntPtr activeHwnd = GetForegroundWindow();
        CaptureFullWindow(activeHwnd);
    }
}

关键说明

  • 获取完整尺寸:通过GetScrollInfo获取滚动条的最大范围和每页大小,计算出完整的可滚动区域尺寸。如果窗口没有滚动条,就直接用客户区的可见尺寸。
  • WM_PRINT消息:相比PrintWindow,SendMessage(WM_PRINT)更可靠地让窗口绘制全部内容,包括滚动区域。我们设置的标志确保了窗口的客户区、非客户区以及所有子控件都被绘制。
  • 兼容性调整:如果某些特殊窗口(比如浏览器、复杂第三方控件)用WM_PRINT效果不好,可以尝试注释里的PrintWindow加PW_CLIENTONLY标志,针对不同窗口灵活切换。

使用方法

直接调用快捷方法就能捕获当前活动窗口:

FullWindowScreenshot.CaptureActiveWindow();

内容的提问来源于stack exchange,提问作者g33k

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 03:57:14