【问题标题】:Disable window messages (No WNDPROC call)禁用窗口消息(无 WNDPROC 调用)
【发布时间】:2017-03-05 11:28:13
【问题描述】:

所以我正在尝试为我的游戏编写一个切换全屏功能。

它有效.. 有点,问题是第一个 SetWindowLongPtr() 调用导致 WM_SIZE 消息排队并发送到我的 WNDPROC(在MSDN 我读取的窗口样式更改仅被缓存并且必须使用SetWindowPos() 虽然)。

SetWindowLongPtr(m_hWnd, GWL_STYLE, dwStyle);
SetWindowLongPtr(m_hWnd, GWL_EXSTYLE, dwExStyle);
SetWindowPos(m_hWnd, NULL, fullscreen ? 0 : window.left, fullscreen ? 0 : window.top, window.right, window.bottom, SWP_NOZORDER | SWP_FRAMECHANGED);
ShowWindow(m_hWnd, SW_SHOW);

当从窗口模式更改为全屏模式时,客户区的大小会调整为窗口矩形并像这样更新(所以现在“包含”条形图等)。 除了导致我的程序两次破坏 Vulkan 上下文之外,这还让我保存了错误的窗口尺寸以便稍后恢复到窗口模式(这是在 WM_SIZE 发生和游戏处于全屏模式时完成的)。

然后通过 SetWindowPos() 将其调整为正确的尺寸。

我的意思是我当然可以在应该丢弃 WM_SIZE 消息的时候加入一个 bool 来丢弃它,但我正在寻找一种更好的并且可能不那么笨拙的方法。 是否有暂时禁用窗口消息或仅用户定义 WNDPROC 的功能?

【问题讨论】:

  • 不需要禁用windows消息,而是正确处理它
  • 我只是这样做并且它有效:SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)DefWindowProc); SetWindowLongPtr(m_hWnd, GWL_STYLE, dwStyle); SetWindowLongPtr(m_hWnd, GWL_EXSTYLE, dwExStyle); SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)StdWndProc);
  • 这当然不是问题。水晶球说您只是忘记存储窗口状态。必需,因为它会告诉您在开始备份时需要如何重新创建窗口,假设您想再次以全屏模式恢复。

标签: windows winapi


【解决方案1】:

这是我用来打开和关闭全屏的功能。 我从Raymond Chen 得到了这个功能。 我不知道它是否会与 Vulkan 混淆,但它适用于 OpenGL。

WINDOWPLACEMENT GlobalWindowPosition = {sizeof(GlobalWindowPosition)};
void ToggleFullscreen(HWND WindowHandle)
{
    DWORD Style = GetWindowLong(WindowHandle, GWL_STYLE);
    if(Style & WS_OVERLAPPEDWINDOW)
    {
        MONITORINFO MonitorInfo = {sizeof(MonitorInfo)};
        if(GetWindowPlacement(WindowHandle, &GlobalWindowPosition) &&
           GetMonitorInfo(MonitorFromWindow(WindowHandle, MONITOR_DEFAULTTOPRIMARY),
                          &MonitorInfo))
        {
            SetWindowLong(WindowHandle, GWL_STYLE,
                          Style & ~WS_OVERLAPPEDWINDOW);
            SetWindowPos(WindowHandle, HWND_TOP,
                         MonitorInfo.rcMonitor.left, MonitorInfo.rcMonitor.top,
                         MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left,
                         MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top,
                         SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
        }
    }
    else
    {
        SetWindowLong(WindowHandle, GWL_STYLE, Style | WS_OVERLAPPEDWINDOW);
        SetWindowPlacement(WindowHandle, &GlobalWindowPosition);
        SetWindowPos(WindowHandle, NULL, 0, 0, 0, 0,
                     SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
                     SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
    }
}

【讨论】:

  • "if(Style & WS_OVERLAPPEDWINDOW)" - 肯定是个坏主意,请参阅 WS_OVERLAPPEDWINDOW 的定义。
  • @KonstantinL:您将样式与WS_OVERLAPPED 混淆了。那个被定义为0x0WS_OVERLAPPEDWINDOW 不是。 Raymond Chen 犯错的情况很少见。
  • @IInspectable,不,我知道区别。我的意思是应该是 if((Style & WS_OVERLAPPEDWINDOW) == WS_OVERLAPPEDWINDOW)。
猜你喜欢
  • 1970-01-01
  • 2010-12-15
  • 2018-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
  • 2013-10-03
相关资源
最近更新 更多