using System;
using System.Runtime.InteropServices;
using VolvicDLL;
namespace MyDirect3D9
{
public unsafe class IDirect3D9 : IDisposable
{
public DelegateCreateDevice RealCreateDevice;
// A pointer to the native IDirect3D9 object that we are providing overrides for.
public Win32.D3D9.IDirect3D9* NativeIDirect3D9
{
get;
private set;
}
// A pointer to the original array of virtual functions. We keep this around so we can call the originals.
private IntPtr* OriginalVFTable = null;
#region Construction
// For the case where we already have a native IDirect3D9 object and we want to override some of it's functions.
public unsafe IDirect3D9(Win32.D3D9.IDirect3D9* InNativeIDirect3D9)
{
NativeIDirect3D9 = InNativeIDirect3D9;
// Override the functions in NativeIDirect3D9 with our own.
OverrideFunctions();
}
// For the case where we don't have a native IDirect3D object so we want one created for us.
public IDirect3D9(ushort SdkVersion)
{
VolvicMain.Interface.L("Same here, no IDirect3D ...");
// Create the real IDirect3D9 object.
NativeIDirect3D9 = Win32.D3D9.Direct3DCreate9(SdkVersion);
// Override the functions in NativeIDirect3D9 with our own.
OverrideFunctions();
}
#endregion
#region Destruction
~IDirect3D9()
{
Dispose(true);
}
public void Dispose()
{
Dispose(false);
}
// Cleanup resources. Destructing == true means we are getting garbage collected so don't reference any managed resources.
private void Dispose(bool Destructing)
{
if (OriginalVFTable != null)
{
Win32.Kernel32.HeapFree(Win32.Kernel32.GetProcessHeap(), 0, *OriginalVFTable);
OriginalVFTable = null;
}
}
#endregion
#region Virtual Function Table Management
// Backup the original native virtual function table and overwrite the pointer to it with our own (which is a copy of the original).
private void InitializeVFTable()
{
// If we don't have a real IDirect3D9 object yet then do nothing.
if (NativeIDirect3D9 == null) return;
// Save off the original VFTable (only if it really is the original).
if (OriginalVFTable == null) OriginalVFTable = NativeIDirect3D9->VFTable;
// IDirect3D9 has 17 members.
UInt32 VFTableLength = 17;
// Allocate space for our new VFTable.
IntPtr
* NewVFTable
= (IntPtr
*)Win32.
Kernel32.
HeapAlloc(Win32.
Kernel32.
GetProcessHeap(), 0,
(UIntPtr
)(VFTableLength
* sizeof(IntPtr
)));
// Copy all of the original function pointers into our new VFTable.
for (int i = 0; i < VFTableLength; i++)
{
NewVFTable[i] = OriginalVFTable[i];
}
// Set the Real IDirect3D9 implementation's VFTable to point at our custom one.
NativeIDirect3D9->VFTable = NewVFTable;
}
// Reset the native virtual function table to point back at the original.
private void ResetVFTable()
{
// If the original table is not defined do nothing.
if (OriginalVFTable == null) return;
// If the original table points to the same place as the current one do nothing.
if (OriginalVFTable == NativeIDirect3D9->VFTable) return;
// Cleanup memory allocated for our custom VFTable.
Win32.Kernel32.HeapFree(Win32.Kernel32.GetProcessHeap(), 0, *NativeIDirect3D9->VFTable);
// Set the VFTable back to the original.
NativeIDirect3D9->VFTable = OriginalVFTable;
// Set the original VFTable back to null.
OriginalVFTable = null;
}
private void OverrideFunctions()
{
InitializeVFTable();
// #0: STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObj) PURE;
// #1: STDMETHOD_(ULONG,AddRef)(THIS) PURE;
// #2: STDMETHOD_(ULONG,Release)(THIS) PURE;
// TODO: Override this and Dispose this object if it is going to return 0.
// #3: STDMETHOD(RegisterSoftwareDevice)(THIS_ void* pInitializeFunction) PURE;
// #4: STDMETHOD_(UINT, GetAdapterCount)(THIS) PURE;
// #5: STDMETHOD(GetAdapterIdentifier)(THIS_ UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9* pIdentifier) PURE;
// #6: STDMETHOD_(UINT, GetAdapterModeCount)(THIS_ UINT Adapter,D3DFORMAT Format) PURE;
// #7: STDMETHOD(EnumAdapterModes)(THIS_ UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode) PURE;
// #8: STDMETHOD(GetAdapterDisplayMode)(THIS_ UINT Adapter,D3DDISPLAYMODE* pMode) PURE;
// #9: STDMETHOD(CheckDeviceType)(THIS_ UINT Adapter,D3DDEVTYPE DevType,D3DFORMAT AdapterFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed) PURE;
// #10: STDMETHOD(CheckDeviceFormat)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat) PURE;
// #11: STDMETHOD(CheckDeviceMultiSampleType)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD* pQualityLevels) PURE;
// #12: STDMETHOD(CheckDepthStencilMatch)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat) PURE;
// #13: STDMETHOD(CheckDeviceFormatConversion)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SourceFormat,D3DFORMAT TargetFormat) PURE;
// #14: STDMETHOD(GetDeviceCaps)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9* pCaps) PURE;
// #15: STDMETHOD_(HMONITOR, GetAdapterMonitor)(THIS_ UINT Adapter) PURE;
// #16: STDMETHOD(CreateDevice)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface) PURE;
}
#endregion
#region IDirect3D9 Interface Function Implementations
public delegate uint DelegateCreateDevice(
Win32.D3D9.IDirect3D9* This, uint adapter, uint deviceType, IntPtr focusWindow, uint behaviorFlags,
IntPtr presentationParameters, Win32.D3D9.IDirect3DDevice9* deviceInterface);
public uint CreateDevice(Win32.D3D9.IDirect3D9* This, uint adapter, uint deviceType, IntPtr focusWindow,
uint behaviorFlags, IntPtr presentationParameters,
Win32.D3D9.IDirect3DDevice9* deviceInterface)
{
VolvicMain.Interface.L("Never here ...");
RealCreateDevice =
(DelegateCreateDevice)
Marshal.
GetDelegateForFunctionPointer(OriginalVFTable
[16
],
typeof(DelegateCreateDevice
));
uint CreateDevice = RealCreateDevice(This, adapter, deviceType, focusWindow, behaviorFlags,
presentationParameters, deviceInterface);
if (CreateDevice == 0)
{
VolvicMain.Interface.L("Creating device ...");
}
return CreateDevice;
}
#endregion
}
}