C# Windows 截图上遇到过的坑
使用 GDI
https://blog.walterlv.com/post/win32-and-system-drawing-capture-window-to-bitmap
使用 PrintWindow
https://blog.walterlv.com/post/win32-capture-window-using-print-window.html
我的需求
我希望对使用目标窗体的句柄来进行截图,但截取后的结果是黑色或者透明的
于是我将需求放宽到对屏幕进行截图,就像qq截图那样
Graphics
中的CopyFromScreen
可以对屏幕区域进行截图,暂时满足我的需求
需求升级,对最小化的窗体进行截图
https://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=20651
这个项目貌似依然是gdi的操作,几乎所有的窗口都能截图,除了游戏窗口,但我的需求是恰恰希望对游戏窗口进行截图
但,windows是怎么做的?
鼠标移到任务栏下方,你可以实时看到程序内正在运行的内容
直到我在上面PrintWindow的注释中看到一个关键字:硬件加速
/ 注:使用 GDI+ 截取“使用硬件加速过的”应用时,截取到的部分是全黑的。
通过搜索,我发现了这个 DwmRegisterThumbnail api
https://stackoverflow.com/questions/56386968/detect-if-a-window-is-using-hardware-accelerated-graphic-context
通过这个api,我找到获取后台程序预览的方法
https://villavu.com/forum/showthread.php?t=101448
这几乎是实时映射,流畅无比
现在,全体起立,让我们把目标句柄设置为桌面
(好吧,它不工作,并没有出现我想象中OBS的那种效果)
private void btn1_Click_1(object sender, EventArgs e) { Console.WriteLine("Attempting to register thumbnail!"); var hWnd = new IntPtr(856296); int i = DwmRegisterThumbnail(this.Handle, hWnd, out thumb); Console.WriteLine("Succesfully registered thumbnail!"); UpdateThumb(); Console.WriteLine("Succesfully updated thumb!"); } #region DWM functions [DllImport("dwmapi.dll")] static extern int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb); [DllImport("dwmapi.dll")] static extern int DwmUnregisterThumbnail(IntPtr thumb); [DllImport("dwmapi.dll")] static extern int DwmQueryThumbnailSourceSize(IntPtr thumb, out PSIZE size); [DllImport("dwmapi.dll")] static extern int DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props); #endregion #region Constants static readonly int DWM_TNP_VISIBLE = 0x8; static readonly int DWM_TNP_OPACITY = 0x4; static readonly int DWM_TNP_RECTDESTINATION = 0x1; #endregion private IntPtr thumb; private void UpdateThumb() { if (thumb != IntPtr.Zero) { PSIZE size; DwmQueryThumbnailSourceSize(thumb, out size); DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES(); props.fVisible = true; props.dwFlags = DWM_TNP_VISIBLE | DWM_TNP_RECTDESTINATION | DWM_TNP_OPACITY; props.opacity = 255; props.rcDestination = new Rect(0,0, size.x, size.y); /* if (size.x < pictureBox.Width) props.rcDestination.Right = props.rcDestination.Left + size.x; if (size.y < pictureBox.Height) props.rcDestination.Bottom = props.rcDestination.Top + size.y; */ DwmUpdateThumbnailProperties(thumb, ref props); Console.WriteLine("Succesfully handled thumbnail stuff"); /* Console.WriteLine("Making BMP!"); Bitmap bmp = new Bitmap(size.x, size.y, PixelFormat.Format32bppArgb); Console.WriteLine("Made BMP; width = " + bmp.Width + ", height = " + bmp.Height); //bmp.Save("J:\\AutomationTool\\screenshot at " + DateTime.Now.ToString("HH-mm-ss tt") + ".png", ImageFormat.Png); bmp.Save(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\screenshot at " + DateTime.Now.ToString("HH-mm-ss tt") + ".png", ImageFormat.Png); Console.WriteLine("Saved bmp!"); bmp.Dispose(); */ } } #region Interop structs [StructLayout(LayoutKind.Sequential)] internal struct DWM_THUMBNAIL_PROPERTIES { public int dwFlags; public Rect rcDestination; public Rect rcSource; public byte opacity; public bool fVisible; public bool fSourceClientAreaOnly; } [StructLayout(LayoutKind.Sequential)] internal struct Rect { internal Rect(int left, int top, int right, int bottom) { Left = left; Top = top; Right = right; Bottom = bottom; } public int Left; public int Top; public int Right; public int Bottom; } [StructLayout(LayoutKind.Sequential)] internal struct PSIZE { public int x; public int y; } #endregion
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步