gpt4 book ai didi

c++ - 如何在 WM_PAINT 处理程序中捕获断言()?

转载 作者:行者123 更新时间:2023-12-02 09:59:59 25 4
gpt4 key购买 nike

我有 MSVC 2019、vc142 x64、SDK 10.0.18362.0、WINAPI 游戏项目、已启用 JIT 调试、_DEBUG被定义为。我用assert()来自标准库#include <cassert>assert(expr)调用扩展到 _wassert 。 if 测试代码assert(false)放置在除 WM_PAINT 之外的任何位置处理程序中,将显示一个带有中止/重试/忽略选项的窗口及其预期行为。

但万一我有 assert(false)case WM_PAINT ,未显示断言窗口。程序只是中止并写入 stderr。问题是很多游戏逻辑是从 WM_PAINT 调用的。的处理程序(例如 Core::Update(dt) ),并且我无法捕获我的代码生成的任何断言。

WndProc代码:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
assert(false);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

程序向此消息发送垃圾邮件并且不会停止:

Program: ...t\source\repos\Test3\x64\Debug\WindowsProject1.exe
File: C:\Users\b2soft\source\repos\Test3\...\Windows...ct1.cpp
Line: 149

Expression: false

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts

(Press Retry to debug the application - JIT must be enabled)Assertion failed!

我希望拥有带有中止/重试/忽略选项的相同调试窗口,即使 assert()WM_PAINT 解雇

最佳答案

处理WM_PAINT消息时我们必须小心。 Windows 管理器不断监视屏幕的哪些部分需要重绘,并将此信息添加到窗口的更新区域。当调用GetMessagePeekMessage并且没有更高优先级的消息时,将为具有非空更新区域的窗口生成WM_PAINT消息。

BeginPaint 使用更新区域来准备窗口的设备上下文以限制绘画区域。清除此更新区域后,窗口甚至可以在开始绘制当前区域之前收集新区域进行绘制。

如果我们省略 BeginPaint 调用,则不会清除更新区域(除非我们使用替代解决方案,例如 ValidateRect)和 WM_PAINT随时准备发送。这会导致无休止的 WM_PAINT 消息流和高处理器使用率。请记住,DefWindowProc 在内部处理 WM_PAINT,因此只有当您显式拦截 WM_PAINT 消息时,这些问题才会出现。

WM_PAINT 处理程序中不调用 BeginPaint 或在调用 BeginPaint 之前使用 assert 会导致消息框和 WM_PAINT< 之间出现不必要的交互 消息。根据设置,assert 可以显示启动新(嵌套)消息循环的消息框。当要显示由 assert 构建的消息框时,会再次生成原始窗口的 WM_PAINT。这会一次又一次地导致下一个嵌套循环。 32 次嵌套调用 MessageBox 失败后,程序被中止(通过调用 abort 函数)。

assert 停止递归循环嵌套之前放置 BeginPaint (或任何清除更新区域的替代方法)(至少直到下一个 WM_PAINT被调度)并且assert可以正确显示消息框。

因此,如果您想在 WM_PAINT 处理程序中使用 assert,请将其放在 BeginPaintValidateRect(hWnd, NULL).

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// assert here could lead to abort

switch (message)
{
case WM_PAINT:
{
// assert here could lead to abort

PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// Update region cleared, no WM_PAINT will be generated
// until some event creates new dirty area

// assert here have chance to be handled properly
assert(false);

EndPaint(hWnd, &ps);

// assert here have chance to be handled properly
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}

// assert here have chance to be handled properly

return 0;
}

请记住,这是基于观察到的行为,而不是基于任何特定文档,因此您可能会根据设置、运行时版本甚至是否附加调试器获得不同的结果。

使用 VC2017 x86 调试版本 ucrt 10.0.17763.0 在 Windows 10 上完成的测试

我个人并不知道这个限制,而且看起来有点糟糕。特别是对于放置在窗口过程顶部的最终断言。幸运的是,附加的调试器至少在输出窗口中显示错误,并且我从未在没有附加调试器的情况下运行调试版本。

关于c++ - 如何在 WM_PAINT 处理程序中捕获断言()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63107372/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com