gpt4 book ai didi

c++ - 什么是 Direct X 虚拟表?

转载 作者:搜寻专家 更新时间:2023-10-31 00:54:28 25 4
gpt4 key购买 nike

我有一个关于虚拟表的问题。

我所知道的虚表是可以找到的函数地址数组多态对象调用虚函数时的函数地址。

但是在directx中,有人提到dx vtable就是d3d9.dll的表的导入函数地址数组。

为什么他们调用导入函数地址数组到directx vtable?它似乎与 vtable 无关。

我的知识有误吗?我可以详细了解 vtable 吗?谢谢!

最佳答案

从 DLL 导出 COM 对象时,通常有两个部分在起作用。首先是“工厂”。工厂可以是从 DLL 导出的标准 C 可调用函数(Direct3D 就是这种情况),或者是在系统注册表中注册的类,在这种情况下,您将使用 CoCreateInstance 创建 COM接口(interface)实例。第一个示例是创建 Direct3D 设备:

ID3D11Device* d3dDevice = nullptr;

hr = D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
0,
0,
nullptr,
0,
D3D11_SDK_VERSION,
&d3dDevice,
nullptr,
nullptr);

在此调用之后,d3dDevice 接口(interface)指向分配的 COM 接口(interface)对象。包含 D3D11CreateDevice 的 DLL 必须隐式链接到调用程序——或者您可以使用 LoadLibrary 进行显式链接,在这种情况下您可以使用指向函数 D3D11CreateDevice 的作用大致相同。这是从 DLL 的“导入表”派生的。

第二个示例是您在使用 Windows 图像处理组件 (WIC) 时执行的操作:

IWICImagingFactory* factory = nullptr;
hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
__uuidof(IWICImagingFactory),
&factory);

这让 COM 系统在注册表中查找类 GUID,加载引用的 DLL,然后调用其中的工厂方法来创建一个返回给您的 COM 接口(interface)对象。

在这两种情况下,接口(interface)指向的实际内容都是以下形式:

typedef struct IUnknownVtbl
{
BEGIN_INTERFACE

HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
IUnknown * This,
/* [in] */ REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject);

ULONG ( STDMETHODCALLTYPE *AddRef )(
IUnknown * This);

ULONG ( STDMETHODCALLTYPE *Release )(
IUnknown * This);

END_INTERFACE
} IUnknownVtbl;

它旨在准确地映射到 virtual 的 Visual C++ 实现:

MIDL_INTERFACE("00000000-0000-0000-C000-000000000046")
IUnknown
{
public:
BEGIN_INTERFACE
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject) = 0;

virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;

virtual ULONG STDMETHODCALLTYPE Release( void) = 0;

END_INTERFACE
};

COM 并没有真正的继承概念,但是 ID3D11Device1 使用来自 ID3D1Device 的 C++ 公共(public)继承还是很方便的,因为语言类型具有没有声明数据成员。接口(interface)的 COM“继承”实际上只是方法的串联,如果您查看 header 中的 C 定义,就会看到这些方法:

#if defined(__cplusplus) && !defined(CINTERFACE)

MIDL_INTERFACE("cc86fabe-da55-401d-85e7-e3c9de2877e9")
ID3D11BlendState1 : public ID3D11BlendState
{
public:
virtual void STDMETHODCALLTYPE GetDesc1(
/* [annotation] */
_Out_ D3D11_BLEND_DESC1 *pDesc) = 0;

};


#else /* C style interface */

typedef struct ID3D11BlendState1Vtbl
{
BEGIN_INTERFACE

HRESULT ( STDMETHODCALLTYPE *QueryInterface )( /* ... */ );

ULONG ( STDMETHODCALLTYPE *AddRef )( ID3D11BlendState1 * This);

ULONG ( STDMETHODCALLTYPE *Release )( ID3D11BlendState1 * This);

void ( STDMETHODCALLTYPE *GetDevice )( /* ... */ );

HRESULT ( STDMETHODCALLTYPE *GetPrivateData )( /* ... */ );

HRESULT ( STDMETHODCALLTYPE *SetPrivateData )( /* ... */ );

HRESULT ( STDMETHODCALLTYPE *SetPrivateDataInterface )( /* ... */ );

void ( STDMETHODCALLTYPE *GetDesc )(
ID3D11BlendState1 * This,
/* [annotation] */
_Out_ D3D11_BLEND_DESC *pDesc);

void ( STDMETHODCALLTYPE *GetDesc1 )(
ID3D11BlendState1 * This,
/* [annotation] */
_Out_ D3D11_BLEND_DESC1 *pDesc);

END_INTERFACE
} ID3D11BlendState1Vtbl;

#endif

It's important to note this only works for the case of pure virtual (i.e. abstract) C++ classes with no data members and only virtual methods using public inheritance (i.e. interfaces). Constructors and destructors are ignored as COM life-time is managed through reference-counting via IUnknown.

方法的调用签名也将指向 COM 对象的指针作为映射到 this 的 C++ 调用约定的第一个参数。

COM 接口(interface)因此被设计为像 C++ 虚拟方法一样工作,因此您可以使用 C++ 语法调用它们,但它们根本不一定是 C++ 类对象。

IUnknown COM 中有一种已知的标准方法来获取特定接口(interface),即 QueryInterface。 Direct3D 工厂函数也为您处理这件事,并且只返回基本接口(interface)。对于 Direct3D 11,这是一个 ID3D11Device

If you want to get an interface to say 11.1, you then use QueryInterface on the ID3D11Device asking for a ID3D11Device1. It would fail on a DirectX 11.0 system, but works on a DirectX 11.1 or later system.

对于使用 Direct3D 的 C++ 程序员,该设计有意将“COM”保持在最低限度(俗称“COM lite”)。真正使用足够的 COM 可以更轻松地处理随时间变化的接口(interface)并提供合理的 ABI。 Direct3D 工厂函数是来自已知 DLL 的简单 C 调用导出,因此您甚至不必处理标准 COM 工厂,事实上,如果您尝试使用 CoCreateInstance,API 将无法正常工作。您可以通过标准 MIDL compiler 的一些宏在技术上使用 C与 C++ 定义一起生成,但这样做有点挑战,而且最近没有经过特别好的测试。

作为 Direct3D COM 的使用者,您真正需要了解的是 IUnknown 引用计数和查询的基础知识——今天最好使用 Microsoft::WRL::ComPtr 来完成。智能指针——以及如何正确检查 HRESULT 值——参见 ThrowIfFailed .

See The Component Object Model and Reference Counting (Direct3D 10)

关于c++ - 什么是 Direct X 虚拟表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45207273/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com