Ever wanted to paint your own graphics (or text) on top of a DirectX application (e.g., to show TeamSpeak informations, or a self-created map, within a game )?
Then, the solution discussed later on might be of help for you. By using a “proxy-dll”, calls to DirectX can be intercepted, data altered and even new objects can be created and be shown within another application.
The different topics of this section on mikoweb.eu cover the creation of a basic proxy-dll for DirectX8/9 3D-calls (d3d8.dll / d3d9.dll), including the full source. Based on your imagination and knowledge, you might enhance this for your very own applications and needs.
In case you like to use a “ready made solution”, check out the GPP-Package at the download page. Please note that the source for this one is also available.
Don’t hesitate to send in feedback and examples of how you did achieve certain goals by using the discussed concept. I’m quite sure some things can be done better, and I’d be happy to present your input here.
As a teaser, here is a picture of a fast’n dirty implementation of a 3D model into the proxy-dll, directly taken from the screen (testing application: Krakout-Arkanoid – DX8). The yellow rectangle in the upper left corner and the cube in the middle aren’t part of the original game, they were created within the proxy-dll and “added”.
Btw, Andrey A. Ugolnik, the author of Krakout RE (the game I used a lot for testing the DX8 proxy) contacted me and offered a free license key. This is a nice move, really. Check out other games and stuff by him here: http://www.ugolnik.info
To obtain DirectX functionality, an application needs to load certain dynamic link libraries (dlls), e.g. d3d8.dll (d3d9.dll respectively). A “proxy-dll” names exactly like a dll in question and manages to get loaded by the app instead of the “real, original” one. Once loaded, the proxy loads the “real” dll by itself and passes all calls from the application on to it.
So, a “filter” is installed between the application and its calls to regular dll functions. Obviously, new own functionality can be added now when intercepting (even altering/faking) certain function calls.
By the way, this concept is very similar to one used by a Microsoft DirectX programming utility, named D3DSpy. Quote from the D3DSpy help file (DX9 here):
|D3DSpy works by providing a proxy DLL, which the application connects to and treats like the real D3D9.DLL. It intercepts all the calls and gathers various information before making the real D3D call.|
The proxy-concept doesn’t work with all applications due to several reasons. It has to be tested thoroughly with an application (game) before making it available to a wider range of users.
There are other approaches on how to draw own stuff in a DirectX application (like “run-time code-injection”, or even altering the code of an executable file). In case the proxy-dll concept doesn’t work for you, you may want to look for one of those (see here, too).
We focus on DirectX8/9 3D calls here. This said, we need to create a d3d8.dll (d3d9.dll) that will be called by the application instead of the “real” (system-provided) library.
Note: For testing the proxy-dll, I used Krakout-Arkanoid (DX8) and Flatspace Demo (DX9), amongst others. Both are nice games, and they were at hand that time. For debugging purposes, DebugView is a nice tool. Ah, and check out dependency walker for the examination of dlls.
First, let’s take a look at an application that uses DirectX 3D calls. It enables D3D support by loading the d3d8.dll, then obtains the IDirect3D8 interface via Direct3DCreate8 and creates a IDirect3DDevice8 with CreateDevice).
If we can manage to get our d3d8.dll/d3d9.dll loaded by the application, thus getting the call to Direct3DCreate8/Direct3DCreate9 redirected to our code, we could create a IDirect3D8/9 Interface object by ourselves. Same goes for the IDirect3DDevice8/9 Interface. We would then offer all funcionality like the original objects to the caller’s code (in fact just redirecting every call to a IDirect3D/IDirect3DDevice we secretetly created of our own).
This gives us the possibility to change data and/or add new things.
Any drawbacks on that ? Yes.
Normally, an application looks for a dll within its working directory first, then browsing the system’s path. Applications may prevent that by directly targetting the system directory. And we can’t just replace the system’s d3d8/9.dll, as we need its functions as described above (btw., I strongly advise to not touch the original system dll. You may screw your DirectX installation).
Furthermore, an application might implement its own e.g. texture manager (or even use undocumented calls). As we will not be able to handle such calls (obviously), the app would possibly not work with a proxy-dll.
Finally, we know what we need…
- a file named d3d8.dll/d3d9.dll that will be placed within the application’s working directory (and hopefully get loaded by the app).
- a function named “Direct3DCreate8” being exposed by that dll (“Direct3DCreate9” respectively).
- an interface provided by the dll that exactly looks the same as the “real” IDirect3D8/9 interface
- an interface provided by the dll that exactly looks the same as the “real” IDirect3DDevice interface
Luckily enough, some header files that come with the DX SDK point out what calls should be handled by our “faked” interfaces.
So, my “basic proxy-dll” implementation consists of
- global routines for the dll handling (entry point, load the system d3d8.dll/d3d9.dll, and so on)
- an object called myIDirect3D8/9, derived from Direct3D8/9, exposing over a dozen functions
- an object called myIDirect3DDevice8/9, derived from IDirect3DDevice8/9, exposing about 100 functions
Basically, all functions within the “my…” objects pass parameters on to the original system dll, providing the possibility to change or add data. A few routines need special attention though.
Release (both Objects)
In case the application releases the interface (and no more references are present), we destroy our own object as well.
QueryInterface (both Objects)
If the application queries for certain interfaces, we do of course pass the address of our very own routine, not passing the system-dll response this time.
Once this is called, we create our own D3DDevice (internally), as we need it to process the application calls. Then, we respond in sending our own object’s address.
For testing purposes, the function myIDirect3DDevice8/9::ShowWeAreHere was added. It is called within myIDirect3DDevice8/9::Present and does nothing but create a yellow rectangle in the upper left screen. This might give you an impression of how to add own content. Drawing own real 3D Objects is possible as well, believe me (if you can handle the application-internal world coordinates, hehe).
Tests on recent games show that some of them (like Tomb Raider – Legend) use IDirect3DSwapChain9::Present for showing their screens, never calling IDirect3DDevice9::Present (as e.g. World of Warcraft does).
Obviously, a proxy-dll has to cover IDirect3DSwapChain9 then, too. An updated code example has beed submitted to the downloads page. Check for the Basic d3d8/9.dll Implementation section.