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
posted @ 2022-05-12 14:26  trykle  阅读(1288)  评论(0编辑  收藏  举报