Jakub
Jakub

Reputation: 45

Create Direct3DEx interface from C doesn't work

i have to admit that i have really strange issue, which im not able to solve by my self. Im trying from few days without success.

My goal is to use Direct3DEx interfaces from C (not C++). I cant use Direct3D because i have to deal with shared resource handles with surfaces from different d3ddevices.

I have no any problems with creating IDirect3DEx from C++, works perfectly. For example this code works as expected

IDirect3D9Ex* m_d3d;

Direct3DCreate9Ex(D3D_SDK_VERSION, &m_d3d);

UINT c = m_d3d->GetAdapterCount();

m_d3d->Release();  

Now im trying to do exactly the same from C,
my code is:

void *pd3dll = (void *) LoadLibrary("d3d9.dll");
 UINT count;
 IDirect3D9Ex *pDirect3D9ExInterface;
 HRESULT hr;

 typedef HRESULT (WINAPI *Direct3DCreate9Ex_t)(UINT SDKVersion, IDirect3D9Ex **ppD3D);

 Direct3DCreate9Ex_t Direct3DCreate9ExFunc;

 Direct3DCreate9ExFunc = (Direct3DCreate9Ex_t) GetProcAddress((HMODULE) pd3dll, "Direct3DCreate9Ex");

 hr = Direct3DCreate9ExFunc(D3D_SDK_VERSION, &pDirect3D9ExInterface);

 if (SUCCEEDED(hr))
 {
    count = IDirect3D9Ex_GetAdapterCount(pDirect3D9ExInterface); //crash 

    IDirect3D9Ex_Release(pDirect3D9ExInterface);
 }  

i dont see absolutly any reason why this piece of code doesnt work.
Please notice that code line:

hr = Direct3DCreate9ExFunc(D3D_SDK_VERSION, &pDirect3D9ExInterface);  

returns S_OK, and when im checking pDirect3D9ExInterface pointer under debuger it looks like a valid pointer.
But this line of code:

count = IDirect3D9Ex_GetAdapterCount(pDirect3D9ExInterface); //crash  

causes my program to crash. When im switching my DirectX9 to debug mode, on VS output window i see after crash, something like this:

Direct3D9: (ERROR) :Invalid initialization function specified. RegisterSoftwareDevice fails. Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

Additionaly if i change this C code to Direct3D initialization (no Direct3DEx) than works without any problems.
What im doing wrong? Where is the catch?
thanks in advance
Jakub

Upvotes: 0

Views: 1028

Answers (1)

Grant Peters
Grant Peters

Reputation: 7835

This seems to be due to a bug in the definition of the d3d9.h header file. A function seems to be left out of the IDirect3D9Ex interface that appears in the IDirect3D9 interface (IDirect3D9Ex inherits from IDirect3D9).

In c++ this still works because of inheritance and virtual functions working correctly, in c, it doesn't correctly pick up the inheritance due to the way their v-tables are constructed.

Below I've commented out the line that needs to be added to fix this issue (in d3d9.h at line 2044):

DECLARE_INTERFACE_(IDirect3D9Ex, IDirect3D9)
{
    /*** IUnknown methods ***/
    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObj) PURE;
    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
    STDMETHOD_(ULONG,Release)(THIS) PURE;

    /*** IDirect3D9 methods ***/
    //Add this here: STDMETHOD(RegisterSoftwareDevice)(THIS_ void* pInitializeFunction) PURE;
    STDMETHOD_(UINT, GetAdapterCount)(THIS) PURE;
    STDMETHOD(GetAdapterIdentifier)(THIS_ UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9* pIdentifier) PURE;
    STDMETHOD_(UINT, GetAdapterModeCount)(THIS_ UINT Adapter,D3DFORMAT Format) PURE;
    STDMETHOD(EnumAdapterModes)(THIS_ UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode) PURE;

You can double check that the functions line up correctly with the returned interface by loading the d3d9.dll symbols from the MS servers and comparing the names in the v-table with the values reported. In the image below, the left hand side is the v-table before being fixed, and the right hand side is the v-table after being fixed.

differences between broken and fixed v-tables in debugger

To get the symbol's from the MS symbol servers:

  • start the application and place a breakpoint after LoadLibrary("d3d9.dll") has been called
  • open up the 'Modules' window (from the menu bar Debug->Windows->Modules)
  • Find d3d9.dll in the modules list (try typing d3d9.dll to quickly go to it)
  • Right-click on d3d9.dll and click on Load Symbols From->Microsoft Symbol Servers
  • Wait a few seconds for it to download and load the symbols, addresses should then resolve to useful names.

Upvotes: 2

Related Questions