Question

Is it possible to catch error inside WindowProc callback? try / catch doesnt work. Looks like __try __except and also hardware exception (AV, for example) doesnt work also.


Update:

I figured out that indeed this is possible to throw exception in WindowProc callback and catch it with catch block outside WindowProc. Tested and works on Windows XP x86. I found releated question 64bit exceptions in WndProc silently fail The problem seems only exist on Windows 7 x64 (and according to that question on other x64 Windows versions too).

So the question is it possible somehow to throw exception in WindowProc and catch it with catch block outside WindowProc? I installed microsoft hotfix, set DisableUserModeCallbackFilter to 1 in registry and best I get is FATAL_USER_CALLBACK_EXCEPTION, not my exception.

Was it helpful?

Solution

The MSDN documentation for WindowProc has detailed info on exceptions thrown/propagated from WindowProc. It seems that exceptions are only propagated in 32-bit versions of Windows.

However, your original question is different from the question in your update. The first one was about catching exceptions in WindowProc, and that will work fine always. The second one is about throwing exceptions from WindowProc.

I'm not sure about the usefulness/necessity of the second one. A window procedure is normally called as a result of:

  1. Calling DispatchMessage in the message loop. There's no need to throw an exception in this case because doing so would just cause the application to exit. If you encounter an error that should cause the application to exit, just call PostQuitMessage(0)
  2. Calling SendMessage. In this case you don't really want to throw exceptions because the window procedure will be executed in the UI thread, and if the calling thread is different from the UI thread, the calling thread won't get the exception anyway
  3. Calling the window procedure directly. Exceptions will work fine in this case.

OTHER TIPS

With C++11, you could handle your situation by manually forwarding any exceptions like this:

#include <exception>
std::exception_ptr windowProcException = nullptr;

LRESULT windowProc(){
  try {
    yourcode();
  catch(...){
    windowProcException = std::current_exception();
  }   
}

You can then rethrow the exception in your mainloop like this:

windowProcException = nullptr;
DispatchMessage();
if (windowProcException)
  std::rethrow_exception(windowProcException);

Chronial gave the best answer. I will give what I think is a useful refinement.

Chronial's concept was to allow use of cpp throw mechanism inside your window procedure, but dont let it propogate outside of the window procedure; which is called in a C library and leads to undefined behaviour on 64 bit windows, namely 64 bits win 7 or windows 8. Instead catch the exception within the window procedure, and save it in a global variable, which you rethrow in your cpp main function and make use of. See Chronial's answer for code example.

The concept is simple, but requires a bit of detail to get 100% right.

  • One pitfall to avoid is not destroying the window you throwed from. Your code will clean up all objects declared in the try block, but the window object you create will still be alive and handling messages. Even though you are no longer dispatching messages. If you use pointers in the window procedure, these pointers may be invalid when your code is in your catch block, while windows is still pumping messages to your window which you didn't destroy.

  • Every window procedure needs to have this try catch, save exception technique. It won't work if only your top level window is prepared, but exceptions are thrown in it's child window's procedure.

  • If the first two were super obvious, this one is slightly non-obvious. For your top level window's procedure; in addition to try catch the entire switch statement, you should also try catch the WM_CREATE message, and return -1 if you caught an exception. This will prevent the window and its children from being created; and save you from having to destroy the window once you rethrow the exception.

  • Lastly once again in your WM_CREATE message of your top level window, after running the code that created child windows, check if those child windows set the global windowProcException variable. Creation of child windows will run their own windowProcedure, and exceptions caught in those window procedures will not automatically propogate to your top level window's procedure. If exceptions happened in the child's window procedure, returning -1 from the top level window will cancel creation of all windows. Unless, you decide that a particular child window was not super important.

    void createChildWindows();

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

    }

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top