欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 产业 > C# 活动窗体截图:基于 Win32 API 的实现

C# 活动窗体截图:基于 Win32 API 的实现

2025/5/16 18:27:32 来源:https://blog.csdn.net/qq_41184334/article/details/147985849  浏览:    关键词:C# 活动窗体截图:基于 Win32 API 的实现
1. 核心功能与技术栈

该截图功能类 ScreenShotClass 基于 Win32 API 实现了两种截图方式:

  • CopyFromScreen 方法:利用 Graphics.CopyFromScreen 直接截取屏幕区域。
  • BitBlt 方法:通过 GDI+ 的位图块传输(BitBlt)实现窗口截图。

核心依赖的 Win32 API 包括:

  • user32.dll:获取窗口句柄、窗口矩形区域。
  • dwmapi.dll:获取窗口扩展边界(适用于现代 Windows 窗口阴影等效果)。
  • gdi32.dll:执行位图复制操作(BitBlt)。

DwmGetWindowAttribute与 GetWindowRect区别
GetWindowRect 返回窗口边框矩形(不含阴影等视觉扩展),而 DwmGetWindowAttribute 能获取实际显示区域,确保截图完整。 

2. 两种截图方式对比
方法实现原理
CopyFromScreen使用 Graphics.CopyFromScreen 直接从屏幕坐标复制像素到目标位图。
BitBlt通过 GetWindowDC 获取窗口 DC,再用 BitBlt 复制像素到目标 DC(位图)。

适用场景与限制

  • 适用场景
    • 截取当前活动窗口或指定窗口内容。
    • 需要包含窗口边框、阴影等视觉元素的精确截图。
  • 限制
    • 性能影响:频繁调用 BitBlt 可能影响 UI 线程,建议异步执行。
    • 兼容性:仅适用于 Windows 系统,依赖 Win32 API。
3. 使用示例 
// 截取前台窗口(使用 CopyFromScreen)
try {Image screenshot = ScreenShotClass.Screenshot_CopyFromScreen();screenshot.Save("screenshot.png", System.Drawing.Imaging.ImageFormat.Png);
} catch (Exception ex) {Console.WriteLine($"截图失败:{ex.Message}");
}// 截取指定窗口(使用 BitBlt)
IntPtr targetHandle = ...; // 获取目标窗口句柄(如通过 FindWindow)
Image screenshot = ScreenShotClass.Screenshot_CopyFromDC(targetHandle);
完整代码:
using System;
using System.Drawing;
using System.Runtime.InteropServices;namespace CSharp学习之截图功能
{public static class Win32Api{// 获取前台窗口句柄[DllImport("user32.dll")]public static extern IntPtr GetForegroundWindow();// 获取窗口属性(这里用于获取扩展框架边界)[DllImport("dwmapi.dll")]public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out RECT pvAttribute, int cbAttribute);// 获取窗口的矩形区域(包括边框、标题栏等)[DllImport("user32.dll")]public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);// 获取指定窗口的设备上下文(DC)[DllImport("user32.dll")]public static extern IntPtr GetWindowDC(IntPtr hWnd);// 释放设备上下文(DC)[DllImport("user32.dll")]public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);// 执行位块传输(BitBlt)操作,用于复制图像[DllImport("gdi32.dll")]public static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);// 定义RECT结构体,用于表示矩形区域[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;}// DWMWA_EXTENDED_FRAME_BOUNDS常量public const int DWMWA_EXTENDED_FRAME_BOUNDS = 9;// SRCCOPY表示源图像直接复制到目标设备上下文public const int SRCCOPY = 0x00CC0020;}public static class ScreenShotClass{public static Image Screenshot_CopyFromScreen(){IntPtr handle = Win32Api.GetForegroundWindow();Win32Api.RECT rect;int result = Win32Api.DwmGetWindowAttribute(handle, Win32Api.DWMWA_EXTENDED_FRAME_BOUNDS, out rect, Marshal.SizeOf(typeof(Win32Api.RECT)));if (result != 0){throw new InvalidOperationException("无法获取窗口边界");}Bitmap bmp = new Bitmap(rect.Width, rect.Height);try{using (Graphics g = Graphics.FromImage(bmp)){g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size);}return bmp;}catch(Exception ex) {// 如果发生异常,确保释放Bitmapbmp?.Dispose();throw new InvalidOperationException($"截图失败: {ex.Message}");}}public static Image Screenshot_CopyFromScreen(IntPtr handle){Win32Api.RECT rect;int result = Win32Api.DwmGetWindowAttribute(handle, Win32Api.DWMWA_EXTENDED_FRAME_BOUNDS, out rect, Marshal.SizeOf(typeof(Win32Api.RECT)));if (result != 0){throw new InvalidOperationException("无法获取窗口边界");}Bitmap bmp = new Bitmap(rect.Width, rect.Height);try{using (Graphics g = Graphics.FromImage(bmp)){g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size);}return bmp;}catch (Exception ex){// 如果发生异常,确保释放Bitmapbmp?.Dispose();throw new InvalidOperationException($"截图失败: {ex.Message}");}}public static Image Screenshot_CopyFromDC(){IntPtr handle = Win32Api.GetForegroundWindow();Win32Api.RECT rect;Win32Api.GetWindowRect(handle, out rect);Bitmap bmp = new Bitmap(rect.Width, rect.Height);Graphics g = null;IntPtr hdcSrc = IntPtr.Zero;IntPtr hdcDest = IntPtr.Zero;try{g = Graphics.FromImage(bmp);hdcDest = g.GetHdc();hdcSrc = Win32Api.GetWindowDC(handle);if (hdcSrc == IntPtr.Zero){throw new InvalidOperationException("无法获取窗口设备上下文");}bool success = Win32Api.BitBlt(hdcDest, 0, 0, rect.Width, rect.Height, hdcSrc, 0, 0, Win32Api.SRCCOPY);if (!success){throw new InvalidOperationException("BitBlt 调用失败");}return bmp;}catch (Exception ex){// 释放资源bmp?.Dispose();throw new InvalidOperationException($"截图失败: {ex.Message}");}finally{// 确保释放资源if (hdcDest != IntPtr.Zero && g != null){g.ReleaseHdc(hdcDest);}if (hdcSrc != IntPtr.Zero){Win32Api.ReleaseDC(handle, hdcSrc);}g?.Dispose();}}public static Image Screenshot_CopyFromDC(IntPtr handle){Win32Api.RECT rect;Win32Api.GetWindowRect(handle, out rect);Bitmap bmp = new Bitmap(rect.Width, rect.Height);Graphics g = null;IntPtr hdcSrc = IntPtr.Zero;IntPtr hdcDest = IntPtr.Zero;try{g = Graphics.FromImage(bmp);hdcDest = g.GetHdc();hdcSrc = Win32Api.GetWindowDC(handle);if (hdcSrc == IntPtr.Zero){throw new InvalidOperationException("无法获取窗口设备上下文");}bool success = Win32Api.BitBlt(hdcDest, 0, 0, rect.Width, rect.Height, hdcSrc, 0, 0, Win32Api.SRCCOPY);if (!success){throw new InvalidOperationException("BitBlt 调用失败");}return bmp;}catch (Exception ex){// 释放资源bmp?.Dispose();throw new InvalidOperationException($"截图失败: {ex.Message}");}finally{// 确保释放资源if (hdcDest != IntPtr.Zero && g != null){g.ReleaseHdc(hdcDest);}if (hdcSrc != IntPtr.Zero){Win32Api.ReleaseDC(handle, hdcSrc);}g?.Dispose();}}}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词