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