如何在C#中截取含滚动区域的完整活动窗口截图
解决C# .NET捕获活动窗口完整滚动区域截图的问题
我明白你的需求——要截的不只是窗口当前显示的部分,而是包括滚动条后面藏着的所有内容对吧?你现在的代码用PrintWindow结合GetWindowRect只能拿到窗口的可见区域,要搞定完整滚动内容的截图,我们得调整一下获取尺寸的方式,并且确保窗口把全部内容都渲染到Bitmap上。
问题分析
你当前代码里的GetWindowRect(hwnd, out rc)获取的是窗口在屏幕上的可见边界,而不是窗口内部可滚动区域的完整大小。所以即使你用这个尺寸创建Bitmap,PrintWindow也只会绘制可见的那部分。
解决方案思路
我们需要:
- 获取窗口客户区的完整可滚动尺寸(通过滚动条信息计算)
- 创建对应大小的Bitmap来容纳全部内容
- 让窗口把整个可滚动区域绘制到这个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
相关产品推荐
相关产品推荐

