c++ - 遵循官方 direct2d 示例但出现访问冲突错误

标签 c++ win32gui direct2d

<分区>

按照 Direct2D ( https://learn.microsoft.com/en-us/windows/win32/direct2d/direct2d-quickstart ) 的官方教程使用 Visual Studio 2019 创建示例项目。在 x86 中运行代码时,将平台更改为 x64 时一切正常,我收到一条错误消息:“异常抛出:读取访问冲突。在 SampleD2D.cpp 中。 (该行在下面的代码中被注释掉了)

错误是:

Exception thrown: read access violation.
this was 0xBB18F6E8.
    LRESULT CALLBACK DemoApp::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    LRESULT result = 0;

    if (message == WM_CREATE)
    {
        LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
        DemoApp* pDemoApp = (DemoApp*)pcs->lpCreateParams;

        ::SetWindowLongPtrW(
            hwnd,
            GWLP_USERDATA,
            PtrToUlong(pDemoApp)
        );

        result = 1;
    }
    else
    {
        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); // throw the error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            }
            result = 0;
            wasHandled = true;
            break;

            case WM_DISPLAYCHANGE:
            {
                InvalidateRect(hwnd, NULL, FALSE);
            }
            result = 0;
            wasHandled = true;
            break;

            case WM_PAINT:
            {
                pDemoApp->OnRender();
                ValidateRect(hwnd, NULL);
            }
            result = 0;
            wasHandled = true;
            break;

            case WM_DESTROY:
            {
                PostQuitMessage(0);
            }
            result = 1;
            wasHandled = true;
            break;
            }
        }

        if (!wasHandled)
        {
            result = DefWindowProc(hwnd, message, wParam, lParam);
        }
    }

    return result;
}

最佳答案

不幸的是,我不是 WinAPI 专家,但出于好奇,我用谷歌搜索了一下。现在,我很确定 OP 问题:

        ::SetWindowLongPtrW(
            hwnd,
            GWLP_USERDATA,
            PtrToUlong(pDemoApp)
        );

特别是 PtrToUlong(pDemoApp) .

这可能适用于 32 位应用程序但不适用于 64 位应用程序。

long在 MS VC++ 32 位中——适用于 x86 和 x64 平台。

因此,将指针转换为 longunsigned long有利于在 x64 上使其出错(只要高 32 位不为 0——这可能很难预测)。

谷歌搜索这个方向我发现例如PtrToUlong Q/A on gamedev.net有了这个(旧的)答案:

msdn, try to avoid using these because you are casting a pointer into an unsigned long. This may work correctly on 32-bit executables but if you compile in 64-bit you may have problems.

这支持了我的怀疑。

根据 MS 文档。 SetWindowLongPtrW function ,签名是:

LONG_PTR SetWindowLongPtrW(
  HWND     hWnd,
  int      nIndex,
  LONG_PTR dwNewLong
);

所以,这应该可以解决它:

        ::SetWindowLongPtrW(
            hwnd,
            GWLP_USERDATA,
            reinterpret_cast<LONG_PTR>(pDemoApp)
        );

请注意 MS 文档。关于 LONG_PTR :

LONG_PTR

A signed long type for pointer precision. Use when casting a pointer to a long to perform pointer arithmetic.

This type is declared in BaseTsd.h as follows:

C++

#if defined(_WIN64)
 typedef __int64 LONG_PTR; 
#else
 typedef long LONG_PTR;
#endif

顺便说一句。我也没看懂

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

根据文档。 GetWindowLongPtrW function , 函数返回 LONG_PTR .那么,为什么 static_cast<LONG_PTR> ?如果绝对必要,类型转换应该始终是最后的手段。 (虽然,我承认没有 WinAPI 可能无法使用。)

关于c++ - 遵循官方 direct2d 示例但出现访问冲突错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57522391/

相关文章:

c++ - ID2D1HwndRenderTarget 总是有黑色背景而不是透明

bitmap - DirectX -- 将四边形渲染到 WicBitmapRenderTarget (SharpDX)

c++ - 使用 Qt 信号和槽 (C++) 在两个 child 之间传输数据

c++ - 如何乘以矩阵?

c++ - 选项卡在 Win32 (C++) 中损坏

c++ - 读取文件 on.get 函数时程序卡住

c++ - 指定不绑定(bind)临时对象的 `const int&`

c++ - C++ 中的数组和覆盖 - 我可以重用同一个对象吗?

python - python 如何在任务栏弹出最小化程序

c++ - 为什么在D3D11下绘制D2D图?