Skip to content

Commit

Permalink
Initial submit of the wrapper generator
Browse files Browse the repository at this point in the history
  • Loading branch information
jarikomppa committed May 19, 2013
1 parent becf807 commit 554ffc8
Show file tree
Hide file tree
Showing 11 changed files with 1,869 additions and 1 deletion.
7 changes: 7 additions & 0 deletions .gitignore
Expand Up @@ -11,3 +11,10 @@
*.lai
*.la
*.a

Release/
Debug/
ipch/
*.filters
*.opensdf
*.sdf
48 changes: 47 additions & 1 deletion README.md
@@ -1,4 +1,50 @@
dxwrapper
=========

DirectX 1-7 wrapper project for making old games run on new hardware
DirectX 1-7 wrapper project for making old games run on new hardware.

Requires DirectX 8.1 SDK headers (although the parser should(tm) be able to handle just about any version), which the wrapper generator will parse to generate the interface wrappers for the various DirectX interfaces.

At its current form, the wrapper is a full pass-through wrapper; it doesn't do anything special, just takes in calls from the application, writes the event to a log, and passes the arguments to the real DirectX.

There's bound to be plenty of bugs left, but I've managed to get a 100k-line log out of Crimson Skies so far..

The whole thing, and the generated code, is released under zlib license:

-- 8< -- 8< -- 8< --

Copyright (c) 2013 Jari Komppa

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.

3. This notice may not be removed or altered from any source
distribution.

-- 8< -- 8< -- 8< --

