c++ - RenderTarget->GetSize 不工作

标签 c++ gcc windows-7-x64 direct2d

为了学习我自己的 Direct2D,我正在关注 this example来自 MSDN。

但是我有一个问题。调用 D2D1_SIZE_F rtSize = m_pRenderTarget->GetSize(); 始终返回大小 0,0,并且在调试器中导致 DrawLine 调用异常。如果我省略 GetSize() 调用并使用有效值填充 D2D1_SIZE_F 结构,它就可以工作。

初始化渲染目标的相关代码为:

    RECT rc;
    GetClientRect(m_hwnd, &rc);

    D2D1_SIZE_U size = D2D1::SizeU(
        rc.right - rc.left,
        rc.bottom - rc.top
        );

    // Create a Direct2D render target.
    hr = m_pDirect2dFactory->CreateHwndRenderTarget(
        D2D1::RenderTargetProperties(),
        D2D1::HwndRenderTargetProperties(m_hwnd, size),
        &m_pRenderTarget
        );

我已经通过调试器验证过有效值的大小。

调用GetSize的绘图代码部分:

    m_pRenderTarget->BeginDraw();

    m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());

    m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
    D2D1_SIZE_F rtSize = m_pRenderTarget->GetSize();
    // Draw a grid background.
    int width = static_cast<int>(rtSize.width);
    int height = static_cast<int>(rtSize.height);

    for (int x = 0; x < width; x += 10)
    {
        m_pRenderTarget->DrawLine(
            D2D1::Point2F(static_cast<FLOAT>(x), 0.0f),
            D2D1::Point2F(static_cast<FLOAT>(x), rtSize.height),
            m_pLightSlateGrayBrush,
            0.5f
            );
    }

所以我的问题是为什么 GetSize() 会返回 0,0 并在稍后导致 AV?

顺便说一句:我正在使用: Windows 7 旗舰版 64 位 代码:: block IDE TDM-GCC-64 gcc编译器v4.8.1 我在 Unicode 模式下编译 #define UNICODE 无论我编译为 32 位还是 64 位,都会出现问题(是的,我对 64 位模式做了一些小调整,以确保我有一个指向 WndProc 中应用程序对象的有效指针)

最佳答案

Why does GetSize() return 0,0 and causes an AV later on?

因为 GCC/MinGW-W64 生成的 GetSize 调用与 d2d1.dll 中实现的调用约定不匹配。 GetSize 的返回类型 D2D_SIZE_F 是一个结构体。根据Microsoft Docs有两种方法可以从函数返回结构:

User-defined types can be returned by value from global functions and static member functions. To return a user-defined type by value in RAX, it must have a length of 1, 2, 4, 8, 16, 32, or 64 bits. It must also have no user-defined constructor, destructor, or copy assignment operator. It can have no private or protected non-static data members, and no non-static data members of reference type. It can't have base classes or virtual functions. And, it can only have data members that also meet these requirements. (This definition is essentially the same as a C++03 POD type. Because the definition has changed in the C++11 standard, we don't recommend using std::is_pod for this test.) Otherwise, the caller must allocate memory for the return value and pass a pointer to it as the first argument.

当 GCC/MinGW-W64 编译文章中的示例代码时,调用者仅为调用 GetSize 设置一个参数(在 rcx 中),并期望在 rax:

# AT&T syntax (destination operand last)
mov 0x10(%rbx),%rcx    # rcx <- pointer to IRenderContext
mov (%rcx),%rax        # rax <- pointer to virtual function table
callq *0x1a8(%rax)     # virtual function call (expect result in rax)

在 Visual Studio 生成的代码中,调用者在调用 GetSize 之前将 rdx 设置为指向堆栈上的某个位置:

# Intel syntax (destination operand first)
mov rax,qword ptr [rsp+168h]     # rax <- pointer to IRenderContext
mov rax,qword ptr [rax]          # rax <- pointer to virtual function table
lea rdx,[rsp+68h]                # rdx <- address of return value (hidden argument)
mov rcx,qword ptr [rsp+168h]     # rcx <- this pointer (hidden argument)
call qword ptr [rax+1A8h]        # virtual function call (expect result at [rdx])

在 GCC/MinGW-W64 上,rdx 中的值不是有效地址,因此当 GetSize 的实现尝试将返回值存储在内存中时,会发生访问冲突。

D2D_SIZE_F 是一个 64 位 POD 结构(只是两个 float 的结构),所以在我看来 GCC 在 rax 寄存器中返回它是正确的.我不知道是什么让 Visual Studio 使用指针返回,恐怕也不知道如何让 GCC 为兼容性做同样的事情。

关于c++ - RenderTarget->GetSize 不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27888109/

相关文章:

c - 如何在 header 中使用静态函数并与 float 组进行比较

gcc - 使用cygwin在Windows 7-64上编译gcc-7-20170212,==> wopen错误

visual-studio-2010 - 无法安装 Nuget 包管理器

c++ - 智能指针在 FinalRelease 中显式释放

c# - 是否应该使用 C++ 来模拟 sql

c++ - 只包含最后 n 个元素的 vector

c - 寻找完美的 Makefile Canvas

c++ - 在不将数据作为参数传递的情况下授予静态函数访问数据的权限

c - ANSI C 兼容事件循环

c++ - 在框架中使用 OpenGL 上下文编写简单的 wxWidgets 应用程序