窗口处理中的异常
Exception in WindowProc
是否可以在回调WindowProc
捕获错误? try
/catch
不起作用。看起来__try
__except
和硬件异常(例如AV
)也不起作用。
更新:
我发现这确实可以在回调中抛出异常WindowProc
并使用WindowProc
外部的catch
块捕获它。经过测试并适用于Windows XP x86
.我发现 WndProc 中的相关问题 64 位异常静默失败该问题似乎只存在于Windows 7 x64
上(根据其他 x64 Windows 版本的问题)。
所以问题是是否有可能以某种方式在WindowProc
中抛出异常并用WindowProc
外catch
块捕获它?我安装了微软修补程序,在注册表中将DisableUserModeCallbackFilter
设置为 1,我得到的最好的是 FATAL_USER_CALLBACK_EXCEPTION
,而不是我的例外。
的 MSDN 文档包含有关从 WindowProc 引发/传播的异常的详细信息。似乎异常仅在 32 位版本的 Windows 中传播。
但是,您的原始问题与更新中的问题不同。第一个是关于在WindowProc中捕获异常,这将始终正常工作。第二个是关于从WindowProc抛出异常。
我不确定第二个的用处/必要性。窗口过程通常由于以下原因而被调用:
- 在消息循环中调用调度消息。在这种情况下,无需引发异常,因为这样做只会导致应用程序退出。如果遇到导致应用程序退出的错误,只需调用 PostQuitMessage(0)
- 调用发送消息。在这种情况下,您实际上并不想引发异常,因为窗口过程将在 UI 线程中执行,如果调用线程与 UI 线程不同,则调用线程无论如何都不会收到异常
- 直接调用窗口过程。在这种情况下,例外将正常工作。
使用 C++11,您可以通过手动转发任何异常来处理您的情况,如下所示:
#include <exception>
std::exception_ptr windowProcException = nullptr;
LRESULT windowProc(){
try {
yourcode();
catch(...){
windowProcException = std::current_exception();
}
}
然后,您可以在主循环中重新抛出异常,如下所示:
windowProcException = nullptr;
DispatchMessage();
if (windowProcException)
std::rethrow_exception(windowProcException);
Chronial给出了最好的答案。我将给出我认为有用的改进。
Chronial 的概念是允许在窗口过程中使用 cpp 抛出机制,但不要让它在窗口过程之外传播;这在 C 库中调用并导致 64 位窗口(即 64 位 win 7 或 windows 8)上的未定义行为。而是在窗口过程中捕获异常,并将其保存在全局变量中,然后在 cpp main 函数中重新抛出该变量并利用该变量。有关代码示例,请参阅Chronial的答案。
这个概念很简单,但需要一些细节才能 100% 正确。
-
要避免的一个陷阱是不要破坏你扔出的窗户。您的代码将清理 try 块中声明的所有对象,但您创建的窗口对象仍将处于活动状态并处理消息。即使您不再发送消息。如果在窗口过程中使用指针,则当您的代码位于 catch 块中时,这些指针可能无效,而窗口仍在向窗口泵送您未销毁的消息。
-
每个窗口过程都需要有这个尝试捕获,保存异常技术。如果仅准备了顶级窗口,但它将不起作用,但在其子窗口的过程中会引发异常。
-
如果说前两个超级明显,那么这个就有点不明显了。对于顶级窗口的程序;除了尝试捕获整个 switch 语句之外,您还应该尝试捕获WM_CREATE消息,如果捕获异常,则返回 -1。这将阻止创建窗口及其子窗口;并使您不必在重新抛出异常后销毁窗口。
最后,在 顶级窗口的WM_CREATE消息中,运行创建子窗口的代码后,检查这些子窗口是否设置了全局窗口ProcException变量。创建子窗口将运行其自己的 windowProcedure,在这些窗口过程中捕获的异常不会自动传播到顶级窗口的过程。如果在子窗口过程中发生异常,则从顶级窗口返回 -1 将取消创建所有窗口。除非您确定某个特定的子窗口不是超级重要。
void createChildWindows();
windowProcedure(hwnd,msg,wparam,lparam){尝试{尝试{if(msg == WM_CREATE){创建儿童窗口();返回窗口ProcException ?-1 : 0;}}捕获(...{windowProcException = std::current_exception();返回 -1;}
return DefWindowProc(hwnd,msg,wparam,lparam); } catch(...) { windowProcException = std::current_exception(); //MingGw won't complain if you don't return a value; //MSVC might //As far as I am concerned, we are throwing, //so any value returned is undefined //We must however be careful with WM_CREATE as that return code //dictates whether or not window creation continues }
}
- 为什么我应该在异常处理中使用std::cerr而不是std::cout
- 当我使用 C++ 中的 C# dll 来使用 Selenium 时,存在异常处理问题
- Firebase C++VS2018 SDL2-在Firebase::app::create(..)上执行异常处理
- 使用 stoi 功能进行异常处理
- 子系统中的异常处理:本机
- 与异常处理程序中的操作员<<不匹配
- 数组 C++ 上的异常处理程序
- 异常处理:如果用户输入不是三个特定字符之一
- C++ 异常处理错误输出
- 视觉 std::矢量无异常:警告 C4530:使用了C++异常处理程序,但未启用展开语义.指定 /EHsc
- C++交换机状态异常处理
- 在字符串类上的成员函数和out_of_range异常处理
- 奇怪的消息 (_Base_bitset::_M_do_to_ulong) 从溢出异常处理程序中打印出来
- 执行视觉工作室异常处理模式
- 为什么隐式转换在异常处理中从派生到基?
- C++执行期间的类成员函数错误/异常处理
- C++ 中未处理的异常处理程序
- 用户定义的异常处理
- C :ScopeGuard vs返回支票和异常处理
- 异常处理期间的类型解析