HUDs and DirectX Hooking

agentgonzo

Grounded since '09
Addon Developer
Joined
Feb 8, 2008
Messages
1,649
Reaction score
4
Points
38
Location
Hampshire, UK
Website
orbiter.quorg.org
In my quest to get a decent looking HUD from an MFD rather than vessel code, I've tried another method and again hit a wall. This time I got really close.

The concept I had this time was to do API hooking. The basic premise of this is you replace by sneaky means a call to a standard API (In this case, DirectDrawCreateEx) with your own call so that when the client application (in this case Orbiter.exe) calls it, it's actually calling your own code.

Here's how far I've got. I've implemented 3 DirectX classes as my own extensions of those classes:
MyDirect3D7 : IDirect3D7
MyDirectDraw : IDirectDraw
MyDirect3DDevice7 : IDirect3DDevice7

I Hook DirectDrawCreateEx so that it calls my function. From this function, I call the proper DirectDrawCreateEx and pass the parameters to create the DircetDraw object, but then return a freshly created MyDirectDraw object instead. This object has a pointer set to the real DirectDraw object and if you look at the code, it just passes all the functions through to the real object. This works fine. The only function that I really affect is the QueryInterface that creates the IDirect3D7 object. Again, I pass the parameters to create this object, but return a MyDirect3D7 object instead, that does a similar passing-of-all-functions-to-the-real-object.

All of this works absolutely fine and orbiter will function as normal. The problem that I have is that when I change the CreateDevice to create a MyDirect3DDevice7 object from an IDirect3DDevice7 object, orbiter will correctly call a load of functions like CreateTexture and SetRenderState, but then crash after a bit of execution.

I can see in the debugger the calls to the previous functions and it appears to work, but then at some stage after some of the texture or renderstate functions (can't rememeber off the top of my head) it crashes in the orbiter code and I don't know why. One thought was that I didn't have the correct functions implemented, but I've checked this twice with the DirectX7 help and can't see missing functions. Does anyone want to experiment with this or tell me why it fails?

The code can be found at http://www.quorg.org/misc/D3D7Hook.zip and you need to call the foobar(HINSTANCE) function from your InitModule() function in your DLL to hook the function. You'll also need to link against the directx headers (normal orbiter .lib has the link funcitonality). I got the headers from the old DX7 skd as I can't find the headers for IDirect3D7 and IDirect3DDevice7 in the later SDKs, despite Microsoft saying that all the SDKs are backward compatible. Don't know whether that makes any difference though, as I'm still linking against the orbiter.lib rather than the directX sdk libs.

My plan was to change the EndScene() function of MyDirect3DDevice7 to call the real EndScene, then call a DrawHUD user function that would draw directly onto the surface before flipping so that you don't get the flicker problems with drawing to the HWND on a timer.

Credit to http://www.codeproject.com/KB/DLL/apihijack.aspx for the apihijack source that made this possible.
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
In my quest to get a decent looking HUD from an MFD rather than vessel code, I've tried another method and again hit a wall. This time I got really close.

The concept I had this time was to do API hooking. The basic premise of this is you replace by sneaky means a call to a standard API (In this case, DirectDrawCreateEx) with your own call so that when the client application (in this case Orbiter.exe) calls it, it's actually calling your own code.

If you're going as far as hooking, what about hooking the VESSEL2-methods? Of course it wouldn't work for standard VESSEL-objects, but most of the addons are VESSEL2 anyway. It is just virtual table hooking - and safer than direct API hooking IMHO - but you can use clbkDrawHud of every VESSEL2-class in your scenario this way. Much like the obsolete global callbacks from the ancient vessel interface.

If you're interested, I've some code handy...

regards,
Face
 

agentgonzo

Grounded since '09
Addon Developer
Joined
Feb 8, 2008
Messages
1,649
Reaction score
4
Points
38
Location
Hampshire, UK
Website
orbiter.quorg.org
Interesting. I hadn't though of that. Though the hooking done via apihijack is for global functions rather than class methods, so I'm not sure that it can be made to work on those.
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
Interesting. I hadn't though of that. Though the hooking done via apihijack is for global functions rather than class methods, so I'm not sure that it can be made to work on those.

I'll pack something together... will be back in a few mins...

EDIT:

Back again... take a look at this...
The last entry there is a link to a ZIP-archive containing the hooking classes I used in OMP-client to record VESSEL2 callbacks in order to transmit them via UDP. I commented clbkDrawHud, because I didn't need that event back then. It shouldn't be a big hurdle to implement it based on the other callback-hooks.

To install the hooks on all classes, I used the following procedure in the client's startup-code:
Code:
c=oapiGetVesselCount();
for(i=0; i<c; i++)
{
       InstallVesselHook((VESSEL2 *) oapiGetVesselInterface(oapiGetVesselByIndex(i)));
 }
and this in the client's shutdown-code:
Code:
CleanUpHooking();
I don't know if it works from scratch in this form, but hope it helps, anyway...

cheers,
Face
 
Last edited:
Top