Direct2D : Unhandled Exception In WM_RESIZE switch

2020-04-07 09:47发布

问题:

I am creating a Simple Direct2D Application. Unfortunately it is giving an unhandled exception. The function where it is taking place:

    void DemoApp::OnResize(UINT width, UINT height)
{
    if (m_pRenderTarget) <----|****The exception occurs here.....****
    {
        // Note: This method can fail, but it's okay to ignore the
        // error here, because the error will be returned again
        // the next time EndDraw is called.
        m_pRenderTarget->Resize(D2D1::SizeU(width, height));
    }
}

And the code snippet calling OnResize() is:

DemoApp *pDemoApp = reinterpret_cast<DemoApp *>(static_cast<LONG_PTR>(
            ::GetWindowLongPtrW(
                hwnd,
                GWLP_USERDATA
            )));

        bool wasHandled = false;

        if (pDemoApp)
        {
            switch (message)
            {
            case WM_SIZE:
            {
                UINT width = LOWORD(lParam);
                UINT height = HIWORD(lParam);
                pDemoApp->OnResize(width, height);
            }
            result = 0;
            wasHandled = true;
            break;
/*rest of switch case*/
       }

The exception says: Unhandled exception at 0x00007FF6BE402CCA in Simple Direct2D application.exe: 0xC000041D: An unhandled exception was encountered during a user callback. occurred

Exception screenshot:

As soon as I start to debug, the program, it gives the exception.I even copied the program word by word from the site.As I am new to the world of DirectX, I am clueless about the exception. What should I do?

回答1:

I've compiled that sample. It works in 32-bit builds, crashes in 64-bit builds.

The error is in Microsoft's sample code and is unrelated to Direct2D.

They pass this into SetWindowLongPtr, in combination with PtrToUlong macro for type conversion. In 64-bit builds, this is 8-bytes long, SetWindowLongPtr also accepts 8 bytes, however PtrToUlong macro converts to unsigned long which is only 4 bytes. So PtrToUlong macro drops higher 4 bytes from this pointer, and the app fails spectacularly.

You can fix by replacing PtrToUlong( pDemoApp ) with (LONG_PTR)pDemoApp

P.S. I think the root cause is, MS pretends very hard Win32 platform is obsolete, pushes developers to UWP instead. That’s why in their DirectX and Direct2D samples, they don’t use their own ATL, because it’s desktop-only library. Using ATL would dramatically simplify these samples: CComPtr for interface pointers, CWindowImpl for windows creation and message handling, and lots more.

Update: here's a better sample.



回答2:

Since you are getting an exception in a point where you are doing nothing but reading a member variable, the only possible reason I can think of is that your this pointer is garbage. While it is common for window message handlers to be called before SetWindowLong has been called, in which case the value returned by GetWindowLong is null, you (correctly) check that it isn't, and this is confirmed by your screenshot (as well as the fact that it's garbage). The possible options left are that either what you pass to SetWindowLong is not a pointer to a valid DemoApp object, or that it once was but the object is no longer valid when the message is received. So, as an answer to your question, you should check that

  1. the value you pass to SetWindowLong really is a valid pointer to a DemoApp
  2. the DemoApp whose pointer you pass is in the heap or a global variable, not a local variable that can go out of scope during the lifetime of the window
  3. you don't delete your DemoApp object, if it is heap allocated, during the lifetime of your window

Also, you are explicitly using the Unicode version of GetWindowLongPtr, which is also used in the original example (with no explanation why). Check your project settings that you are compiling an Unicode application.