multithreading - 检测窗口恢复操作即将开始

标签 multithreading winapi event-handling directx

WM_GETMINMAXINFO 在最大化操作即将开始时生成,WM_SIZE 在最大化操作完成时生成。

WM_SIZE 也会在恢复操作完成时生成。

但是如何检测窗口恢复操作即将开始?


我需要检测窗口即将恢复的确切时刻,而不是已经恢复的时刻。我正在开发多线程 DirectX 应用程序。我在专用的辅助线程中渲染。当窗口即将开始最大化或恢复时,我需要更改渲染后缓冲区大小(DirectX Device Reset)。我只能从主线程调整后台缓冲区的大小,因此我使用关键部分与渲染线程同步。问题是我无法中断渲染线程中的“当前”操作,并且当最大化或恢复操作即将开始时,我会等到当前的“当前”操作完成,然后才开始调整大小(最大化/恢复)。如果您太晚更改后台缓冲区大小(当最大化/恢复操作完成时(WM_SIZE 消息)),您会注意到旧帧以错误的大小绘制(图像被拉伸(stretch))。

最佳答案

嗯,很高兴看到有人仍在思考这些问题。这些小事情,例如调整大小时图像拉伸(stretch)一秒,将专业外观的应用程序与卧室编码的应用程序区分开来。

在我的旧代码中,我发现了您可能会感兴趣的技巧。 首先,您可以检查 WM_SYSCOMMAND:

        case WM_SYSCOMMAND:
           {
               switch (wParam)
               {
               case SC_MAXIMIZE:
                   std::cout << "Going to MAXIMIZE: " << std::endl;
                   break;

               case SC_MINIMIZE:
                   std::cout << "Going to MINIMIZE: " << std::endl;

                   break;

               case SC_RESTORE:
                   std::cout << "Going to RESTORE: " << std::endl;
                   break;


               default:
                   break;
               }
               return DefWindowProc(m_hWnd, msg, wParam, lParam);
           }

但问题是,当用户双击标题栏时,它无法捕获最大化/恢复事件。

所以我在解析WM_WINDOWPOSCHANGING时发现了一个小技巧。

首先让我们做一些有趣的研究。我们阅读文档 herehere我们发现:

WM_WINDOWPOSCHANGING message sent to a window whose size, position, or place in the Z order is ABOUT to change

因为在通用调试器中调试事件几乎是不可能的(如果调试器经常更改窗口的 z 顺序,您将如何测试?),因此出于测试目的,我们将使用 int main() 制作一个小控制台应用程序,我们像平常一样初始化一个窗口(我们可以从 GetModuleHandle(0); 获得 HINSTANCE)。所以我们同时有一个控制台和一个窗口。在窗口过程中,我们捕获 WM_WINDOWPOSCHANGING 并打印信息,它会告诉我们,控制台:

        case WM_WINDOWPOSCHANGING:
        {
            WINDOWPOS* wp = ((WINDOWPOS*)lParam);

            // We checking current state which is saved in member (or global) bools
            // Set them checking WM_SIZE before
            if (m_bMaximized)
            {
                std::cout << "Currently MAXIMIZED: ";
            }
            else if (m_bMinimized)
            {
                std::cout << "Currently MINIMIZED: ";
            }
            else
            {
                std::cout << "Currently NORMAL: ";
            }

            dbgPrintPositionCurrent();

            std::cout << "Going to change to: ";
            dbgPrintPosition(wp->x, wp->y, wp->cx, wp->cy, wp->flags);
            std::cout << std::endl << std::endl;

            return DefWindowProc(m_hWnd, msg, wParam, lParam);
        }

查看实用函数here .

当我们玩得足够多时,我们现在可以让它变得有用:

                bool bFrameChanged = ((wp->flags) & SWP_FRAMECHANGED) > 0;
            bool bNoCopyBits = ((wp->flags) & SWP_NOCOPYBITS) > 0;
            bool bNormal = (!m_bMaximized) && (!m_bMinimized);

            // from maximized
            if(m_bMaximized && bFrameChanged && !bNoCopyBits)
            {
                std::cout << " MAXIMIZED -> NORMAL " << std::endl;
            }
            if (m_bMaximized && bFrameChanged && bNoCopyBits)
            {
                std::cout << " MAXIMIZED -> MINIMIZED " << std::endl;
            }

            // from normal states
            if (bNormal && bFrameChanged && !bNoCopyBits)
            {
                std::cout << " NORMAL -> MAXIMIZED " << std::endl;
            }
            if (bNormal && bFrameChanged && bNoCopyBits)
            {
                std::cout << " NORMAL -> MINIMIZED"  << std::endl;
            }

            // from minimized
            if(m_bMinimized && bFrameChanged)
            {
                std::cout << " MINIMIZED -> MAXIMIZED " << std::endl;
            }
            if(m_bMinimized && m_bMaximized && bFrameChanged)
            {
                std::cout << " MINIMIZED -> MAXIMIZED " << std::endl;
            }


            return DefWindowProc(m_hWnd, msg, wParam, lParam);

我真的不确定这是最简单的还是正确的方法。但它现在有效 =) 另外,我认为您的应用程序并不关心具体发生了什么:最大化、恢复或调整大小。它只关心大小是否发生变化,因此您需要调整缓冲区大小/重新创建交换链等...

希望对您有帮助!快乐编码!

关于multithreading - 检测窗口恢复操作即将开始,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16204488/

相关文章:

c - 绘制溢出到顶级窗口之外的子窗口

java - java中带定时器的图形绘图仪

c++ - 如何检查 win32 exe 文件是否已经在运行? (使用 win32 API 代码)

java - 如何在fastutils中实现线程安全或不可变的集合?

c++ - 哪些策略可以有效地处理异构多核架构上的并发读取?

c# - Thread.Sleep的线程安全替代方案,允许C#中的浏览器事件

winapi - 在 Vista/Aero 上处理 WM_NCPAINT "breaks"DWM 玻璃渲染

java - JavaFx 的 setOnAction 方法在幕后是如何工作的?

c# - 如何使用控件数组在 C# 中获取给定对象的数组索引?

Java volatile 变量多线程行为