问题 窗体在后台(不聚焦)时,Picturebox不刷新

沙菲克

新成员
已加入
2018年5月30日
留言内容
3
编程经验
3-5
目的:通过捕获外部窗口(Directx游戏)的图像并使用计时器将其显示在图片框中,来镜像该窗口。

问题:当我的应用程序成为焦点时,一切都会很好!但是,如果将焦点切换到Directx游戏窗口,则图片框将停止刷新图像。当我再次专注于应用程序时,一切恢复正常。

局限性:即使我的应用程序在后台,我也需要PictureBox才能继续更新。

重要的: 在记事本,计算器,浏览器等窗口中不会发生这种情况。仅在Directx游戏窗口中会发生这种情况。

计时器以捕获图像并在图片框中显示:
C#:
private void timer_picBOX_refresh_Tick(object sender, EventArgs e)
{
   pictureBox1.BackgroundImage = PrintScreen.CaptureWindow(GAME_MainHandle);            
   pictureBox1.Refresh();            
}

捕获特定窗口的类:
C#:
public class class_ScreenCapture
    {
        public Image CaptureScreen()
        {
            return CaptureWindow(User32.GetDesktopWindow());
        }
     
        /// <summary>
        /// Creates an Image object containing a screen shot of a specific window
        /// </summary>
        public Image CaptureWindow(IntPtr handle, int imgX = 0, int imgY = 0, int largura = 0, int altura = 0)
        {
            // get te hDC of the target window
            IntPtr hdcSrc = User32.GetWindowDC(handle);
            // get the size
            User32.RECT windowRect = new User32.RECT();
            User32.GetWindowRect(handle, ref windowRect);

            if (largura == 0 || altura == 0)
            {
                largura = windowRect.right - windowRect.left;
                altura = windowRect.bottom - windowRect.top;
            }

            // create a device context we can copy to
            IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
            // create a bitmap we can copy it to,
            // using GetDeviceCaps to get the width/height
            IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, largura, altura);
            // select the bitmap object
            IntPtr hOld = GDI32.SelectObject(hdcDest, hBitmap);
            // bitblt over
            GDI32.BitBlt(hdcDest, 0, 0, largura, altura, hdcSrc, imgX, imgY, GDI32.SRCCOPY);
            // restore selection
            GDI32.SelectObject(hdcDest, hOld);
            // clean up 
            GDI32.DeleteDC(hdcDest);
            User32.ReleaseDC(handle, hdcSrc);

            // get a .NET image object for it
            Image img = Image.FromHbitmap(hBitmap);
            // free up the Bitmap object
            GDI32.DeleteObject(hBitmap);

            return img;
        }        

        /// <summary>
        /// Helper class containing Gdi32 API functions
        /// </summary>
        private class GDI32
        {

            public const int SRCCOPY = 0x00CC0020; // BitBlt dwRop parameter

            [DllImport("gdi32.dll")]
            public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest,
                int nWidth, int nHeight, IntPtr hObjectSource,
                int nXSrc, int nYSrc, int dwRop);
            [DllImport("gdi32.dll")]
            public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth,
                int nHeight);
            [DllImport("gdi32.dll")]
            public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
            [DllImport("gdi32.dll")]
            public static extern bool DeleteDC(IntPtr hDC);
            [DllImport("gdi32.dll")]
            public static extern bool DeleteObject(IntPtr hObject);
            [DllImport("gdi32.dll")]
            public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
        }

        /// <summary>
        /// Helper class containing User32 API functions
        /// </summary>
        private class User32
        {
            [StructLayout(LayoutKind.Sequential)]
            public struct RECT
            {
                public int left;
                public int top;
                public int right;
                public int bottom;
            }

            [DllImport("user32.dll")]
            public static extern IntPtr GetDesktopWindow();
            [DllImport("user32.dll")]
            public static extern IntPtr GetWindowDC(IntPtr hWnd);
            [DllImport("user32.dll")]
            public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
            [DllImport("user32.dll")]
            public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);

        }
    }
 
Last edited:

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,524
地点
悉尼,澳大利亚
编程经验
10+
您有做任何诊断问题的事情吗?您是否检查了计时器的Tick事件是否仍在引发和处理?您是否检查了CaptureWindow方法是否按预期执行了?不要只是阅读代码。调试它。

另外,是否有特定原因导致您使用PictureBox的BackgroundImage属性而不是Image属性?
 

沙菲克

新成员
已加入
2018年5月30日
留言内容
3
编程经验
3-5
您有做任何诊断问题的事情吗?您是否检查了计时器的Tick事件是否仍在引发和处理?您是否检查了CaptureWindow方法是否按预期执行了?不要只是阅读代码。调试它。

另外,是否有特定原因导致您使用PictureBox的BackgroundImage属性而不是Image属性?

就像我说的那样,当表单集中时,一切都可以正常工作。仅当窗体失去焦点(图片框保持静态且不更改图像)时,才会出现此问题。当我重新关注表单时,一切恢复正常。
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,524
地点
悉尼,澳大利亚
编程经验
10+
就像我说的那样,当表单集中时,一切都可以正常工作。仅当窗体失去焦点(图片框保持静态且不更改图像)时,才会出现此问题。当我重新关注表单时,一切恢复正常。

我知道你这么说我是第一次读。我不确定为什么会重复你已经发布的内容而忽略我所说的一切,这是一个好主意。
 

沙菲克

新成员
已加入
2018年5月30日
留言内容
3
编程经验
3-5
我知道你这么说我是第一次读。我不确定为什么会重复你已经发布的内容而忽略我所说的一切,这是一个好主意。

很抱歉,如果它看起来令人反感,当在线翻译人员翻译时,某些语言形式似乎对其他人来说是侵略性的(无解释)。以我的语言来说,通常以"like I said"。但这没问题。对不起

我的应用程序的整个代码在后台运行时仍可继续工作,逻辑部分不会冻结。冻结的是视觉部分(UI)。一旦将焦点转到应用程序窗口,它就会恢复为"alive"从图像中可以清楚地看到,代码在后台继续运行。

当我专注于Web浏览器,记事本,计算器等窗口时,不会发生这种冻结。当这些窗口类型成为焦点时,我的应用程序的视觉UI会继续"alive".

仅当我专注于游戏窗口(Directx游戏)时才会发生冻结。当游戏窗口成为焦点时,我可以看到应用程序的窗口冻结。该问题是由这种类型的窗口强加在窗口上的任何模式(例如winform类型等)引起的。

在我看来,这种方式的开始是要知道为什么这种类型的窗口会阻止Winform窗口继续刷新外观。

您是否知道在打开游戏窗口时鼠标只限于该窗口的边缘吗?是否有必要按ALT + TAB到窗口之外?我正在谈论的就是这种窗口。
 
最佳 底部