5

是否可以在WindowProc回调中捕获错误?try/catch不起作用。看起来__try __except和硬件异常(AV例如)也不起作用。


更新:

我发现确实可以在WindowProc回调中抛出异常并用catchblock outside捕获它WindowProc。经过测试并适用于Windows XP x86. 我在 WndProc 中发现了相关的问题 64bit exceptions silently fail这个问题似乎只存在于Windows 7 x64(并且根据该问题也存在于其他 x64 Windows 版本上)。

所以问题是有可能以某种方式抛出异常并用块外WindowProc捕获它吗?我安装了 microsoft hotfix,在注册表中设置为 1,我得到的最好的是,不是我的例外。catchWindowProcDisableUserModeCallbackFilterFATAL_USER_CALLBACK_EXCEPTION

4

3 回答 3

4

WindowProc的MSDN 文档包含有关从 WindowProc 引发/传播的异常的详细信息。似乎异常仅在 32 位版本的 Windows 中传播。

但是,您的原始问题与更新中的问题不同。第一个是关于在 WindowProc 中捕获异常,这将始终正常工作。第二个是关于从 WindowProc抛出异常。

我不确定第二个的有用性/必要性。窗口过程通常由于以下原因而被调用:

  1. 在消息循环中调用 DispatchMessage。在这种情况下不需要抛出异常,因为这样做只会导致应用程序退出。如果您遇到应该导致应用程序退出的错误,只需调用 PostQuitMessage(0)
  2. 调用发送消息。在这种情况下,您并不想抛出异常,因为窗口过程将在 UI 线程中执行,并且如果调用线程与 UI 线程不同,则调用线程无论如何都不会得到异常
  3. 直接调用窗口过程。在这种情况下,异常将正常工作。
于 2013-03-08T11:33:26.863 回答
2

使用 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);
于 2019-02-22T02:34:03.050 回答
0

Chronial给出了最好的答案。我会给出我认为有用的改进。

Chronial 的概念是允许在你的窗口过程中使用 cpp throw 机制,但不要让它在窗口过程之外传播;它在 C 库中调用并导致 64 位 Windows 上的未定义行为,即 64 位 win 7 或 Windows 8。而是在窗口过程中捕获异常,并将其保存在全局变量中,然后在 cpp main 中重新抛出功能和利用。有关代码示例,请参阅 Chronial 的答案。

这个概念很简单,但需要一些细节才能 100% 正确。

  • 要避免的一个陷阱是不要破坏你扔掉的窗户。您的代码将清除在 try 块中声明的所有对象,但您创建的窗口对象仍将处于活动状态并处理消息。即使您不再发送消息。如果您在窗口过程中使用指针,当您的代码在您的 catch 块中时,这些指针可能无效,而 Windows 仍在向您的窗口发送未销毁的消息。

  • 每个窗口过程都需要有这种try catch,保存异常技术。如果只准备您的顶级窗口,它将不起作用,但在其子窗口的过程中会引发异常。

  • 如果前两个非常明显,那么这个就有点不明显了。对于您的顶级窗口的过程;除了尝试捕获整个 switch 语句之外,您还应该尝试捕获 WM_CREATE 消息,如果捕获到异常则返回 -1。这将阻止创建窗口及其子项;并且一旦您重新抛出异常,您就不必破坏窗口。

  • 最后再次在顶级窗口的 WM_CREATE 消息中,运行创建子窗口的代码后,检查这些子窗口是否设置了全局 windowProcException 变量。子窗口的创建将运行它们自己的 windowProcedure,并且在这些窗口过程中捕获的异常不会自动传播到您的顶级窗口的过程。如果子窗口过程发生异常,从顶层窗口返回 -1 将取消所有窗口的创建。除非,您认为特定的子窗口不是超级重要。

    无效 createChildWindows();

    windowProcedure(hwnd,msg,wparam,lparam) { try { try { if(msg == WM_CREATE) { createChildWindows(); 返回 windowProcException ?-1:0;} } catch(...) { 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
     }
    

    }

于 2021-10-19T05:25:12.213 回答