The basic idea is to extend DirectX COM interface classes, and then pass the extended classes to the application. The application doesn't have any clue that it's not talking directly to DirectX (usually. I'm pretty sure punkbuster or some such does have checks against this). Then, when the application calls a function, we can muck around with the parameters before passing it to DirectX, and/or muck around with the returning value. It's also entirely possible to just skip on talking to DirectX and make an OpenGL back-end, like I did with ddhack for Wing Commander games, but that's a lot of work.

Now, every time the application calls a function with a parameter that happens to be one of our wrapped classes, we also have to change these pointers to point at the original objects. This can get a bit tricky, and I'm sure I've missed several places (especially on interfaces I haven't seen in use yet). Just something to keep in mind when playing with it.

Sometimes the application calls some function that returns another wrappable object. Sometimes we've already wrapped this. For this, I've added a simple (slow, and stupid) database of pointer pairs that is checked whenever one of those functions is called. Sometimes this can cause a false warning in the log, since the framebuffer, for example, doesn't need to be created implicitly, but is an attached surface. Or something. I've added code to wrap it when it's queried for the first time.

It's entirely possible that other interfaces (like directmedia/directshow) eat or output directx objects, in which case we're either in trouble, or have to wrap more interfaces.

If you play with this code, toss me a note, I'm always interested in hearing about it, but I'm most likely too busy to actually help you (much) =)

Cheers,
Jari
100 changes: 100 additions & 0 deletions wrapper/ddinput.cpp
@@ -0,0 +1,100 @@
#define STRICT
#define WIN32_LEAN_AND_MEAN
#define INITGUID
#define DIRECTDRAW_VERSION 0x0700
#define DIRECT3D_VERSION 0x0700

#include <windows.h>
#include <ddraw.h>
#include "d3d.h"
#include "ddoutput.h"
#include "wrapper.h"

#ifdef _DEBUG
#define DEBUGMESS(a) OutputDebugStringA(a)
#else
#define DEBUGMESS(a)
#endif


typedef HRESULT (_stdcall *DDrawCreateProc)(void* a, void* b, void* c);
typedef HRESULT (_stdcall *DDrawEnumerateProc)(void* callback, void* context);
typedef void (_stdcall *DDrawMiscProc)();
typedef HRESULT (_stdcall *DDrawCreateExProc)(GUID FAR *lpGUID, LPVOID *lplpDD, REFIID iid, IUnknown FAR *pUnkOuter);

static DDrawCreateProc DDrawCreate=0;
static DDrawEnumerateProc DDrawEnumerate=0;
static DDrawMiscProc AcquireLock;
static DDrawMiscProc ParseUnknown;
static DDrawMiscProc InternalLock;
static DDrawMiscProc InternalUnlock;
static DDrawMiscProc ReleaseLock;
static DDrawCreateExProc DDrawCreateEx;

static void LoadDLL() {
char path[MAX_PATH];
GetSystemDirectoryA(path,MAX_PATH);
strcat_s(path, "\\ddraw.dll");
HMODULE ddrawdll=LoadLibraryA(path);
//HMODULE ddrawdll=LoadLibraryA("csfix.dll");
DDrawCreate=(DDrawCreateProc)GetProcAddress(ddrawdll, "DirectDrawCreate");
DDrawEnumerate=(DDrawEnumerateProc)GetProcAddress(ddrawdll, "DirectDrawEnumerateA");
DDrawCreateEx=(DDrawCreateExProc)GetProcAddress(ddrawdll, "DirectDrawCreateEx");

AcquireLock=(DDrawMiscProc)GetProcAddress(ddrawdll, "AcquireDDThreadLock");
ParseUnknown=(DDrawMiscProc)GetProcAddress(ddrawdll, "D3DParseUnknownCommand");
InternalLock=(DDrawMiscProc)GetProcAddress(ddrawdll, "DDInternalLock");
InternalUnlock=(DDrawMiscProc)GetProcAddress(ddrawdll, "DDInternalUnlock");
ReleaseLock=(DDrawMiscProc)GetProcAddress(ddrawdll, "ReleaseDDThreadLock");
}

extern "C" void __declspec(naked) myAcquireLock() {
logf(__FUNCTION__ "\n");
_asm jmp AcquireLock;
}
extern "C" void __declspec(naked) myParseUnknown() {
logf(__FUNCTION__ "\n");
_asm jmp ParseUnknown;
}
extern "C" void __declspec(naked) myInternalLock() {
logf(__FUNCTION__ "\n");
_asm jmp InternalLock;
}
extern "C" void __declspec(naked) myInternalUnlock() {
logf(__FUNCTION__ "\n");
_asm jmp InternalUnlock;
}
extern "C" void __declspec(naked) myReleaseLock() {
logf(__FUNCTION__ "\n");
_asm jmp ReleaseLock;
}

extern "C" HRESULT _stdcall myDirectDrawCreate(GUID* a, IDirectDraw** b, IUnknown* c) {
logf(__FUNCTION__ "\n");
if(!DDrawCreate) LoadDLL();
HRESULT hr=DDrawCreate(a,b,c);
if(FAILED(hr)) return hr;
*b=(IDirectDraw*)new myIDirectDraw(*b);
return 0;
}

extern "C" HRESULT _stdcall myDirectDrawCreateEx(
GUID FAR *lpGUID,
LPVOID *lplpDD,
REFIID iid,
IUnknown FAR *pUnkOuter
)
{
logf(__FUNCTION__ "\n");
if(!DDrawCreate) LoadDLL();
HRESULT hr = DDrawCreateEx(lpGUID, lplpDD, iid, pUnkOuter);
genericQueryInterface(iid, lplpDD);
return hr;
}

extern "C" HRESULT _stdcall myDirectDrawEnumerate(void* lpCallback, void* lpContext) {
logf(__FUNCTION__ "\n");
if(!DDrawEnumerate) LoadDLL();
return DDrawEnumerate(lpCallback, lpContext);
}

12 changes: 12 additions & 0 deletions wrapper/exports.def
@@ -0,0 +1,12 @@
LIBRARY wrapper
EXPORTS

DirectDrawCreate=myDirectDrawCreate @1
DirectDrawCreateEx=myDirectDrawCreateEx @2
DirectDrawEnumerateA=myDirectDrawEnumerate @3

AcquireDDThreadLock=myAcquireLock
D3DParseUnknownCommand=myParseUnknown
DDInternalLock=myInternalLock
DDInternalUnlock=myInternalUnlock
ReleaseDDThreadLock=myReleaseLock
60 changes: 60 additions & 0 deletions wrapper/interfacequery.cpp
@@ -0,0 +1,60 @@
#include <stdio.h>
#include <stdlib.h>
#include "wrapper.h"

void *d3d9InterfaceQuery(REFIID a);

void genericQueryInterface(REFIID a, void **ptr)
{
#define QUERYINTERFACE(x) \
if(a==IID_##x) \
{ \
*ptr = (void*)new my##x(*(x **)ptr); \
logf("\tWrapped: " #x "\n");\
wrapstore(orig, *ptr);\
return;\
}

logf("\tInterface Query: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
a.Data1, a.Data2, a.Data3,
a.Data4[0],a.Data4[1],a.Data4[2],a.Data4[3],
a.Data4[4],a.Data4[5],a.Data4[6],a.Data4[7]);

void * orig = *ptr;

QUERYINTERFACE(IDirect3D);
QUERYINTERFACE(IDirect3D2);
QUERYINTERFACE(IDirect3D3);
QUERYINTERFACE(IDirect3D7);
QUERYINTERFACE(IDirect3DDevice);
QUERYINTERFACE(IDirect3DDevice2);
QUERYINTERFACE(IDirect3DDevice3);
QUERYINTERFACE(IDirect3DDevice7);
QUERYINTERFACE(IDirect3DExecuteBuffer);
QUERYINTERFACE(IDirect3DLight);
QUERYINTERFACE(IDirect3DMaterial);
QUERYINTERFACE(IDirect3DMaterial2);
QUERYINTERFACE(IDirect3DMaterial3);
QUERYINTERFACE(IDirect3DTexture);
QUERYINTERFACE(IDirect3DTexture2);
QUERYINTERFACE(IDirect3DVertexBuffer);
QUERYINTERFACE(IDirect3DVertexBuffer7);
QUERYINTERFACE(IDirect3DViewport);
QUERYINTERFACE(IDirect3DViewport2);
QUERYINTERFACE(IDirect3DViewport3);
QUERYINTERFACE(IDirectDraw);
QUERYINTERFACE(IDirectDraw2);
QUERYINTERFACE(IDirectDraw4);
QUERYINTERFACE(IDirectDraw7);
QUERYINTERFACE(IDirectDrawClipper);
QUERYINTERFACE(IDirectDrawColorControl);
QUERYINTERFACE(IDirectDrawFactory);
QUERYINTERFACE(IDirectDrawGammaControl);
QUERYINTERFACE(IDirectDrawPalette);
QUERYINTERFACE(IDirectDrawSurface);
QUERYINTERFACE(IDirectDrawSurface2);
QUERYINTERFACE(IDirectDrawSurface3);
QUERYINTERFACE(IDirectDrawSurface4);
QUERYINTERFACE(IDirectDrawSurface7);
logf("\t**** Unknown interface - not wrapped\n");
}
95 changes: 95 additions & 0 deletions wrapper/main.cpp
@@ -0,0 +1,95 @@
#define STRICT
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <shlobj.h>
#include <stdio.h>
#include <stdlib.h>
#include <varargs.h>
//#include "ddoutput.h"

bool _stdcall SetWindowPosHook(HWND, HWND, int, int, int, int, int) { return true; }
bool _stdcall SetWindowLongHook(HWND, int, int) { return true; }
bool _stdcall ShowWindowHook(HWND, int) { return true; }

bool _stdcall DllMain(HANDLE, DWORD dwReason, LPVOID) {
if(dwReason==DLL_PROCESS_ATTACH) {
} else if(dwReason==DLL_PROCESS_DETACH) {
//d3d9Exit();
}
return true;
}

void logf(char * fmt, ...)
{
va_list ap;
va_start(ap, fmt);
FILE *f = fopen("wrapper.log", "a");
if (f)
{
vfprintf(f, fmt, ap);
fclose(f);
}
va_end(ap);
}

struct WrapPair
{
void * mOriginal;
void * mWrapper;
};

#define MAX_PAIRS 4096
WrapPair gWrapPair[MAX_PAIRS];
int gWrapPairs = 0;

void * do_wrapfetch(void * aOriginal)
{
int i;
for (i = 0; i < gWrapPairs; i++)
{
if (gWrapPair[i].mOriginal == aOriginal)
{
return gWrapPair[i].mWrapper;
}
}
return NULL;
}

void wrapstore(void * aOriginal, void * aWrapper)
{
if (do_wrapfetch(aOriginal) == NULL)
{
gWrapPair[gWrapPairs].mOriginal = aOriginal;
gWrapPair[gWrapPairs].mWrapper = aWrapper;
gWrapPairs++;
}
else
{
int i;
for (i = 0; i < gWrapPairs; i++)
{
if (gWrapPair[i].mOriginal == aOriginal)
{
gWrapPair[i].mWrapper == aWrapper;
return;
}
}
}

if (gWrapPairs >= MAX_PAIRS)
{
logf("\n\t**** Max number of wrappers exceeded - adjust and recompile\n");
}
}

void * wrapfetch(void * aOriginal)
{
void * ret = do_wrapfetch(aOriginal);

if (ret == NULL)
{
logf("\t**** Wrapped object not found - returning null - brace yourself\n");
}
return ret;
}
48 changes: 48 additions & 0 deletions wrapper/wrapper.h
@@ -0,0 +1,48 @@
#pragma once
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "ddraw.h"
#include "ddrawex.h"
#include "d3d.h"

#include "myIDirect3D.h"
#include "myIDirect3D2.h"
#include "myIDirect3D3.h"
#include "myIDirect3D7.h"
#include "myIDirect3DDevice.h"
#include "myIDirect3DDevice2.h"
#include "myIDirect3DDevice3.h"
#include "myIDirect3DDevice7.h"
#include "myIDirect3DExecuteBuffer.h"
#include "myIDirect3DLight.h"
#include "myIDirect3DMaterial.h"
#include "myIDirect3DMaterial2.h"
#include "myIDirect3DMaterial3.h"
#include "myIDirect3DTexture.h"
#include "myIDirect3DTexture2.h"
#include "myIDirect3DVertexBuffer.h"
#include "myIDirect3DVertexBuffer7.h"
#include "myIDirect3DViewport.h"
#include "myIDirect3DViewport2.h"
#include "myIDirect3DViewport3.h"
#include "myIDirectDraw.h"
#include "myIDirectDraw2.h"
#include "myIDirectDraw3.h"
#include "myIDirectDraw4.h"
#include "myIDirectDraw7.h"
#include "myIDirectDrawClipper.h"
#include "myIDirectDrawColorControl.h"
#include "myIDirectDrawFactory.h"
#include "myIDirectDrawGammaControl.h"
#include "myIDirectDrawPalette.h"
#include "myIDirectDrawSurface.h"
#include "myIDirectDrawSurface2.h"
#include "myIDirectDrawSurface3.h"
#include "myIDirectDrawSurface4.h"
#include "myIDirectDrawSurface7.h"

void logf(char * format, ...);
void genericQueryInterface(REFIID riid, LPVOID * ppvObj);
void wrapstore(void * aOriginal, void * aWrapper);
void *wrapfetch(void * aOriginal);

0 comments on commit 554ffc8

Please sign in to comment.