c++ - GetCPUDescriptorHandleForHeapStart 堆栈损坏

标签 c++ c com directx-12 direct3d12

我在使用 DirectX 12.0 编程时偶然发现了一个相当不寻常的问题。到目前为止,还没有任何研究具有洞察力。

我正在使用 C(不是 C++)编程。看起来官方的 DirectX 12 header 支持 C 和 C++ 的绑定(bind),但是编写 C 等效代码来执行所述任务会导致崩溃,而 C++ 不会。我不认为错误是我的。

详细信息如下:我的 D3D12 设备初始化过程中有以下代码块:

/* Get a handle to the memory location in the render target
view heap to identify where the render target views will be
located for the two back buffers */
hRTV = pThis->pRTVHeap->lpVtbl->GetCPUDescriptorHandleForHeapStart(pThis->pRTVHeap);

其中 hRTV 代表 'Handle to Render Target View' (D3D12_CPU_DESCRIPTOR_HANDLE) 而 pRTVHeap 代表 ' 指针渲染目标 View 堆' (ID3D12DescriptorHeap)。

这是 C++ 等效项 - 这工作正常:

/* Get a handle to the memory location in the render target
view heap to identify where the render target views will be
located for the two back buffers */
hRTV = this->pRTVHeap->GetCPUDescriptorHandleForHeapStart();

不存在编译时错误,但在运行时,在 C 中调用此方法 (GetCPUDescriptorHandleForHeapStart) 会触发堆栈损坏(%ESP 被替换为 4 个字节)。

我检查了该方法的反汇编并记下了 RET(返回)指令:

mov         edi,edi
push        ebp
mov         ebp,esp
mov         ecx,dword ptr [ebp+8]
mov         eax,dword ptr [ecx+2Ch]
cmp         dword ptr [eax],2
jne         5029004A
mov         eax,dword ptr [ebp+0Ch]
mov         ecx,dword ptr [ecx+28h]
mov         dword ptr [eax],ecx
jmp         50290055
push        dword ptr [ebp+0Ch]
call        5029005E
mov         eax,dword ptr [ebp+0Ch]
pop         ebp
ret         8

对于那些熟悉汇编和(希望如此)COM(组件对象模型)对象的 __stdcall 调用约定的人来说,this(或等效的)指针传递给stack,是该方法的第一个参数(在本例中,应该是唯一的参数),这是一种使 COM 对象能够访问自己的数据的做法。

以下代码片段(也在上面显示)引起了我的困惑,当运行时抛出“未对齐的堆栈指针/堆栈损坏”(%ESP)错误时,这是​​理所当然的:

ret        8

在这种情况下只应传递一个参数(this 指针)。指针的大小(在 32 位系统上——我的目标架构是 x86)是 4 个字节(32 位),那么为什么被调用者要清理堆栈上的 8 个字节?

我称这是一个错误是否正确?是否需要将此问题告知 Microsoft?我错了吗?

感谢您的宝贵时间,希望比我知识渊博的人能赐教。请不要提出更喜欢 C++ 而不是 C 的古老论点。

最佳答案

解决方案

D3D12.DLL 的调试符号足以显示。命名约定(例如 ID3D12DescriptionHeap::GetCPUDescriptorHandleForHeapStart)强烈表明 DLL 是用 C++ 编写的。 (隐藏的)第二个参数确实传递给了该方法 - 指向输出结构 D3D12_CPU_DESCRIPTOR_HANDLE 的指针(仅包含一个整数,别名为结构。我不知道他们为什么这样做).我忘记了 C++ 与 C 的不同之处在于 C++ 可以将结构作为返回值返回,并且结构不能通过累加器 (%EAX) 寄存器作为返回值传递,因此它必须作为堆栈上的指针传递给被调用方。

问题是错误的 C 绑定(bind)(Microsoft header 错误)。建议进行以下修复:

旧代码:

D3D12_CPU_DESCRIPTOR_HANDLE (
    STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart )( 
    ID3D12DescriptorHeap * This);

替换为:

void ( STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart )(
    ID3D12DescriptorHeap *This, D3D12_CPU_DESCRIPTOR_HANDLE *pOut);

谢谢。

编辑

此 header 错误已随 10.0.22000.0 Windows SDK 的发布得到修复。

关于c++ - GetCPUDescriptorHandleForHeapStart 堆栈损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34118929/

相关文章:

c - 在 Linux 中使用 c 私有(private)内存使用量不断增加

c - 如何使用 C 程序在 Linux 中获取磁盘使用情况?

windows - 对于COM服务器和注册表项重定向,是否需要做文件路径重定向转换?

C: *数组[x]的大小?

c# - Unity - 如何为 COM Interop DLL 注册类型

c++ - MFC:类似于 Windows Explorer 的应用程序,用于与其主线程并行导出文件

android - 使用 Marmalade (C++) 开发移动应用程序

c++ - 为什么我们不能有 move 的迭代器?

C++ 类型转换

c++ - 在同一表达式内的表达式中使用副作用结果是否安全?