Drawing Overlay inside DX11 Game (CryEngine) with C# and EasyHook

radonthetyrant picture radonthetyrant · May 25, 2014 · Viewed 7.3k times · Source

What I want to do:

I have a Game based on CrySDK which is DirectX11 and I want to draw an ingame overlay like the steam overlay.

-> I write C# since I don't know any C++, so I'm looking for ways to do this in C#.

-> I use EasyHook and SharpDX Libaries because it seems this is the best way to go.

-> I found a reference project which is apparently some kind of hack for SC2, I'm just interested in the overlay part however.

-> I use Visual Studio 2013

-> For now I'd be happy if I could draw random stuff inside a game at all

What I did so far:

I was looking through google and SO search results, problem is, that either the stuff is in C++, C or other, the results are from 2010 and not up to date with the current dx11, contain dead links or are unusable for any other reasons. This covers 95% of all I've turned up myself, some usuable hints have been included into my code.

I managed to create a Injector.dll and inject it into the game (at least i think it is injected, haven't had any usuable results so far)

What I have:

The file which does the injection:

...                
// Try inject thingy

            EasyHook.Config.Register("Star Citizen Noise.sc Client Overlay",
                                    //         "Direct3D9Hook.dll",
                                             "SharpDX.dll",
                                             "SharpDX.Direct3D11.dll",
                                             "Injector.dll");

            // Do the inject
            RemoteHooking.Inject(scProcess.Id, InjectionOptions.DoNotRequireStrongName, "Injector.dll", "Injector.dll", "Star Citizen Noise.sc Injector.dll");
            Console.WriteLine("DLL Injected.");
...

The injector.dll itself consists of this file, called Hooks/Graphics/Direct3D11Hook.cs (I tried to keep the structure similar to the oter sc2 reference project)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Runtime.InteropServices;
using EasyHook;
using SharpDX;
using SharpDX.Direct3D11;
using Rectangle = SharpDX.Rectangle;

namespace Injector.Hooks.Graphics
{
    public class Direct3D11Hook : HookBase
    {

        private Device device = null;

        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
        private delegate Result EndSceneDelegate(IntPtr devicePointer);

        public delegate void EndSceneEventDelegate(ref IntPtr devicePointer);
        public event EndSceneEventDelegate OnEndScene;

        private Result EndScene(IntPtr devicePointer)
        {
            try
            {
                //this.Log.LogMethodSignatureTypesAndValues(devicePointer);

                //GetOrCreateDevice
                if (this.device == null)
                    this.device = Device.FromPointer<Device>(devicePointer);

                if (this.OnEndScene != null)
                    this.OnEndScene(ref devicePointer);

                System.Drawing.Graphics g = System.Drawing.Graphics.FromHdc(devicePointer);
                //System.Drawing.Graphics g = System.Drawing.Graphics.FromHwndInternal(devicePointer);

                // lets try to draw something
                Pen myPen = new Pen(System.Drawing.Color.Pink, 4);
                System.Drawing.Point P1 = new System.Drawing.Point(50, 50);
                System.Drawing.Point P2 = new System.Drawing.Point(500, 500);
                g.DrawLine(myPen, P1, P2);
                g.Dispose();
                //this.device.EndScene();

                return Result.Ok;
            }
            catch (SharpDXException ex)
            {
                //Log.Warn(ex);
                Console.WriteLine(ex);
                return ex.ResultCode;
            }
            catch (Exception ex)
            {
                //this.Log.Fatal(ex);
                Console.WriteLine(ex);
                return Result.UnexpectedFailure;
            }
        }

        public override void Install()
        {
            try
            {
                EndSceneDelegate esd = new EndSceneDelegate(this.EndScene);

            }
            catch (Exception)
            {

                throw;
            }
        }

        public override void Uninstall()
        {

        }

    }
}

Here I tried to provide an override function for the EndScene function, because i think this is where I need to be. Needless to say, nothing appears to be drawn.

The delegate definitions are somewhat of a copypaste from the reference project however I have yet to find out how to actually hook my function into the render pipeline and/or react to events which might help my cause.

There is also this huge file [https://github.com/jasonpang/Starcraft2Hook/blob/master/Game/Hooks/Graphics/Direct3D9.cs] which defines function addresses which seems to work for DX9, I don't think that it can just be copy pasted and used for DX11 as well, so probably there are new function addresses in DX11? How can I find those? Where do I need to look? Is it something SharpDX can help me with?

TL;DR

Want to create steam-like overlay for DX11 game, need to hook into D3D stuff and magic and shit, got dll inject working, need help with pipeline injection

Answer