C# - Screen Capture and Overlays For Direct3D 9, 10 and 11

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 128

Spazzarama

C#, DIRECT3D, PROGRAMMING

C# – SCREEN CAPTURE AND OVERLAYS


FOR DIRECT3D 9, 10 AND 11 USING API
HOOKS
MARCH 14, 2011 | JUSTIN STENNING | 337 COMMENTS

So it’s been almost a year and I have finally got around to finishing a new version of my
screen capture project that supports Direct3D 9, 10, and 11! This solution still uses
SlimDX for the Direct3D API wrapper along with EasyHook to perform the remote
process hooking and IPC between the host process and target process.

Some of the changes since the previous version:

1. 100% C# implementation
2. Added Direct3D 10 and 11 support
3. Capturing multi-sampled/anti-aliased images (for 10 & 11) is supported
4. Re-organised code making it easier to support multiple D3D versions
5. Implemented a new and improved test bed application
6. Provided example overlays for D3D 9 and 10
7. Improved debug messaging from Target application to Host (mostly removed when
compiled with “Release” configuration)

Update 2012-04-14: code now hosted on Github

Prerequisites
Like the previous post you need the SlimDX June 2010 SDK or Runtime, and it is useful
to have the DirectX SDK handy to try screenshots on their samples.

The download already includes the EasyHook binaries, but if you want to download
them yourself you can find them at CodePlex here.

C# only Implementation
Previously I had a C++ helper DLL to get the VTable addresses.
This has been replaced with the following C# implementation:

1 protected IntPtr[] GetVTblAddresses(IntPtr pointer, int number


2 {
3 List vtblAddresses = new List();
4
5 IntPtr vTable = Marshal.ReadIntPtr(pointer);
6 for (int i = 0; i < numberOfMethods; i++)
7 vtblAddresses.Add(Marshal.ReadIntPtr(vTable, i * IntPt
8
9 return vtblAddresses.ToArray();
10 }

Adding Direct3D 10 and 11 Support


Direct3D 10 and Direct3D 11 have a completely different rendering pipeline com-
pared to Direct3D 9, making use of the DirectX Graphics Infrastructure (DXGI). We
now hook the IDXGISwapChain.Present method to capture in D3D 10 & 11.

The capture method used in Direct3D 10 and 11 is also more thread-safe allowing us
to extract data from the resulting texture on a background thread. This reduces the im-
pact to the frame rate.

We are also able to copy only the region of the backbuffer that we are actually inter-
ested in – making the capture of smaller regions quicker as less data needs to be
copied to system memory. This also will make capturing a sequence of frames for use in
video production much easier.

Note: I believe that D3D9Ex (Vista+ shared surfaces – e.g. DWM) also uses the DXGI
Present but haven’t looked into this in greater detail as the EndScene hook in Direct3D
9 achieves what we are after also.

Support capturing Multi-Sampled (anti-aliased) Images


Direct3D 10 and 11 both provide the ResolveSubresource method
(Direct3D10.Device.ResolveSubresource, and
Direct3D11.Device.ImmediateContext.ResolveSubresource), that makes it easy to re-
solve a multi-sampled texture down into a single sample for copying into a Bitmap.

D3D 10 code:

1 // If texture is multisampled, then we can use ResolveSubresou


2 Texture2D textureResolved = null;
3 if (texture.Description.SampleDescription.Count > 1)
4 {
5 this.DebugMessage("PresentHook: resolving multi-sampled te
6 // texture is multi-sampled, lets resolve it down to a sin
7 textureResolved = new Texture2D(texture.Device, new Textur
8 {
9 CpuAccessFlags = CpuAccessFlags.None,
10 Format = texture.Description.Format,
11 Height = texture.Description.Height,
12 Usage = ResourceUsage.Default,
13 Width = texture.Description.Width,
14 ArraySize = 1,
15 SampleDescription = new SlimDX.DXGI.SampleDescription(
16 BindFlags = BindFlags.None,
17 MipLevels = 1,
18 OptionFlags = texture.Description.OptionFlags
19 });
20 // Resolve into textureResolved
21 texture.Device.ResolveSubresource(texture, 0, textureResol
22 }

Direct3D 9 and 10 Overlays


I have implemented two sample overlays for Direct3D 9 and 10.

The D3D 9 example displays the frame rate and draws a box with a cross in the middle
to identify the region that was captured – this fades after 1sec.

1 #region Example: Draw Overlay (after screenshot so we don't ca


2
3 #region Draw fading lines based on last screencapture request
4 if (_lastRequestTime != null && _lineVectors != null)
5 {
6 TimeSpan timeSinceRequest = DateTime.Now - _lastRequestTim
7 if (timeSinceRequest.TotalMilliseconds < 1000.0)
8 {
9 using (Line line = new Line(device))
10 {
11 _lineAlpha = (float)((1000.0 - timeSinceRequest.To
12 line.Antialias = true;
13 line.Width = 1.0f;
14 line.Begin();
15 line.Draw(_lineVectors, new SlimDX.Color4(_lineAlp
16 line.End();
17 }
18 }
19 else
20 {
21 _lineVectors = null;
22 }
23 }
24 #endregion
25
26 #region Draw frame rate
27 using (SlimDX.Direct3D9.Font font = new SlimDX.Direct3D9.Font(
28 {
29 if (_lastFrame != null)
30 {
31 font.DrawString(null, String.Format("{0:N1} fps", (100
32 }
33 _lastFrame = DateTime.Now;
34 }
35 #endregion
36
37 #endregion

The D3D 10 example simply displays the current date and time:

1 #region Example: Draw overlay (after screenshot so we don't ca


2
3 using (Texture2D texture = Texture2D.FromSwapChain(swapChain,
4 {
5 if (_lastFrame != null)
6 {
7 FontDescription fd = new SlimDX.Direct3D10.FontDescrip
8 {
9 Height = 16,
10 FaceName = "Times New Roman",
11 IsItalic = false,
12 Width = 0,
13 MipLevels = 1,
14 CharacterSet = SlimDX.Direct3D10.FontCharacterSet
15 Precision = SlimDX.Direct3D10.FontPrecision.Defaul
16 Quality = SlimDX.Direct3D10.FontQuality.Antialiase
17 PitchAndFamily = FontPitchAndFamily.Default | Font
18 };
19
20 using (Font font = new Font(texture.Device, fd))
21 {
22 DrawText(font, new Vector2(100, 100), String.Forma
23 }
24 }
25 _lastFrame = DateTime.Now;
26 }
27
28 #endregion

Unfortunately Direct3D 11 does not provide any support for Direct2D / Fonts for our
overlay, so you would need to create a D3D 10 device with a shared texture, and blend
this into the D3D 11 backbuffer
(see http://forums.create.msdn.com/forums/t/38961.aspx and
http://www.gamedev.net/topic/547920-how-to-use-d2d-with-d3d11/).

Issues
1. I have found that often a target 64-bit process will hang if your host application (e.g.
the test bed) closes before the target process, I could not determine what the cause
was, but I’m guessing it has something to do with EasyHook (unconfirmed)
2. No example overlay for Direct3D 11 yet
3. If you try to inject / capture using the wrong Direct3D version you could crash your
host or target application
4. Load test in D3D11 would be slow if host application (e.g. test bed) does not have
focus – not sure where the delay is there

Some Numbers
Direct3D 9 – SDK Sample Blobs (640×480)

Time spent in render pipeline ~8ms


Total time to request and retrieve a capture ~50ms

Direct3D 10 – SDK Sample CubeMapGS (32-bit) (640×480)

Time spent inside render pipeline ~1-2ms


Total time to copy backbuffer, copy result into system memory and send back re-
sponse ~70ms
Total time to request and retrieve a capture ~100-130ms

Direct3D 11 – SDK Sample SubD11 (640×480)

Time spent inside render pipeline ~1-2ms


Total time to copy backbuffer, copy result into system memory and send back re-
sponse ~70-80ms
Total time to request and retrieve a capture ~150-200ms

Examples

Direct3D 9: SDK Sample Blobs

D3D9 Blobs Overlay and Capture

Direct3D 10: SDK Sample CubeMapGS


D3D10 CubeMapGS Overlay

D3D10 CubeMapGS Capture

Direct3D 11: SDK Sample SubD11

D3D11 SubD11 Capture

Download
You can access the source on Github here

It’s also recommended you read the previous


post

.NET C# DIRECT3D DIRECTX EASYHOOK HOOK SCREEN CAPTURE

SCREENSHOT
337 THOUGHTS ON “C# – SCREEN CAPTURE AND OVERLAYS FOR DIRECT3D 9,
10 AND 11 USING API HOOKS”

Pingback: C# – Screen capture with Direct3D 9 API Hooks « Justin's Blog

air
MARCH 28, 2011 AT 4:51 PM

Excuse my silly question but do you think it can capture the whole desktop ? I just
come to the illution that the dwm.exe or somewhat is a d3d10.1 application (in
some way) with the responsibility to draw the screen display frame buffer…in
win7. it’s not correct, or not?may i have your op?

 Justin
MARCH 28, 2011 AT 7:31 PM

Not a silly question at all.

My guess is that yes this would be possible, somehow 🙂

I have created a quick Direct3D 10.1 version of the hook and disabled the bring
to front and can successfully hook the DWM process, however as yet I have no
images captured.

I’m going to take a closer look at the source code in the following link (a DWM
Win 7 Hack demo) and see what methods they are hooking in the 10.1 device.

Not sure when I will get to it due to current busyness tho.

Cheers,
J
Milo
MAY 8, 2011 AT 3:39 AM

Hell,
I’d very interested in desktop capture using this method as well. I’m investi-
gating low-latency desktop capture like this – lots of exciting possibilities…

Reece
MAY 30, 2014 AT 7:39 AM

Hello, Not sure if you check this but im using your class and im trying to save
the captured data to video however there isnt a function to get a continuus
stream so im having to to constantly call getscreenshot which is an issue be-
cause the frame rate is all messed up and it causes the program to crash. Is
there a way i could record the data thats captured? Thanks Reece.

 Justin Stenning
JUNE 2, 2014 AT 5:31 PM

Yes you can do this by modifying the injected code to implement additional
logic during frame capture (i.e. within the Present hook).

As you have found, capturing frames and passing along an IPC channel for
the purpose of real-time video creation is far too resource intensive.

Michael
MAY 25, 2011 AT 5:06 AM

Hi there,

I tried to change your code, so I can hook the DirectXDevice9::Present function,


but if i try this, the injected program always crashes. The reason for catching
Present is because there might be multiple EndScenes before the final scene is
rendered, so this seems to be the way to go.

I’m pretty stumped here, even an empty function just returning the return value of
Device.Present leads to a disaster.

Did you try something similiar yourself or do you have any hints for me?

 Justin
MAY 25, 2011 AT 10:01 AM

Hi Michael,
Yes I have been able to hook Present. Can you post the code you are using in-
cluding method signature for Present?

Does it crash when trying to hook, or when the hooked method is called?

Cheers,
J

Michael
MAY 26, 2011 AT 12:57 AM

Hi Justin,

thanks for your fast answer. I posted the relevant code parts here:
http://nopaste.info/bbc64b7673.html

I forgot to include the delegate, but it corresponds to the function definition,


which I just checked.

It seems to crash after the hook is called. I also tried to just return 0 from the
hook, but the result is the same.

 Justin
MAY 26, 2011 AT 7:48 PM

Hi Michael,

I’m pretty sure you need to be using Int32 in your RECT structure not Int64
(check pinvoke.net or SlimDX has a wrapper/converter), everything else
looks good to me.

Let me know how you go. I’m not on my dev machine and I’m in the middle of
moving it to a new machine so can’t test right now.

Cheers,
J

Michael
MAY 27, 2011 AT 1:38 AM

After I had some problem yesterday with my assembly not being updated
in the GAC, this is what I’m confronting today:
STATUS_INTERNAL_ERROR: Unknown error in injected assembler code.
(Code: 5)

This also happens with your unmodified code and is an exception thrown
by RemoteHook.Inject.

Damn it!

 Justin
MAY 27, 2011 AT 4:55 PM

Hi MIchael,

When you are starting to have issues with GAC etc, I usually try to find a
sample (e.g. Direct3D SDK sample) that I can copy to the bin directory of
my project (or copy all my binaries to the destination application direc-
tory), and run without having to install anything other than the EasyHook
assembly to the GAC. Otherwise you can spend quite a bit of time debug-
ging issues that are due to out of date assemblies and so on.

It is also much easier to attach to the target process for debugging if the
injected assembly is not in the GAC.

Good luck. If you continue to have issues you can contact me via the con-
tact page and subsequently email through a project or something.

Cheers,
J

 Justin
MAY 28, 2011 AT 10:03 AM

Hi Michael,

Try the following:

gedFunctionPointer(CallingConvention.StdCall, CharSet = Cha


e int Direct3D9Device_PresentDelegate(IntPtr device, ref RE

sentHook(IntPtr devicePtr, ref RECT sourceRect, ref RECT de

ng (Device device = Device.FromPointer(devicePtr))

//this.DebugMessage("PresentHook");
using (Region region = Region.FromHrgn(pRgnData))
{
return device.Present(Rectangle.FromLTRB(sourceRect.le
}
Cheers,
J

Lucas
NOVEMBER 19, 2011 AT 9:02 AM

Hey Justin, that code doesn’t work for me. How is your RECT struc?

Lucas
NOVEMBER 21, 2011 AT 12:24 AM

I did make it work. Dunno what was the problem. I’m using Int32 in the
RECT struct.

Reece
JUNE 9, 2014 AT 7:53 PM

Hey Justin,

I’ve been trying to recored the present ex hook to no avail I wondered if


you had tips or ideas on how to do it it’s been bugging the hell out of me
for days!

Thanks!

Threk
JUNE 3, 2011 AT 8:55 AM

If I inject it, the app stucks.


It seems that he cant find the process, but the process is open and I’ve written the
right name( Wow.exe).
He is hanging in the !newInstanceFound loop.

 Justin
JUNE 3, 2011 AT 10:29 AM

Hi Threk,

What Direct3D version did you use when you hooked? I’m pretty sure you need
to use Direct3D 9 with WoW.

Cheers,
J
Threk
JUNE 3, 2011 AT 5:33 PM

Yes, I’ve used Direct3D 9.


My D3D Hook in c++ works fine with Wow.
Mybe we can write in icq? 🙂
376916619

Threk
JUNE 4, 2011 AT 7:04 PM

I’ve compiled the project with Visual studio 2010.


Maybe it dont work with vs 2010 ?

 Justin
JUNE 4, 2011 AT 7:07 PM

I use VS 2010 as well.

Threk
JUNE 4, 2011 AT 7:20 PM

After chatting with Justin, we have found the problem.


You must type the process name without extensions.
So not Wow.exe but Wow.

OverlayGuy
JUNE 28, 2011 AT 5:27 AM

I simply try ti run TestScreenShot.exe as administrator and it fails all the time. It
hangs and the window title shows “Not responding”.
I am sure I installed Easy Hook, and SlimX.
What I need to do to get this sample to work?

Do you have another sample that allows TEXT output on the screen?

I appreciate your work, effort and help.


Thanks.

 Justin
JUNE 28, 2011 AT 5:41 PM

1. Make sure you don’t have “.exe” in the process name.


2. Make sure the ScreenshotInject.dll is also registered in the GAC. I also some-
times have to reboot my machine after installing in GAC then attempt to hook.

The DirectX 9 version has text output (frames per second). Otherwise check
SlimDX examples on their website, you might find some useful bits on using
SlimDX to render text there.

Good luck!
J

chen
JULY 12, 2011 AT 10:44 AM

i have the same question with you ,i want to know how to solve this problem if
you have correct it.thank you for your reply

chen
JULY 12, 2011 AT 3:06 PM

hi,Justin.
before i run this program,i registered the easyhook.dll,screenshotinject.dll into
GAC.but the slimdx.dll couldnt registered ,its give the message “Unknown
option:filesslimdx”.i have install the slimdx SDK and slimdx.dll exsist in the install
directory.

then i reboot my machine,and run your program use


ParallaxOcclusionMapping.exe for example ,the UI only display messages as
below:

2904:DXHookD3D9: Hook: Device created


2904:DXHookD3D9: Hook: Before device creation
2904:DXHookD3D9: Hook: Begin
2904:64-bit Process: False
2904:DLL Injection succeeded

why 64-bit process :false,and how can continue to use your program,look farward
to your reply

 Justin
JULY 12, 2011 AT 9:05 PM

Hi Chen,

That is all working fine, it just means that the ParallaxOcclusionMapping.exe is a


32-bit application.
Try taking a screenshot from there, and let me know if the overlay is appearing
for you.

If it doesn’t work from here, try the other D3D version options.

Cheers,
J

chen
JULY 13, 2011 AT 11:14 AM

i run this program in two conditions .one is win 7 ,in this condition the pro-
gram works fine and i can run directx sdk samples in Direct3D10.another con-
dition is window xp professional 2002,in this conditions there have some
problems as follows:
when i click the inject button ,its display an error dialog ,the title is “a client
process (3868) has reported an error…”,the content is
“system.runtime.interopservices.sehexception:
in createdxgifactory(_guid*,void**)
in slimdx.dxgi.factory..ctor()
in screenshotinject.dxhookd3d10,hook()”
directx sdk samples in Direct3D10 didnt work,it shows “Could not initialize
direct3d 10.this application requires a direct3d 10 class device (hardware or
reference rasterizer)running on windows vista(or later)
Is my os version wrong?
Only os version is different in This two condition

 Justin
JULY 13, 2011 AT 12:42 PM

Hi Chen,

Windows XP only supports up to Direct3D 9. To use D3D 10 or above you


must have Vista or later.

Cheers,
J

chen
JULY 13, 2011 AT 7:08 PM

hi justin,thank you very much to anser my question patiencly,now i have


changed my os to win7,but when i clicked the inject button ,it shows that
“shadowmap,exe have already stopped work”,another examples have the
same conditions ,i am comfused.i installed Microsoft DirectX SDK (June
2010),and my graphics is intel g41 express chipset

 Justin
JULY 13, 2011 AT 10:08 PM

Hi Chen, I’m not really sure what is happening here, I can’t remember get-
ting that message at all. When you run shadowmap.exe without trying to
inject is it working correctly? Perhaps you could use the contact page to
send through PM details or so that I can request some screenshots.

Cheers,
J

chen
JULY 14, 2011 AT 5:28 PM

hi justin,now the progarm can work now,i install the related softwares
again.so it can work.thanks for guiding

 Justin
JULY 14, 2011 AT 5:31 PM

Glad to hear it and good luck!


Cheers,
J

sdecorme
JULY 15, 2011 AT 7:59 PM

Hi,
Do you think with a hook system is it possible to get vehicule movement from a
game like rfactor or sbk that use directx ?
Thanks

 Justin
JULY 16, 2011 AT 7:50 PM

I think it’s possible, but you would need to do a fair amount of memory checking,
or debugging using something like OllyDbg to determine where you might be
able to hook to get this information. I don’t really have the skills or experience in
this area, so if you’re interested in this type of thing you should take a look over
at http://gamedeception.net
Cheers,
J

OverlayGuy
JULY 27, 2011 AT 6:35 AM

Is the captured screen shots supposed to appear on the dialog box itself? Or it is
saved in a file? If on a file, where should I find it? I was able to run the injection suc-
cessfully, however I never seen the captured screen images yet.
Thanks.

 Justin
JULY 27, 2011 AT 8:53 AM

It appears in the dialog box itself.

Play with the different DirectX versions, and if that still doesn’t get you any-
where you will be able to remotely debug the injected process and add break-
points in the Screenshot.dll project (just untick “Just My Code” in the debugger
settings).

Process explorer (http://technet.microsoft.com/en-us/sysinternals/bb896653)


is a great tool for checking which D3D dll’s are being used.

Cheers,
J

silek65
JULY 30, 2011 AT 9:54 PM

Hi

I’m looking for a good method of capturing screen with a great/best as possible
performance from MPC-HC latest one version (where is a problem to capture
screen from .NET – blank screen on EVR surface) or from older one 1.2.1008.0
where I’m able to capture from EVR surface even GetBackBuffer(1), .NET and
GDI32.

Unfortunatelly in Windows 7 (only, Windows Vista works fine!) with two displays
connected I cannot use GetBackBuffer method anymore. Reason? When MPC-HC
1.2.1008.0 is playing video on a primary screen through EVR DX Fullscreen sur-
face it works fine, but when it is playing this movie a on a right, second screen (sec-
ondary-extended desktop), than I see some strange on a captured image – video
picture from player is shifted to the right with width from primary screen (but in
real video is located on a second screen). I know it’s hard to understand, but let me
desribe:

Primary Secondary
1680 1920
——- ———-
#### xxxxxxx->shifted by 1680
——- ———-
1050 1080

But DX GetBackBuffer captures picture from 2nd monitor shifted by 1680px to


the right so it’s something like that:
http://qnapclub.pl/qnas/epiLightDX/Windows_7/bug.jpg

I’m working on some DIY Ambilight project and I’m still looking for best way to
capture screen. I see you are best of best guys in a screen capturing so I would like
to get advise from you guys or even some perfect source code to do this magic
trick 🙂

Thanks and Best regards

 Justin S.
JULY 31, 2011 AT 7:45 PM

Try specifying the coordinates for the capture with this in mind, does it then
work correctly?

Cheers,
J

 Justin S.
JULY 31, 2011 AT 7:52 PM

Btw – there are some other comments in this blog somewhere of some
Ambilight stuff, they had a URL to their modified screen capture taking into con-
sideration anti-aliasing as well. Also they were simply scaling the image down to
approx. a 4×4 pixel image which made it super fast (since it was only for
ambilight).

The URL is:


http://gathering.tweakers.net/forum/list_message/34384265#34384265 (site
is in Dutch I think) and you are looking for posts by Gerrit.
silek65
JULY 31, 2011 AT 9:50 PM

Thank you for an answer.


“Try specifying the coordinates for the capture with this in mind, does it then work
correctly?”
Correctly for a first few seconds (~10sec.) only or shorten when LB mouse clicks
on some Window(/Explorer) which will shift video image.

Do you understand Dutch? Can you explain me to understand what’s different be-
tween these two:
http://gathering.tweakers.net/forum/list_message/34384265#34384265
and
http://gathering.tweakers.net/forum/list_message/34390719#34390719

Do you know if there is a full working source corde to capture the screen (even to
capture one frame) by this method? I would like to see proper use of this method.
I’m convinced that you are an expert in screen capturing with .NET C#, but I do not
want to ask you for detailed help in this issue and I don’t want to waste your time,
because that blog and published news in it are truely amazing! I’m really im-
pressed. Respect bro!

Thanks once again!

 Justin S.
AUGUST 1, 2011 AT 5:45 PM

Use google translate or something similar to translate them. I don’t think there
is any real functional difference between the two. The second one recreates the
render target each time which would probably mean no other resizing checks
are required in the Device.Reset.

Both of those links are modifications of the Direct3D 9 hooking I have here on
this site.

I might take a look at MPC-HC myself and see what’s going on. But not sure
when I will get around to it.

Cheers,
J

 Justin S.
AUGUST 1, 2011 AT 8:20 PM

Hi,

I have taken a look and the black area you are referring to is probably because
the device created by the MPC-HC app is of that size and displaying black
around the video it is playing back.

In my tests at fullscreen on my second display it would capture fine. The capture


would only include the actual video picture even though the video playback had
a little extra black due to different aspect ratio of video to screen.

In windowed mode there is a small black area captured at the bottom of the
screen (behind where the video playback controls appear). Or if I have the win-
dow sized incorrectly for the image aspect ratio the black would appear else-
where as appropriate.

In windowed mode you will find that it is capturing the entire image including
black, so you would need to crop out the black area, unfortunately this is just the
way the MPC-HC app is rendering to the DirectX surface.

In fullscreen you shouldn’t have any issues – or at least I could not duplicate the
same thing you say you are experiencing in fullscreen.

Cheers,
J

Guest
AUGUST 1, 2011 AT 4:18 AM

I was getting GAC issues as well, downloading the latest EasyHook binaries from
EasyHooks website fixed the issue for me. Just letting anyone else having issues
know.

silek65
AUGUST 2, 2011 AT 2:43 AM

Thank you Justin for everything, but I spent last 20 hours with non-sleep and just
looking and trying to make screen capture working through GetBackBuffor, but
unfortunatelly output is alwayas BLACK.

If anyone would like to check this:


http://pastebin.com/8D8nGqu2
Please! Thanks!
Going get some rest now 🙂

 Justin S.
AUGUST 2, 2011 AT 8:01 PM

Hi,

You cannot capture the backbuffer from outside of the process that creates the
Direct3D device (unless it does some stuff with cooperative mode).

This is why it is always black for you in that sample code. My code gets around
this by hooking the target process and running the capture from within the same
process.

Try this: copy the TestScreenshot.exe along with the rest of the bin folder of this
sample into the directory that has mpc-hc64.exe (or mpc-hc.exe I guess if 32-
bit). Then try to run it, type the executable name in (without .exe) in the screen-
shot test bed and it should capture fine for you.

Good luck!
J

chen
AUGUST 6, 2011 AT 1:16 PM

Hi, Justin
Please forgive me to disturb you again
are you sure this program can work fine in windows xp.

i want to work this in windows xp.but always if fails,i mean the captured image
didnt display in the pictureBox1,

i debug it ,i find the code behind


“id3dDeviceFunctionAddresses.AddRange(GetVTblAddresses(device.ComPointe
r, D3D9_DEVICE_METHOD_COUNT));” didnt be implemented. i add try catch ,i
display DXHookD3D9: D3DERR_INVALIDCALL: Invalid call (-2005530516).i dont
know why?can you give me some information?

i know it can work in my computer if i install windows 7.

 Justin S.
AUGUST 6, 2011 AT 2:23 PM
My guess is that the error is actually around the creation of the temporary de-
vice to then get the method addresses from (e.g. incorrect parameters or
something).

The best thing to do is to install the DirectX SDK and enable the debug mode in
the DirectX control panel included in the SDK. This will allow you to enable trac-
ing and be able to see the actual errors that are occurring under the hood.

Cheers,
J

silek65
AUGUST 19, 2011 AT 1:55 AM

Hi Justin S.

Well your method really works. I see you have a lot of experience and passion to
create the way to capture screen from application. Can you tell us what is the rea-
son why you do that? You helped me a lot…!!! in DIY AmbiLight! Thanks for that.

But I like the way how “Taksi” application works. No needed to inject Hook before
surface is created. How this works?

Also I have tried your method with the game Starcraft II which uses DX9. When I
set in options of the game “Fullscreen”, then your method does not work. But when
I have changed to “Windowed (FullScreen)” then it works. So is there a method to
make it working also for DX Fullscreen?

Thanks and Best regards!

 Justin S.
AUGUST 19, 2011 AT 6:31 PM

Hi silek65,

The main reason was because I saw it as a challenge, and wanted to solve the
puzzle. But since them I have been more interested in looking at doing game
overlays, and also I would like to try a DIY AmbiLight project of my own. Most
importantly it is something people have found useful and I’m happy to continue
working on it while that is the case.

I’m not sure I understand your question about “Taksi”, the solution on this blog
allows you to inject at any time rather than only at the start of the application.
Fullscreen to windowed should also work fine – check if anti-aliasing is enabled
in fullscreen and disable it perhaps that is the issue? Also try injecting when it is
already in fullscreen and see if that works, it could be that the DeviceReset code
is not getting called correctly on change of the device dimensions.

Glad you found this useful, that’s why it is here.

Cheers,
J

silek65
AUGUST 22, 2011 AT 4:27 AM

Hi Justin 🙂

Okay so let me write all steps I’m doing and can’t get Inject working while the app
is already run.
(OS: Win7 x64)
1) Started Screenshot Hook app
2) Started mpc-hc.exe (1.2.1008.0) x86
3) Loading and Starts playing movie
(FIY Movie is created on a window handle called: “MPC D3D FullScreen”, rect:
[1920 x 1080], (1680,0)-(3600,1080), class:
Afx:00400000:b:00010021:00000006:00000000)
4) Switched back to Inject Hook app and entered:
EXE Name: mpc-hc
Direct3D 9 selected
Auto register GAC checked
5) Pushed Inject button and log is:
4500:DXHookD3D9: Hook: Device created
4500:DXHookD3D9: Hook: Before device creation
4500:DXHookD3D9: Hook: Begin
4500:64-bit Process: False
4500:DLL Injection succeeded

Q1) And I cannot inject it while movie is played. So what’s wrong?

Q2) Sometimes I see another MPC-HC surface blink for a 1 frame shot… normally
it is capturing clean movie surface, but sometimes I see a fast blink with content
from whole display surface including subtitles. I have also observed that this hap-
pens only when CPU is overload much – no issue while >70% of CPU resources are
free.
Q3) May you suggest me a way to make a fast blur GetBackBuffer D3Dv9 surface?
I was trying to find some help on a Web, maybe sample code but unfortunatelly I
did not find it.

[quote]also I would like to try a DIY AmbiLight project of my own[/quote]


GREAT! THAT’S AWESOME NEWS! Let me say something about my software
project named epiLight for MoMoLight compatible controllers (S/W at begining
based on some old source BobLight Windows source which is not actually used
anymore – first time used C# – thank god for it)

I’m implementic your fast method of screen capturing into my old-based software
epiLight and I’m fixing some buggy like-a-video-processing issues to make soft-
ware easier to use and manage
…and to bring a user totally new dimension of a movie view in his own home cin-
ema. This is done by new True-Cinema +Expansion mode which analyse input
“image”/colours and dynamicly changes voodoo settings to best one for currently
displayed picture.

When epiLight software will be ready, then as always I’ll post all C# sources on a
AmbiLight4PC forum – doing this to keep project alive. – where a lot of other DIY
AmbiLight users are not doing that! WRRR! and this does NOT help to the project!

Hope you’ll also enjoy it!


You need to know that you are the GUY, who made revolutionary STEP for a DIY
AmbiLight!

Here are some detailed words about my software:


epiLight is only one available app which supports MoMoLight V3 protocol with ex-
tra data: inverted checksum to prevent “blank blinks” on some cheap RS232USB
adapters.
It is compatible backward – 3rd party MoMoLight v1/v2 compatible software
works fine on a v3 FW:
(software sends init v3 string, device checksum flag is switched on and from now
unit is expects new data format from a software)
v2: R1R2R3G1G2G3B1B2B3
v3: $R1R2R3G1G2G3B1B2B3CHKS [inverted: FF FF – checksum]

..

Anyway in same time I’m working on a totally new app called AmbiLED, when I’m
going to use your code and I guess I’ll ask you for some help
Bellow is some my feature/working note – I didn’t read it yet …
http://pastebin.com/wpqfH6Wq

Hope to see you ASAP with AmbiLighters 🙂

 Justin S.
AUGUST 24, 2011 AT 10:10 PM

Q1) I can’t see what’s wrong there, it is a bit weird what is happening. Maybe the
creation of the temporary device/surface is causing the issue but I really don’t
know at the moment

Q2) Again not sure ( i haven’t played with MPC-HC a great deal, but from what I
had already seen it had a few weird things going on with view port placement
that we discussed previously, so maybe some more such things?)

Q3) Yes, you can scale the surface down to a 4×4 pixel image using DX (or simi-
lar), and this will give you the colour averages etc.. (is this what you are after?)
This is how some other AmbiLight users used this code.

Cheers,
J

silek65
AUGUST 24, 2011 AT 11:47 PM

Q3) Well, regarding to the solution with 4×4 sufrace resize I’m not really happy
with it.
Ambi is producing a lot of unwanted blinks.
But when I’m resizing surface to, let say 192×108 and then saved into unsafe bit-
map to perform faster GetPixel operation, then my average colour is more precise
then mentioned 4×4 solution.

I think D3D9 uses some fast method to perform resize operation. Looking onto
output surface which is really sharpen, it seems to me that resize is done on not all
pixels from original image. I believe it uses some step on pixels to perform it faster.

I don’t know… I just would like to try a method like that:


1) Resize > 192×108
2) Blur with radius 15px
3) (eventually resize again) Average GetPixels

topher
SEPTEMBER 26, 2011 AT 2:47 PM

silek,

Any luck with your implementation? Would really like to see the source code.
Checked most of your posts in ambilight4pc forums, but all the download links
for binaries and source are dead. Have a custom LED hardware I want to use
against it. Curious how you’re handling the resize, blur, and get average pixels
like you talked about above.

Silas, Mariusz Grzybacz


JANUARY 28, 2012 AT 12:02 PM

Hi there! Sorry for the VERY late reply. I had to stop the project for a while…
Too bad I didn’t published the source code before. I have done this just right
now. So we lost few months with the project.

I just get an email from a guy who asked me for a source code… So I just zipped
all the stuff and sent him and also want to publish it here… …

Source code of the project you can download after you read the short note I
wrote:
http://qnapclub.pl/qnas/AmbiLED/software/AmbiLED/20110903/IMPORTA
NT_NOTE.txt
(Read before downloading or browsing zipped files)

Source code you can find in the directory I have all files:
http://qnapclub.pl/qnas/AmbiLED/
path: /software/AmbiLED/20110903/AmbiLEDd.NETv3.src.zip

 Justin S.
JANUARY 28, 2012 AT 8:55 PM

Hey Silas,

Good to see ur back around. Since you were last about a friend of mine and I
have also started a small ambilight clone project on GitHub (using Arduino
for the hardware), I’ll let you know when more is posted on this – we have a
working prototype haven’t yet refactored the project for source release in
GitHub. I’ll check out your project as well though, I don’t want to reinvent
the wheel 🙂

Cheers,
Justin
Silas, Mariusz Grzybacz
JANUARY 29, 2012 AT 6:15 AM

That’s perfect news!


But honestly I’m little bit dissapointed, because of platform you choose…
ofcourse Arduino platform is very popular. But I was thinking that maybe
you’ll go another way and you’ll take a try on a platform from Microsoft
.NET Gadgeteer – http://www.netmf.com/gadgeteer/ – seems it fit my re-
quirements enough! Someday I need to try it.

Anyway I’m waiting for even drafts of your project…

Also I would like to say something about the code I have provided. Well
🙂 Frankly speaking it’s a third version of the Ambilight module software
controller and I need to say, that on the first one I was learning .NET plat-
form and C# – previously I never had a chance to play with this platform.
So I know that this code is full of mess and contains a lot of lamy and
nooby calls.

From this time I have spent some weeks learning C#… So now with a little
bit better knowledge and experience in AmbiLight project I would like to
share with you my opinnions and maybe you’ll find something interesting
solution there… Please read them… BTW: Sorry for pure english I’m little
bit tired while writing this…
(let’s start with basics things…)
1) Many DIY AmbiLight users complained about the lack of dynamic chan-
nels support. So I can only suggest you to create channel data collection.
Each object should contain at least:
– source location (screen point/100%);
– some flags defining priority point: middle of the screen – not so impor-
tant, near to bounds of the screen – important. Let’s call this for fun
“smooth offset” or Gradient Importance… bleh what’s that? :>
– current RGB values;
– and a list of undefinied count of previous RGB values objects for next
cycles work (that will clear when collecting new data will be triggered
from finished Smooth-loop or from Aggresive Scene Changes Detector)

2) Support for external inputs from other software…


[not so important at software development time, but later will be helpful
to win the market with this software]
(in this feature I think there needs to be possibility to map by a user inputs
to specified channel outputs and smart communication between X app
with unknown data source and Y module with unknown LED channels)
3) It’s very cool when software could work like a winamp – with plugins
supports for inputs, outputs and maybe other …

4) (this one will be very hard to maintance and hard to code, but…)
Revolutionary in DIY AmbiLight projects that guarantees success and
hope it will invite more people to the project is support for profiles cre-
ated for each application – !and now attention! – with managed and
definied by user a way of data interpretation and calculation for channels
output values
In this I mean, that a user can decide about each mathematical function
position in the colour processing list but simple Blocks drag&drop on the
application GUI.
If the module (mathematical functions) requires another data inputs, then
user must connect it from another module on the calculation work dia-
gram.
Module can be everything, eg.
– parametr container (int, boolean, current RGB array, …)
– HSV or HSL of current/previous[x] colour,
– Nght switcher trigger
– Expand color module with external switch (eg. from Night switcher) to
change multipier to 3x during low room lightness – at night (with value
changed only at begining of working state to prevent LED intensity
changes – during the movie) and 3x multipier for daytime as default
– trigger: aggressive scene change detection
– Gamma correction (def 0.5; LCD/TV color != LED stripes color);
– Compensation (non-white wall behind TV);
– Color smoothing+Aggressive attacks;
– Scene colour expand (with mentioned day/night presets)

… I can help with that. This could be nice tool. But if we go so far, then in
same time we can bring to the user empty modules with possibility to en-
ter mathematical function by himself… And everyone one will be able to
build AmbiLight color calculation method…

.. That last point… Is it really necessary? Maybe you do not want to go this
way… But shorty let me tell you story about AmbiLight DIY status…
Tere was a lot of custom and different DIY projects with unique software.
This is a time where is a chance to built universal software controller with
non-limitted input data processing methods.
I think AmbiLight DIY projects are dieing… Most of other software
projects works terrible, some of them had flickering and some of them
long time waiting for colour change and other one works like a Quake 2
on 486DX2… So this is a chance to keep this project alive and bring to the
world best AmbiLight ever and even better then Philips.
And btw… before I’ll go to the next and last point, I can only say that last
modules conception comes when I saw FPS output when you bring us DX
Hook method 🙂 Let me explain you why…
5) When you managed a way to hook DX9 and I have implement it in the
software, then all I did in previous releases of AmbiLight was wrong and
not properly working after this. Software was displaying color changes so
fast…
(btw I’ll forgot later, so… capturing images through DX hook method
while 24Hz Refresh rate on a display device is set and movie is 23.978fps
(RefreshRate=FramePerSecond) produces slower image on screen with
few images per seconds only)
Anyway at 60Hz refresh rate it was displaying so fast… 1:1 that I didn’t ex-
pected while writing smoothing calculations… So I was needed to rewrite
all the stuff.

And I found solution that was best for eye with all movie effects on a
lightness effects. I think it’s is currently the best available for DIY
AmbiLight. Calculation are done in this order:
1) Input RGB values
2) Expand colour values with multipier 3x — important it prevent from
darkness low light flickering, and this will be reduced later by Gamma
3) When aggressive attack is set 64(one RGB value difference from previ-
ous 64 (eg. R value) triggers cycle from the begining and apply current
colour configuration
4) Smooth colour radius is calculated this way: [cut from my code]
http://pastebin.com/rWLEzKSp
5) Then output RGB value goes to Gamma (0.5) – settings depends on
RGB colours reproduction by AmbiLight from TV at middle colour value
(128)

And even I think this way of getting smooth colors with all movie effects
replaced from screen onto AmbiLight is currently the best – flash blink-
ings, etc… run oldie movie Armageddon in HD – it’s one of best to perform
AmbiLight tests especially at the scene moment when they countdown to
the launch …
.. is the best available becuase colour changes are easy to view at day time
and night time, then I think these calculation should go away and we
should take a try on the new mathematical way to reproduce perfect
colours on the AmbiLight.

I think it’s the time to bring something newer and better using more ad-
vanced mathematical functions like “Least-Squares Polynomial
Approximation”, please take a look on this:
http://www.chem.uoa.gr/applets/AppletPoly/Appl_Poly2.html – take a
look on a java applet on the right side
http://www.devx.com/enterprise/Article/44408
–> http://www.devx.com/enterprise/Article/44408/0/page/2
… … … and the Smooth radius (points number) (= RGB values to calculate)
can be fixed number of RGB values…
or better way can various decreasing and increasing from acceleration
and deacceleration:
http://stackoverflow.com/questions/4739064/acceleration-deceleration-
ratio-equivalent-with-keyframe
and this can be done from the current and previous RGB.Color -> HSV.V
difference.

I’m think that this method of smoothing colours could be best ever…
That’s why I would like to see a software with customizable mathematical
operations.

So what you think about that?


Sorry for the long post – I didn’t expected that it will be so long.

Have a nice weekend!

 Justin S.
JANUARY 29, 2012 AT 9:49 AM

Hey Silas,

Although we haven’t yet gone to the level of detail you have for the vari-
ous algorithms, I think we have the same goals in mind.

We actually have a FezSpider here for the .NET Gadgeteer setup, we just
wanted to get the Arduino implementation finished first before we imple-
ment that one. We actually are using a stream to USB serial so any hard-
ware solution that can read the stream will work. At the moment we are
using a string of 50 “smart” LEDs, but the number and placement is
configurable.

We plan to make a pluggable architecture, but again it is early days and


we just want to get it working first. This will include plugins for capture
method, output to hardware etc… Your thoughts on some post processing
plugins are good too, we hadn’t yet thought this through.

We are also looking at implementing a Linux version via Mono. Of course


we will not be using the DirectX capture, but will be looking at the various
options available in Linux (specifically Ubuntu).
I admire your passion on this topic, and hope we can collaborate more on
it. I will let you know when our Git repository is ready.

Cheers,
J

 Justin S.
MAY 30, 2012 AT 12:07 PM

Hi Silas,

Just wanted to let you know that the starting point for our Ambilight type
project is up: https://github.com/frozenpickle/afterglow and
http://afterglow.frozenpickle.com/

It provides a flexible system for driving an ambilight system – regardless


of what lighting system or capturing approach you use. It currently has a
very primitive plug-in system to allow custom capturing methods / colour
extraction / colour post processing (e.g. smoothing / gamma correction
and so on) and custom outputs (e.g. arduino / preview or in future gad-
geteer or other – you could even create one that creates background
sounds based on colour if it was what you wanted).

It is still early days – but you are more than welcome to take a look. At the
moment you probably would require assistance to setup the software – it
has a primitive preview output so that you can try it out without any
hardware.

Cheers,
J

p.s. I haven’t completed the DirectX capture plugin so it is not committed


yet 🙂

Martin
SEPTEMBER 13, 2011 AT 9:06 PM

Hi Justin!
At first thank you for this nice program.

I want to make an overlay for a directx9 game.


It works fine if the game is in windowed-mode, but if I want to inject in the game in
full screen the injected dll sucks at creating the device.
But if I inject in windowed-mode and switch in the game to full screen it works.
Did you have a solution?
Thanks
Martin

 Justin S.
SEPTEMBER 15, 2011 AT 9:31 AM

Hi Martin,

Yes – I noticed I have made a mistake in the creation of the device. If you instead
use something like the following in the creation of the device it should work for
you.

DXHookD3D9.cs:
using (device = new Device(d3d, 0, DeviceType.NullReference, IntPtr.Zero,
CreateFlags.HardwareVertexProcessing, new PresentParameters() {
BackBufferWidth = 1, BackBufferHeight = 1 }))

DXHookD3D10.cs:
using (SlimDX.Direct3D10.Device device = new Device(factory.GetAdapter(0),
DriverType.Null, DeviceCreationFlags.None ))

DXHookD3D11.cs:
SlimDX.Result result = SlimDX.Direct3D11.Device.CreateWithSwapChain(
DriverType.Null,
….

update: 2012-04-10: See below comment for what has to be changed in


DXHookD3D10/11

Martin
SEPTEMBER 16, 2011 AT 2:05 AM

Hi Justin
I have tested it on directx9 and it works.
Thank you for your fast and good solution.

Martin

PS: If someone has Problems with the GAC-Auto register he should use .NET-
Framework 3.5, because EasyHook has sometimes Problems with .NET-
Framework 4.0.
Jianming
APRIL 10, 2012 AT 7:10 AM

Hi Justin,

First of all thank you for providing such an great C# code on how to do
screenshot/capture and overlay in D3D 9/10/11 . It is very helpful for my
work. I need to implement an overlay for Direct3D(9/10/11) game applica-
tions. It works fine if the game is in windowed-mode, but I want to inject DLL
in the full screen game and make an overlay work for game in the full-screen
mode.

If I injected DLL into Windowed mode, switched from Windowed to fullscreen


mode for D3D 9, it works. But if I injected DLL into full-screen game, I got er-
ror message:Device lost.

If I injected DLL into full-screen game for D3D 10/11, the injection is success-
ful, the game changed from fullscreen to windowed mode automatically. The
overlay is still working. When I switched the game from windowed to
fullscreen mode, the game crashed.

All testing above set DeviceType as Hardware

In order to make an overlay work for the full-screen game, I follow your in-
struction to change DeviceType as DeviceType.NullReference(D3D 9) or
DeviceType.Null(D3D 10/11), then tested the program again.

For D3D 9, injection of DLL into fullscreen game works, but no overlay
presents. API hooking doesn’t work.
For D3D 10/11, injection of DLL into fullscreen game makes full-screen game
application crash.

My platform: Win 7/ 64bit laptop, D3D engine version–9/10/11


Could you help me to confirm if it is possible to make an overlay work for full-
screen game in three D3D version(9/10/11)?
If yes, what is the possible mistakes in my program based on your experience?
what is the correct direction or solution for me to fix the bugs ?

I really need your help to continue the work.

Jianming
 Justin S.
APRIL 10, 2012 AT 9:05 AM

Hi Jianming,

For D3D10/11 change the DeviceType back to what it was before then do
the following changes to PresentHook to make fullscreen capture work:

DXHookD3D10.cs (change start of PresentHook):

1 private SwapChain _swapChain;


2 private IntPtr _swapChainPointer;
3
4 /// <summary>
5 /// Our present hook that will grab a copy of the bac
6 /// </summary>
7 /// <param name="swapChainPtr"></param>
8 /// <param name="syncInterval"></param>
9 /// <param name="flags"></param>
10 /// <returns>The HRESULT of the original method</retu
11 int PresentHook(IntPtr swapChainPtr, int syncInterval
12 {
13 if (swapChainPtr != _swapChainPointer)
14 {
15 _swapChain = SlimDX.DXGI.SwapChain.FromPointe
16 }
17 SwapChain swapChain = _swapChain;
18 //using (SlimDX.DXGI.SwapChain swapChain = SlimDX
19 {

DXHookD3D11.cs (change start of PresentHook):

1 private SwapChain _swapChain;


2 private IntPtr _swapChainPointer;
3
4
5 /// <summary>
6 /// Our present hook that will grab a copy of the bac
7 /// </summary>
8 /// <param name="swapChainPtr"></param>
9 /// <param name="syncInterval"></param>
10 /// <param name="flags"></param>
11 /// <returns>The HRESULT of the original method</retu
12 int PresentHook(IntPtr swapChainPtr, int syncInterval
13 {
14 if (swapChainPtr != _swapChainPointer)
15 {
16 _swapChain = SlimDX.DXGI.SwapChain.FromPointe
17 }
18 SwapChain swapChain = _swapChain;
19
20 //using (SlimDX.DXGI.SwapChain swapChain = SlimDX
21 {
Jianming
APRIL 12, 2012 AT 10:02 AM

Justin,

I have made a progress for the injection of the full-screen game.Thank you
very much.
But the problem still existed for switching between full-screen and win-
dows mode. When
I switched from fullscreen to windowed mode, the game was crashed by
the injected DLL.
The reason is from the release of reference counts for SwapChain object
or its pointer.
SlimDX doesn’t provide a good method to release the reference
counts/resources automatically.
I try the methods of Dispose() and Marshal.Release(). But both couldn’t
keep the game not crashing by SwapChain object..
Do you have any suggestion for solving the probelm(Release COM refer-
ence counts/resources correctly).
Regards,

 Justin S.
APRIL 12, 2012 AT 10:42 AM

Hi Jianming,

Try keeping an additional reference to the swap chain and see if you no
longer get any crashes, if that is the case it probably means that SlimDX is
causing the COM object to release before the main application is finished
with it, which I guess would also mean SlimDX isn’t incrementing the us-
age count when wrapping the COM object initially. Anyway try this first
to see how it behaves.

Cheers,
J

 Justin S.
APRIL 14, 2012 AT 10:00 AM

Hi Jianming,
I have just done a test with the CubeMapGS Direct3D 10 sample, and us-
ing the test capture project I was able to hit the Load Test, and switch to
and from fullscreen without any issues.

Could you confirm it works for you with the D3D SDK samples?

Cheers,
Justin

Superymk
OCTOBER 5, 2011 AT 12:50 AM

Hi Justin,

Good job! I am interested in this tool and make some experiments on it. But I met a
problem similar to Michael. When I hook the Present() method in an x64 D3D ap-
plication, the target is crashed and the injection is never invoked (Program Files
(x86)Microsoft DirectX SDK (June
2010)SamplesC++Direct3DBinx64Instancing.exe). But it works well on x86 D3D
application if I use the commented “return device.Present().Code” instead of the
uncommented piece of code. Any idea on this?

Source code: http://nopaste.info/398612bf51.html

 Justin S.
OCTOBER 5, 2011 AT 11:38 AM

Hi Superymk,

Do other hooks work? E.g. try to hook the EndScene method.

Also try to confirm where it crashes, is it while it is creating the hook, or is it


within the new Present method? Output to a debug log or something to confirm.

Cheers,
J

Superymk
OCTOBER 5, 2011 AT 1:20 PM

If I remove the Present() hook, then other hooks work pretty well. I’ll try to
debug it today. Thank you very much!
 Justin S.
OCTOBER 5, 2011 AT 2:42 PM

If that’s the case, it sounds like the parameters being sent to the SlimDX
Present call could be the issue. I would take a look at them carefully and see
if there is something amiss there.

Cheers,
J

Superymk
OCTOBER 5, 2011 AT 2:57 PM

Thank you very much. I’ll send you the debug information I get. I use Win7
x64 Ultimate. The version of D3d9.dll is 6.1.7600.16385. Though it works
well when using the commented “return device.Present().Code” for x86
applications, I think it will lead to performance degradation.

Superymk
OCTOBER 5, 2011 AT 3:43 PM

When hooking on the Present() method (the same code for Michael) in an
x64 application, the target process crashed. The output of Direct3DHook
is:

3704:DXHookD3D9: Hook: End


3704:DXHookD3D9: Insert Present Hook
3704:DXHookD3D9: Hook: Device created
3704:DXHookD3D9: Hook: Before device creation
3704:DXHookD3D9: Hook: Begin
3704:64-bit Process: True
3704:DLL Injection succeeded

Superymk
OCTOBER 5, 2011 AT 3:45 PM

I add “3704:DXHookD3D9: Insert Present Hook” in Hook() method.

Superymk
OCTOBER 5, 2011 AT 9:32 PM

For the issue on Win7 x64, it seems to be something wrong occurs in


EasyHook. I try to read the disassembly code and find that a jmp is placed
in the beginning of Present(). But the PresentHook() function is never
called.

Alex
OCTOBER 16, 2011 AT 1:30 PM

Justin,

First off thanks for putting this together, I’ve been looking for a way to do this and
came to know this is not an easy task.

I’m able to run your code just fine, however coming across a scenario where after
hooking into a full screen directx app I’m no longer able to ALT+TAB out at all.
Even Ctl+Del or Win key do not work. It seems that that window is stuck in fore-
ground no matter what after hooking.

Were you experiencing the same thing? Is there any way to address this?

Thanks in advance.

 Justin S.
OCTOBER 16, 2011 AT 4:44 PM

Hi Alex,

Yes I have experienced this, and had found a way around it by changing fore-
ground focus within the host application while hooking. That mechanism should
still be there…

Not that this helps you out much, but to fix it manually exit fullscreen with
Alt+Enter and re-enter again, that used to sort it out for me.

I’m starting to have vague recollections of sorting out some fullscreen issues in
my local version of the code, not sure that it was related to this issue tho. I’ll wait
and see how you go.

Cheers,
J

crypt
NOVEMBER 9, 2011 AT 4:19 AM

I have a problem when i try to build it : “ResGen.exe” exited with code 2


can anybody help me?
 Justin S.
NOVEMBER 9, 2011 AT 8:36 AM

Not sure.. sounds like the kind of error you get when converting the solution file
to a new VS version.

crypt
NOVEMBER 10, 2011 AT 12:50 AM

Yes, but how can i fix it?

Lucas
NOVEMBER 19, 2011 AT 7:25 AM

Fix to capture dx9 with multisample, just replace de using for this one:

using (Surface backBuffer = device.GetBackBuffer(0, 0))


{
if (backBuffer.Description.MultisampleType != MultisampleType.None)
{
Surface multiSampleBuffer = Surface.CreateRenderTarget(device,
backBuffer.Description.Width, backBuffer.Description.Height,
backBuffer.Description.Format, MultisampleType.None, 0, false);

device.StretchRectangle(backBuffer, multiSampleBuffer, TextureFilter.Linear);

device.GetRenderTargetData(multiSampleBuffer, _renderTarget);
}
else
{
// Create a super fast copy of the back buffer on our Surface
device.GetRenderTargetData(backBuffer, _renderTarget);
}

// We have the back buffer data and can now work on copying it to a bitmap
ProcessRequest();
}

Lucas
NOVEMBER 19, 2011 AT 7:27 AM

I can’t make it work with Day of Defeat Source at full screen. No snapshot is cap-
tured.
Any idea how can I debug it?
Lucas
NOVEMBER 21, 2011 AT 12:23 AM

I’ve already found the answer here at the comments.

Lucas
NOVEMBER 21, 2011 AT 12:29 AM

Justin,
I’m trying to hook swapchain present method in dx9.
Here is the relevant part of the code to get the vtable. But I do receive
D3DERR_INVALIDCALL: Invalid call (-2005530516) at swapchain construction.
Do you know what is wrong?

http://pastebin.com/jjHSDGvX

Randell
DECEMBER 31, 2011 AT 3:11 AM

I’m having a problem with your samples. They work fine until I resize the window
(not fullscreen, just drag it a little larger), then the FPS counter disappears and
screen capture stops working; it’s as if it “loses” the EndScene hook.

I was trying it against the various D3D9 examples in the DirectX SDK. Any
thoughts?

Also, would there be a large benefit to caching/storing off the device and not cre-
ating it on every EndScene call?

 Justin S.
DECEMBER 31, 2011 AT 2:32 PM

Hi Randell,

I’ll take a look at why it isn’t working on resize for you. I seem to remember fixing
something here ages ago.

We aren’t creating a new device in each EndScene, just a new reference to it in


SlimDX. There is potentially a performance improvement by caching it, but you
would have to also be careful to check that the IntPtr of the SlimDX device
wrapper still matches the one being passed in with the call to EndScene, and of
course clean it up properly. I’m guessing that any performance improvement will
be fairly minimal, but that still might make a difference for something that is
called so frequently.
Cheers,
J

Peter
JANUARY 15, 2012 AT 9:42 AM

Hey Just, I would appreciate if you could help me with a small code here. I need
help updating the text of the GUI via a request from the form. I cant seem to figure
it as the whole request method is a bit to complicated for me. I simply want to type
in a textbox “hi” and when clicking a button on the form send a request through
the screenshotmanager.cs file and have the program change the font text to hi. I
know this is possible and probably very easy, I just cant seem to figure out how to
do this. Thanks!

 Justin S.
JANUARY 15, 2012 AT 4:04 PM

Hi Peter,

The easiest way I think would be to modify the


ScreenshotInterface.ScreenshotInterface class, to include a property that is set
in your form such as “DisplayText”, and a method such as “GetDisplayText()” (it
will most likely work just with a property with a getter and setter actually) that
is called from within the ScreenshotInjection.cs Run(..) method (within the while
loop).

You will probably need to use a lock around the read and write of the string
property.

I hope that helps out.

Cheers,
J

Nathan
JANUARY 18, 2012 AT 10:40 PM

Just got this to work in my XNA game I’m developing. Had to run as administrator,
set auto register GAC, and put the name of the application in without extensions.
It displayed FPS and took a nice picture.

Anonymous
JANUARY 20, 2012 AT 4:51 AM
I`m a newbie to programming. Just started to play with VS 2010 tried opening and
playing around with dx sdk samples. Checked out nvidia`s parallel nsight 2.1.
Ultimately what I am looking for is checking out geometry and textures of a new
d3d11 game Battlefield 3. Would there be any chance to put a step by step guide
on using your method?

Thank you

Dainius
JANUARY 20, 2012 AT 4:58 AM

I am a newbie to programming. Just started playing with VS 2010.


I am interested in geometry and textures of a d3d11 game Battlefield 3.
Any chance of step by step tut on using you method?

Thanks

 Justin S.
JANUARY 20, 2012 AT 5:45 PM

Hi Dainius,

If you follow through the previous post on hooking Direct3D 9, and then apply
what you learn there to this post with Direct3D 10 you should be able to find
your way into the depths of hooking the Direct3D pipeline. I’m no expert at pro-
gramming for Direct3D and there are plenty of other resources out there that
will teach you what you need to know on that matter.

Cheers,
J

Dainius
JANUARY 21, 2012 AT 3:58 PM

Hey,
Thanks for the input, I am working on it.
Btw as I have mentioned above I tried Nvidia`s Nsight 2.1. And this application
does part of the job I need. It injects graphics analyzing tools in to the d3d11
game and you can capture and examine a lot of things(which most of them I
don`t understand ;] ) it displays captured geometry and textures. So my next
question is… is there a way to save assets displayed in the Nsight`s viewport. I
mean 3d geometry to a usable format and textures to image files with trans-
parency channels and all. Like I said I am total newbie at VS and it looks like a
totally new world to me so please don laugh if I am not getting the main con-
cepts of the program ;]]]

Thanks again for your time ;]

Martin
FEBRUARY 1, 2012 AT 5:09 AM

Hi Justin!

I would like to use your project, to create an overlay for a directx9 game.
It all works fine, but sometimes i have problems to uninstall the hook and the over-
lay doesn’t disappear.
Do you have a solution or does anyone have the same problem?

Thanks
Martin

 Justin S.
FEBRUARY 1, 2012 AT 2:36 PM

Hi Martin,

I have seen this happen although it is usually with a 64-bit process. Probably the
best approach would be to send a flag that stops the overlay showing before at-
tempting to uninstall the hook (i.e. the overlay checks the flag each time before
doing what you need to do show it). At least this way the overlay will not be
shown if the hook uninstall fails.

I don’t have any solution to the hook uninstall I’m sorry.

Cheers,
J

Martin
FEBRUARY 2, 2012 AT 6:14 AM

Hi Justin,
Thanks for your fast answer.
I have a 32-bit-OS.
I allready made something like a flag, but also if i stop drawing the overlay, it
doesn’t disappears all times (but mostly).
I only asked, because i want to know if there is a better solution, but so I will
use the old solution.
Thank you!

Martin

mouser
FEBRUARY 10, 2012 AT 9:31 PM

Thank you for sharing this code. Very tricky stuff and I haven’t come across any-
thing that works nearly as well.

But can anyone think of a straightforward way to *programatically* figure out


which version of directx a target process is using — so that it does not have to be
manually set by user?

 Justin S.
FEBRUARY 11, 2012 AT 10:12 AM

Hi mouser,

Yes, I do this in my local version now. Here is a snippet of what I do (you will no-
tice I no longer pass the directx version from the host application).

1 public void Run(


2 RemoteHooking.IContext InContext,
3 String channelName)
4 {
5 // NOTE: We are now already running within the target
6 try
7 {
8 _interface.OnDebugMessage(RemoteHooking.GetCurren
9
10 bool isX64Process = RemoteHooking.IsX64Process(Re
11 _interface.OnDebugMessage(RemoteHooking.GetCurren
12
13 IntPtr d3D9Loaded = IntPtr.Zero;
14 IntPtr d3D10Loaded = IntPtr.Zero;
15 IntPtr d3D10_1Loaded = IntPtr.Zero;
16 IntPtr d3D11Loaded = IntPtr.Zero;
17 IntPtr d3D11_1Loaded = IntPtr.Zero;
18 int delayTime = 100;
19 int retryCount = 0;
20 while (d3D9Loaded == IntPtr.Zero &amp;&amp; d3D10
21 {
22 retryCount++;
23 d3D9Loaded = GetModuleHandle("d3d9.dll");
24 d3D10Loaded = GetModuleHandle("d3d10.dll");
25 d3D10_1Loaded = GetModuleHandle("d3d10_1.dll
26 d3D11Loaded = GetModuleHandle("d3d11.dll");
27 d3D11_1Loaded = GetModuleHandle("d3d11_1.dll
28 Thread.Sleep(delayTime);
29
30 if (retryCount * delayTime &gt; 5000)
31 {
32 _interface.OnDebugMessage(RemoteHooking.G
33 return;
34 }
35 }
36
37 Direct3DVersion version = Direct3DVersion.Unknown
38 if (d3D9Loaded != IntPtr.Zero)
39 {
40 version = Direct3DVersion.Direct3D9;
41 }
42 else if (d3D10Loaded != IntPtr.Zero)
43 {
44 version = Direct3DVersion.Direct3D10;
45 }
46 else if (d3D10_1Loaded != IntPtr.Zero)
47 {
48 version = Direct3DVersion.Direct3D10_1;
49 }
50 else if (d3D11Loaded != IntPtr.Zero)
51 {
52 version = Direct3DVersion.Direct3D11;
53 }
54 else if (d3D11_1Loaded != IntPtr.Zero)
55 {
56 version = Direct3DVersion.Direct3D11_1;
57 }
58
59 switch (version)
60 {
61 case Direct3DVersion.Direct3D9:
62 _directXHook = new DXHookD3D9(_interface
63 break;
64 case Direct3DVersion.Direct3D10:
65 _directXHook = new DXHookD3D10(_interface
66 break;
67 //case Direct3DVersion.Direct3D10_1:
68 // _directXHook = new DXHookD3D10_1(_inter
69 // return;
70 case Direct3DVersion.Direct3D11:
71 _directXHook = new DXHookD3D11(_interface
72 break;
73 //case Direct3DVersion.Direct3D11_1:
74 // _directXHook = new DXHookD3D11_1(_inter
75 // return;
76 default:
77 _interface.OnDebugMessage(RemoteHooking.G
78 return;
79 }

mouser
FEBRUARY 11, 2012 AT 10:17 AM

ah well i guess my code enumerating all modules (including taking a module


Snapshot to handle win32 processes not found by the Processes class, that
was the painful part), trying to guess the directx version based on which di-
rectx modules got loaded — is no longer need. your solution looks better.
thanks for sharing that.

mouser
FEBRUARY 11, 2012 AT 7:28 AM

A more serious showstopper.

Martin in one of the comments above mentioned that the process fails on full
screen directx.

In your reply you suggested a fix:


“DXHookD3D9.cs:
using (device = new Device(d3d, 0, DeviceType.NullReference, IntPtr.Zero,
CreateFlags.HardwareVertexProcessing, new PresentParameters() {
BackBufferWidth = 1, BackBufferHeight = 1 }))

DXHookD3D10.cs:
using (SlimDX.Direct3D10.Device device = new Device(factory.GetAdapter(0),
DriverType.Null, DeviceCreationFlags.None ))

DXHookD3D11.cs:
SlimDX.Result result = SlimDX.Direct3D11.Device.CreateWithSwapChain(
DriverType.Null,”

I have tried this, and while it does indeed fix Directx 9 — it seems to completely
break capture on Directx 10 and 11 (i.e. not only doesnt it let fullscreen grab work,
but windowed grab also seems to fail).

This code is so close to working perfectly, but the fullscreen bug is a show stopper.
Any ideas how to get it to work ? (ps. using latest SlimDx build from jan 2012).

Again, fantastic work on this stuff.

 Justin S.
FEBRUARY 11, 2012 AT 10:14 AM

Hi mouser,

I will be working on this code over the next few weeks for an Ambilight clone
project, I’ll keep you informed of any fixes I find.
Cheers,
J

mouser
FEBRUARY 11, 2012 AT 10:19 AM

Thanks Justin! Looking forward to any updates.

Mike W
FEBRUARY 19, 2012 AT 5:52 PM

Hi Justin, first of all thanks for providing such an excellent c# code example on how
to do this. I’ve actually been able to hook into a full screen 3rd PC game and dis-
play FPS (it was really cool to finally see this work!).

I have a Win 7 64 PC, and I’m running into a snag though regarding the DX9 regis-
tration and hook processes:

Config.Register(“ScreenshotInjector”, “MyAssembly.dll”);
….
// Inject DLL into target process
RemoteHooking.Inject(
process.Id,
InjectionOptions.Default,
“MyAssembly.dll”,
“MyAssembly.dll”,
_channelName,
);

I’ve only been able to register and hook to my dll when the dll is referenced from
within my VS project and output to its bin directory. I can’t seem to get this work-
ing when the dll files are moved to my application directory. I’m running as Admin,
and I get the error “The system cannot find the file specified”, however, the dll is
actually there. Basically, could you provide a detailed breakdown of how the
Config.Register and RemoteHooking.Inject processed work in relation to the GAC,
please? I apologize if this is a very noobish question.

 Justin S.
FEBRUARY 19, 2012 AT 7:52 PM

Hi Mike,

I find the auto register to GAC to be a finicky thing…


To have it working all you need is all the EasyHook stuff in the application direc-
tory along with your injection assembly. However I have also had hair pulling
moments where it just won’t work for some reason – often a reboot would sort
it for me. In the end I register them in the GAC permanently instead (except
while debugging).

When I’m debugging I copy the application I am injecting into my build output di-
rectory so everything works nicely without having to worry about getting the
new assembly into the GAC each time. I also change the startup project to my in-
jection assembly and configure the debug settings to start the application I will
be injecting. I then run my TestScreenshot app to perform the injection – this
gives you immediate debugging access (from the start of the “Run” function).

I hope this helps… I am planning a new version that will hopefully streamline this
all a little – but it is a little ways off yet.

Cheers,
J

Devon A
FEBRUARY 20, 2012 AT 6:20 AM

Hi Justin, I’m planning on writing a small program to capture a portion of a


game’s buffer and overlay it (partially transparent and much, much larger) on
the main game window. Is this article what I should reference in my attempt-
ing this, or am I in the wrong neck of the woods?

 Justin S.
FEBRUARY 20, 2012 AT 7:46 AM

Hi Devon,

Yes, this example code will help you along the way. The only part not cov-
ered is displaying the captured image as an overlay, but everything up to the
capture of it is covered.

Cheers,
J

Mike W
FEBRUARY 21, 2012 AT 2:34 AM
Thanks for the quick reply. One question though, when you mention perma-
nently registering the assembly into the GAC, do you mean using the
Gacutil.exe utility directly? I’m curious because I’ve also noticed serveral folks
taking this approach:
http://msdn.microsoft.com/en-
us/library/system.enterpriseservices.internal.publish.gacinstall.aspx

 Justin S.
FEBRUARY 21, 2012 AT 7:34 PM

Yeah I use the gacutil.exe. I haven’t used the method you linked, but that
would probably suffice as well.

Cheers,
J

Mike W
FEBRUARY 23, 2012 AT 2:21 AM

Thanks Justin, I finally was able to get everything working correctly. Very
cool indeed, and I look forward to your streamlined version when it’s
ready.

Dan
MARCH 13, 2012 AT 8:08 AM

Hey Justin,

This is a great project and I’m excited to see any continued development.
I having a problem taking screenshots in fullscreen wtih DX9 games (I have not
tried DX 10 or 11).
I always receive this exception:
10044:DXHookD3D9: EndSceneHook: Exeception:
SlimDX.Direct3D9.Direct3D9Exception: D3DERR_INVALIDCALL: Invalid call
(-2005530516)

I had found a very similar problem on gamedev here:


http://www.gamedev.net/topic/543847-slimdx-handling-lost-devices-solved/

But I was not able to come to any sort of fix. As previously mentioned in these
comments, I did set DeviceType.NullReference when creating my device but that
does not seem to make a difference.

Any thoughts or suggestions?


Cheers and thank you for sharing this great project.

 Justin S.
MARCH 13, 2012 AT 6:36 PM

Hi Dan,

Could you send me an email with your Direct3D9 hook code, and also let me
know what game/application you are attempting to capture from. Also is it any
DirectX 9 application that the error happens in? I’ll try to catch you on skype or
chat to further troubleshoot.

Thanks!
J

Dan
MARCH 14, 2012 AT 6:05 AM

Hello Justin,

My colleague pointed out to me that I was not removing my original


ScreenshotInject.dll and registering the new ScreenshotInject.dll in the GAC. I did
that, and things begin to work just fine.

I now need to see if it is possible to tune this for performance. My same colleague
mentioned above wrote a small modification to write uncompressed BMP files
from the frame captures to disk. It takes 20-60 seconds depending on the com-
puter we use to grab 100 frames, so for video we are looking at .6 – 5 FPS.

If you are available on Skype to chat about that, and potentially how to make full
screen capture work in DX 10 and DX 11 as well, I’d love to talk about it.

Thank you for the communication and nice project.

 Justin S.
MARCH 15, 2012 AT 6:35 PM

Dan,

For DX9 you will want to offload the frame to a queue for background process-
ing as soon as you have copied the frame from the DX surface. If you are saving
the image to a file, DX9 includes a surface save to file method that will hopefully
reduce the number of times you are copying the buffer around (in SlimDX I think
this is Surface.ToFile).
For DX10/11 you are able to copy the contents of a texture in another thread so
you can create multiple textures and alternate which you are capturing into. You
then queue each one up for background processing – you will have to create
some logic to determine when to create more textures, and optimize how many
frames/sec you are able to process.

The process of copying the image data over IPC back to the host process can be
quite expensive, so you might want to implement as much as possible within the
injected DLL.

Also the timing and image capturing logic should be implemented within the in-
jected assembly (within the capture hook even) rather than relying on a request
over IPC, the loop while waiting for image requests from the host process can be
expensive (in time if not processing) – the sleep in this loop could then be in-
creased to 500ms or so.

I hope this helps.


Cheers,
J

Jianming Li
MARCH 29, 2012 AT 5:32 AM

Justin:

I have a question about the cleanup for DXHookD3D11/10. I injected the DLL into
the target process and implemented an overlay function, everything is fine. I have
a trouble for resizing or closing Windows for the target process.While I resized or
closed a injected D3D (10\11) application’s Window I got the error message:

The Direct3D device has a non-zero reference count, meanin some objects were
not released?

I traced the Injected DLL and Target Process. One of the reasons is from the
Cleanup for DXHookD3D11/10 in the following class. The Cleanup function never
executed when I closed the target process(D3D application).

How can I release the resources in the injected DLL when I closed D3D
Application?
How can I make CleanUp function be executed when I closed D3D Application
Windows?

I look forward to your reply.


public class ScreenshotInjection : EasyHook.IEntryPoint {
public void Run(
RemoteHooking.IContext InContext,
String channelName,
Direct3DVersion version)
{
// Wait for host process termination…
try
{
while (_interface.Ping(RemoteHooking.GetCurrentProcessId()))
{
Thread.Sleep(10);

ScreenshotRequest request =
_interface.GetScreenshotRequest(RemoteHooking.GetCurrentProcessId());

if (request != null)
{
_directXHook.Request = request;
}
}
}
catch
{
// .NET Remoting will raise an exception if host is unreachable
}
finally
{
try
{
_directXHook.Cleanup();
}
catch
{
}
}
}

 Justin S.
MARCH 29, 2012 AT 2:55 PM

Hi Jianming Li,
You will want to clean up your resources in two locations, firstly within the re-
size hook. Being able to hook during the target process termination will need to
be done by listening for the WM_CLOSE event I think.

The current .Cleanup() call is executed when the host process is terminated, or
the IPC channel is closed.

I hope this helps.

Cheers,
J

Carl
APRIL 2, 2012 AT 3:19 AM

Hi Justin,

I stumbled upon your blog and am very impressed with your work. I was wonder-
ing if you ever returned to the idea of full-screen capturing or if you had any ideas
which direction would yield a great low-latency option.

Thanks.

 Justin S.
APRIL 2, 2012 AT 9:04 AM

Hi Carl,

Check through the comments and you will find the fixes to get fullscreen cap-
ture working (maybe read from bottom up). The latency is fairly low, however
can be improved by doing some buffering within the hooked process. You will
see some comments about this also.

I’m planning on setting up a github repository for this project soon so that the
fixes are immediately available, and so that others can contribute.

Cheers,
J

Carl
APRIL 5, 2012 AT 4:41 AM

Hi Justin,
Thank you for the reply. I didn’t realize I wasn’t being clear enough. I was actu-
ally wondering about full desktop screen capture as opposed to a fullscreen
application. I think in earlier versions of this code you attempted to hook the
windows DWM to get the full screen but they had changed something about
DWM in Windows 7 making it only work for Vista. Any insight you might have
would be fantastic. Thanks!

 Justin S.
APRIL 6, 2012 AT 9:04 AM

Hi Carl, I did look at it again but haven’t had the time to implement a solu-
tion as yet.
Cheers,
J

Mike
APRIL 6, 2012 AT 3:56 PM

I’m glad to see that you are still actively working on this project. I was
looking at this to use as a base for an overlay I want to create, but as other
people have mentioned, I’m having issues with GAC since I’m using
.NET4.0. Even after installing the dll with gacutil 4.0.x, the application is
having issues finding ScreenshotInject. The tool I’m working on is going to
be potentially be used by many people, so I wanted to create a process
that is as easy as possible. I saw that you mentioned about streamlining all
of this, so I was wondering how that is going. Anyway, thanks for all your
hard work. This is the only good resource I’ve found for DX injection.

 Justin S.
APRIL 6, 2012 AT 4:16 PM

Mike,

Yes I created a version that works with .NET 4 and doesn’t require the
GAC, however I had to make changes to the EasyHook library. I have
joined the EasyHook project at Codeplex and will be committing changes
there once I get some spare time to clean up my implementation.

I plan to also get this code into a project on Github so others can contrib-
ute to it.

I’ll post any updates on the blog and here.


Cheers,
J

Jianming
APRIL 5, 2012 AT 5:24 AM

Carl,
I also have a fullscreen trouble in Windows 7. My testing environment is
Direct3D 11, Windows 7/64bit. My target process (game) with injected DLL
crashes when I try to switch from Windowed mode to fullscreen mode. Do
you test the switching between two mdoes when you try to get fullscreen cap-
ture working? Could we share some ideas about full-screen mode?

Regards,

Jianming

Jianming
APRIL 3, 2012 AT 3:37 AM

Justin,

Could I inject an overlay DLL into a full-screen game application(Direct3D 11),


keep the application in the full-screen state, or inject the DLL into a windowed-
mode game application, then switch to the full-screen mode?

I need to hook the full-screen game application. I have added hooked functions–
ResizeTarget and ResizeBuffer. When I resize the windows of game application,
ResizeTarget never works, only ResizeBuffer works in the injected DLL.

If I inject DLL into the full-screen game apps, the apps automatically switcches
from full-screen mode to windowed mode.

After I successfully inject a DLL into the game application, then switch from
Windowed mode to full-screen mode, the game application crashes. The error
info:Unhandled exception at 0x000007fefda3cacd (KernelBase.dll) in
DecalTessellation11.exe: 0xE0434F4D: 0xe0434f4d.

Do you meet the similar case when you switch the game apps with injected DLL
from Windowed mode to full-sceen mode? I have spent a long time, try the differ-
ent ways to fix the bug. Until now, I haven’t a clue.
Could you provide any solution or clue to fix the full-screen bug. I wiil really appre-
ciate your help.

Jianming
Elliot
APRIL 10, 2012 AT 8:39 PM

Would it be possible to do this in VB?

 Justin S.
APRIL 11, 2012 AT 3:02 PM

Yes I’m fairly certain that this would work fine in VB.NET, the code does not use
any specific C# language constructs that do not have a VB.NET equivalent.

Kyle
APRIL 14, 2012 AT 1:55 AM

Justin, I’m not a pro at visual studio (my background is in Linux), but I’m trying to
get this to work. I open your example, make sure it’s using my installed slimDX (the
January 2012 version), compile, run, and give it the name of the window the
DirectX example Text3D has, and I get an Argument NULL exception: “value can-
not be NULL” in file dwmcapture.cs, line 71. Any idea what I’m doing wrong?

I would greatly appreciate your help. Thank you!

 Justin S.
APRIL 14, 2012 AT 9:50 AM

Hi Kyle,

Which project have you downloaded to try? It looks like you are trying to run the
Vista DWM example – this will not work for you except on Vista. Instead I would
grab the Direct3DHook project located here:
https://github.com/spazzarama/Direct3DHook and try again.

Cheers,
J

Reece
JUNE 3, 2014 AT 11:32 PM

What library would you recommend for realtime video file creation I used
aforge but the frame rate is all messed up?

David
APRIL 14, 2012 AT 4:57 AM

We’re trying to use this for a DX9 application. For example, the Text3D sample in
the DirectX SDK. We installed the newest SlimDX (Jan. 2012) and updated the ex-
ample to link to it. When we ran it and tried to inject the Text3D program (it
claimed it was successful), the the Text3D program simply disappeared– no error
or anything. Then trying to “request capture” resulted in the green progress bar,
but no image (same with the “Load Test” button). We tried this three ways– run-
ning as admin and checking the auto GAC box, adding the DLLs to the GAC
through the terminal and running as a regular user WITHOUT checking the auto
GAC box, and finally, after the DLLS were added to the GAC through the terminal,
running as an admin without checking the auto GAC box. All of these resulting in
the same behavior– namely, the Text3D program disappears with no error, and no
captures can be had.

Yes, the DX9 radio button is selected. We tried both 64-bit and 32-bit Text3D ver-
sions. There were no apparent errors in the program output box.

We’re out of ideas. Can you help? Thank you!

Please note that we’re using 64-bit Windows 7, with two video cards in SLI.

 Justin S.
APRIL 14, 2012 AT 9:47 AM

Hi David,

I’ve just run this now (first time on this new Windows 7 64-bit install), and it has
worked fine using the run as admin + “Auto Register” approach (I have used Jan
2012 SlimDX SKD, with the Direct3DHook source that is now hosted on Github
– https://github.com/spazzarama/Direct3DHook).

For a sanity check, copy the “EmptyProject” DirectX sample into your build out-
put dir and run from there (no auto register to GAC) – if it works then you are
having issues with the GAC, if not then it is something more to do with the
hooking/injection I would guess.

Then I would try the following:

1. Uninstall EasyHook + screenshotinject from GAC (force uninstall if


necessary)
2. Reboot
3. Install into GAC again manually
4. Reboot
5. Retest

I have found that using the Auto register option can result in issues within the
GAC (it has been noted on the EasyHook forums also). So its best to use the
manual install. I have found that a reboot has been necessary after installing in
the past – for no explainable reason.

I am working on a version that no longer requires the GAC – you’ll find this once
I commit it on Github. But that is waiting for some EasyHook improvements
first, you will find the status of the EasyHook 2.7 release at
http://easyhook.codeplex.com

Cheers,
Justin

David
APRIL 17, 2012 AT 4:23 AM

Justin, thank you for the prompt and thorough response. Unfortunately, it
didn’t seem to change anything. I cloned your git repo so I have the most up-
to-date stuff, and I can see that both ScreenshotInject.dll and EasyHook.dll
are in the GAC (and I rebooted), and I copied EmptyProject into
Direct3DHook/bin. I run both EmptyProject and TestScreenshot as non-ad-
min, and the Test Screenshot app shows the following in its log:

6052:DXHookD3D9: Hook: End


6052:DXHookD3D9: Hook: Device created
6052:DXHookD3D9: Hook: Before device creation
6052:DXHookD3D9: Hook: Begin
6052:64-bit Process: False
6052:DLL Injection succeeded

After that, the EmptyProject closes, and Request Capture does nothing. For
the heck of it, I also tried running both AS admin, with no change. What does
that mean?

 Justin S.
APRIL 17, 2012 AT 8:00 PM

Hi David,

Couple things you can do to further debug:


1. Add additional debug message(s) within the EndScene hook (note: if you
can see the FPS appear on the DX9 window then it is working). It is prob-
ably a good idea to only do a debug message on every 20th call as it will
be hit a lot of times otherwise.
2. Try without the SLI – and perhaps on another machine if you have one
handy.
3. Try a D3D 10/11 sample, do they work?

Hope that helps.


Cheers,
J

David
APRIL 18, 2012 AT 3:43 AM

Hey Justin,

Thanks again for the insight. I now have it running perfectly on another
computer with the DirectX samples. (Still not sure what was wrong on the
first computer, but I can look into that later).

My issue now is I am running a simulation I created in the Unity3D game


engine (http://unity3d.com/) and when I run the TestScreenshot.exe and
press inject nothing happens and TestScreenshot locks up and crashes
with no output in the log.

Do you have any ideas?

Thanks so much,

David

TS
SEPTEMBER 29, 2015 AT 12:45 PM

Hi, where are you guys seeing this log? I’m just seeing a bunch of

Debug: DXHookD3D9: System.NullReferenceException: Object reference


not set to an instance of an object.
at Capture.Hook.DXHookD3D9.DoCaptureRenderTarget(Device device,
String hook) in c:\Users\ts\Documents\hooktest2011\Direct3DHook-
master\Capture\Hook\DXHookD3D9.cs:line 381
printed over and over again in the bottom box of the Test Screenshot app,
like it’s stuck in a loop. Is that your log? Anyone know what this NullRef er-
ror is about? As far as I can tell, I haven’t been able to successfully inject to
anything.

TS
SEPTEMBER 29, 2015 AT 12:54 PM

I see it’s a little more stable using EmptyProject10 – I have it inside the
project bin folder and am attempting to do a capture that will show the
capture location overlay as in the image example on this page.

What can this mean though?

Debug: DXHookD3D10: Hook: Device created


Debug: DXHookD3D10: Hook: Before device creation
Debug: DXHookD3D10: Hook: Begin
Debug: DXHookD3D10: Create
Information: Remote process is a 32-bit process.
Information: Injected into process Id:6076.
Debug: Total Time: 00:00:03.6412082
Information: Disconnecting from process 6076
Error: Error in InitialiseHook: SharpDX.SharpDXException: HRESULT:
[0x80004002], Module: [General], ApiCode: [E_NOINTERFACE/No such
interface supported], Message: No such interface supported

at SharpDX.Result.CheckError()
at SharpDX.Direct3D10.D3D10.CreateDevice1(Adapter adapterRef,
DriverType driverType, IntPtr software, DeviceCreationFlags flags,
FeatureLevel hardwareLevel, Int32 sDKVersion, Device1 deviceOut)
at SharpDX.Direct3D10.Device1..ctor(Adapter adapter,
DeviceCreationFlags flags, FeatureLevel featureLevel)
at Capture.Hook.DXHookD3D10_1.Hook() in
c:\Users\ts\Documents\hooktest2011\Direct3DHook-
master\Capture\Hook\DXHookD3D10_1.cs:line 167
at Capture.EntryPoint.InitialiseDirectXHook(CaptureConfig config) in
c:\Users\ts\Documents\hooktest2011\Direct3DHook-
master\Capture\EntryPoint.cs:line 245
Debug: DXHookD3D10_1: Hook: Before device creation
Debug: DXHookD3D10_1: Hook: Begin
Debug: DXHookD3D10_1: Create
Debug: Autodetect found Direct3D 9
Debug: Autodetect found Direct3D 10
Debug: Autodetect found Direct3D 10.1
Information: Remote process is a 32-bit process.
Information: Injected into process Id:6076.

 Justin Stenning
OCTOBER 2, 2015 AT 6:33 PM

I haven’t tried the D3D10 hook for a while, it could be that it is detecting
the wrong D3D10 version.

Paul
APRIL 14, 2012 AT 12:03 PM

I was wondering, have you had heard of XSplit and their game source capture im-
plementation? It seems like they are doing D3D hooking as well in order to cap-
ture the rendering from games for live streaming. The performance is quite good.
The program now costs money in order to use the game source mode though.

There is also another program by a Japanese guy called DXTory which hooks into
D3D and OGL programs in order to capture and encode video from them.

Were you planning on adding any kind of capture functionality to your app? I
haven’t downloaded it to check it out yet but I hope to see more of this kind of
thing in the future.

 Justin S.
APRIL 14, 2012 AT 1:17 PM

Hi Paul,

Yes I am planning on adding video capture support (or at least the beginnings of
it) to the project on Github, along with a more complete implementation of the
DX overlay. I’ll probably be trying to find some more people to participate in cre-
ating a more complete application in the future also.

I hadn’t heard of those projects yet so thx for the pointer, I’ll take a look at them.

Cheers,
J

Paul
APRIL 17, 2012 AT 3:54 AM

Awesome! That’s great to hear. With web streaming becoming so popular


right now, especially in the gaming segment, I’m surprised there aren’t more
solutions out there for direct, 3D screen capturing with a generic output to
Direct Show or something similar. I know that DShow is on the way out (XP
just won’t die!) but hopefully we will see a good general solution in the future
that doesn’t require purchasing a bunch of other software on top. For example
not everyone that buys XSplit may want to use their app to do the video com-
pression as well as the capture.

 Justin S.
APRIL 17, 2012 AT 8:09 PM

Yes I would certainly like to see something like that happen. Keep an ear
out, I’ll post any progress in that direction somewhere on this site. It will
definitely require some additional input from others with more experience
in that area than me.

Cheers,
J

Brett
APRIL 18, 2012 AT 7:24 AM

Justin, thank you so much for taking the time to create this project and share your
knowledge with the rest of us. I had no problem hooking in with Direct3D 9 exam-
ples built from the DirectXSDK. After getting the hang of things, I tried hooking
into a published game that uses Direct3D 9 and kept getting the error
“STATUS_ACCESS_DENIED: The given process is not accessible. (Code: 5)”. I nar-
rowed down the issue and found that ScreenshotInjection.Run() was throwing an
exception at the line:

bool isX64Process =
RemoteHooking.IsX64Process(RemoteHooking.GetCurrentProcessId());

I noticed the bool value isn’t actually used other than for printing out a debug mes-
sage. I commented out this line of code, and surprising, everything after that
worked flawlessly. I honestly don’t have the know-how to figure out why this error
is occurring or how to delve into it further. Hope this helps if anyone else runs into
this issue.

Any ideas what would be causing it? I’m running Win7 64-bit and the process is
32-bit.

Many thanks,
Brett
 Justin S.
APRIL 18, 2012 AT 8:56 AM

Hi Brett,

My best guess is that the app you are trying to hook into is running under a dif-
ferent user account (sometimes games install their shortcut to run as adminis-
trator or the like). Try running the TestScreenshot as administrator.

You cannot access processes in another user session without running as admin-
istrator (you will see that when in the Task Manager and selecting show all pro-
cesses can result in UAC request depending on UAC config). But why you get
that far and then fail on that particular call? Not really sure…

Cheers,
J

MikhailM
APRIL 24, 2012 AT 7:33 AM

Hello Justin, a very useful project, thank you. Not only it is an excellent intro into
Direct3D hooking, but it is also a nice
example of interprocess communication. I have learned a lot from it and was able
to make it capture a gameplay video clip of an adequate
quality using a push source filter in a DirectShow graph. I also use a simple text
overlay that tells the user
about a hot key combination that stops/starts the capture. While I want this over-
lay be shown in the target app, I don’t want it to
get recorded into the video. And it almost works as expected, except for that over-
lay somehow gets captured in an occasional frame
and appears randomly in the recorded video for a fraction of a second. I just don’t
understand how this could happen. Apparenly it
stays in the back buffer after the previous call to EndScene or perhaps gets cached
elsewhere. I tried hooking to Present and to avoid calling multiple
pairs of BeginScene/EndScene without a Present between them (not shown in my
code listing below). Anyway here is my EndScene code,
if you have some idea of how a frame with the overlay can sometimes end up in my
DirectShow push source filter, I’d like to hear it.
Thanks again for a great example.

1 using System;
2 using SlimDX;
3 using SlimDX.Direct3D9;
4 using System.Diagnostics;
5 using DirectShowLib;
6 using System.Runtime.InteropServices;
7
8 [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
9 [System.Security.SuppressUnmanagedCodeSecurity]
10 [Guid("EA2829B9-F644-4341-B3CF-82FF92FD7C20")]
11
12 public interface IScene
13 {
14 unsafe int PassMemoryPtr(void* ptr, bool noheaders);
15 int SetBITMAPINFO([MarshalAs(UnmanagedType.LPArray, S
16 }
17
18 public class Class1
19 {
20 object _lockRenderTarget = new object();
21 public string StatusMess { get; set; }
22 Surface _renderTarget;
23 //points to image bytes
24 unsafe void* bytesptr;
25 //used to store headers AND image bytes
26 byte[] bytes;
27 IFilterGraph2 ifg2;
28 ICaptureGraphBuilder2 icgb2;
29 IBaseFilter push;
30 IBaseFilter compressor;
31 IScene scene;
32 IBaseFilter mux;
33 IFileSinkFilter sink;
34 IMediaControl media;
35 bool NeedRunGraphInit = true;
36 bool NeedRunGraphClean = true;
37 DataStream s;
38 DataRectangle dr;
39
40
41 unsafe int EndSceneHook(IntPtr devicePtr)
42 {
43 int hr;
44
45 using (Device device = Device.FromPointer(deviceP
46 {
47 try
48 {
49 lock (_lockRenderTarget)
50 {
51
52 bool TimeToGrabFrame = false;
53
54 //....
55 //logic based on elapsed millisec
56
57 if (TimeToGrabFrame)
58 {
59
60 //First ensure we have a Surf
61 //called only once
62 if (_renderTarget == null)
63 {
64
65 //Create offscreen surfac
66 using (SwapChain sc = dev
67 {
68
69 //Att: created in sys
70 _renderTarget = Surfa
71
72 } //end using
73 } // end if
74
75 using (Surface backBuffer = d
76 {
77 //The following line is w
78 //Direct3D 9 back buffer
79 //which has been connecte
80 //bitmap capture filter
81 //Inside the filter ( cod
82 //scanned to create a str
83 device.GetRenderTargetDat
84
85 if (NeedRunGraphInit) //r
86 {
87 ifg2 = (IFilterGraph2
88 icgb2 = (ICaptureGrap
89 icgb2.SetFiltergraph(
90 push = (IBaseFilter)
91 scene = (IScene)push;
92
93 //this way we get bit
94 //ToStream is slow, b
95 s = Surface.ToStream(
96 bytes = new byte[s.Le
97
98 s.Read(bytes, 0, (int
99 hr = scene.SetBITMAPI
100
101 //we just supplied th
102 //filter. Let's pass
103 //just image bytes fr
104
105 dr = _renderTarget.Lo
106 s = dr.Data;
107 Result r = _renderTar
108 bytesptr = s.DataPoin
109 hr = scene.PassMemory
110
111 //continue building g
112 ifg2.AddFilter(push,
113
114 icgb2.SetOutputFileNa
115
116 icgb2.RenderStream(nu
117
118 media = (IMediaContr
119
120 media.Run();
121
122 NeedRunGraphInit = f
123 NeedRunGraphClean =
124
125 StatusMess = "now ca
126
127 } //end if
128
129 } // end using backbuffer
130 } // end if Time to grab frame
131
132 } //end lock
133 } // end try
134
135 //It is usually thrown when the user make
136 //or it is thrown deliberately when time
137 //it resulted in stopping a capture.
138 //If it is thrown for another reason, it
139 //idea to stop recording and free the gra
140 catch (Exception ex)
141 {
142 //..
143 //stop the DirectShow graph and cleanu
144
145 } // end catch
146
147 //draw overlay
148 using (SlimDX.Direct3D9.Font font = new S
149 {
150 font.DrawString(null, StatusMess, 20,
151 }
152
153 return device.EndScene().Code;
154
155 } // end using device
156
157 } //end EndSceneHook
158 }

 Justin S.
APRIL 24, 2012 AT 7:48 PM

Hi Mikhail,

Thanks for the feedback. I’m actually looking to implement something like what
you have done soon, so a very timely question.

My best guess at the moment is a threading issue. But I think I will need to try
the code out myself to better understand what is happening, do you have the
project hosted anywhere or can you send it through?

Cheers,
Justin

MikhailM
MAY 10, 2012 AT 3:38 PM
If anyone is interested, here is a workaround that helps to resolve this issue. It
turned out that backbuffer in some Direct3D9 apps is not necessarily re-
freshed each time the hooked EndScene is called. Hence, occasionally the
backbuffer with the text overlay from the previous EndScene hook call was
passed to the DirectShow source filter responsible for collecting input frames.
I started stamping each frame with a tiny 3 pixel overlay with known RGB val-
ues and checking if this dummy overlay was still present before passing the
frame to the DirectShow filter. If the overlay was there, the previously cached
frame was passed instead of the current one. This approach effectively re-
moved the text overlay from the video recorded in the DirectShow graph.

Malwine Feldhaus
MAY 21, 2012 AT 3:10 PM

Hello. How would you determine current yaw and pitch of the camera? I want to
build a head tracker and I need this for feedback.

Malwine Feldhaus
MAY 21, 2012 AT 4:18 PM

I get a “System.BadImageFormatException” while

RemoteHooking.Inject(
process.Id,
InjectionOptions.Default,
typeof(ScreenshotInject.ScreenshotInjection).Assembly.Location,//”ScreenshotInj
ect.dll”, // 32-bit version (the same because AnyCPU) could use different assembly
that links to 32-bit C++ helper dll
typeof(ScreenshotInject.ScreenshotInjection).Assembly.Location,
//”ScreenshotInject.dll”, // 64-bit version (the same because AnyCPU) could use
different assembly that links to 64-bit C++ helper dll

// the optional parameter list…


ChannelName, // The name of the IPC channel for the injected assembly to con-
nect to
direct3DVersion.ToString(), // The direct3DVersion used in the target application
cbDrawOverlay.Checked
);

is being selected as the cause, saying ScreenshotInject.dll or a dependency wasn’t


found.

What now?
Malwine Feldhaus
MAY 22, 2012 AT 1:43 AM

I solved the issue by using slimdx for .net 2 instead of .net 4.

But still, how do I have to change your code for it to output the pitch and yaw?

 Justin S.
MAY 22, 2012 AT 8:26 PM

Hi Malwine,

For Direct3D9 I would suggest you hook the SetTransform method of the
IDirect3D9Device and log what comes in. I think you will need to do this for calls
where D3DTRANSFORMSTATETYPE is equal to D3DTS_VIEW, see
IDirect3DDevice9::SetTransform. This won’t work for shader based transforms.

In Direct3D 10+ fixed-function transform and lighting pipeline in not available.


Instead, you must use shaders.

I don’t know a lot more than that and you will find more by going through sam-
ples and seeing what API’s they use to update camera positions (pitch/yaw/roll)
across the different Direct3D versions.

Hope this helps point you in the correct direction and I would love to hear how
you get along with it.

Cheers,
Justin

eugene
JUNE 6, 2012 AT 3:02 PM

Hello Justin, a good project, thank you.


I compiled it and made ​a couple of tests, everything works fine.
I wanted to ask you. Is it possible with your “hook” such as manipulating/get tex-
tures?
I found interesting project http://www.deep-shadows.com/hax/3DRipperDX.htm
But it is closed and not OpenSource.
And another interesting project
http://graphics.stanford.edu/~mdfisher/GameAIs.html (I could not run it)
 Justin S.
JUNE 6, 2012 AT 7:03 PM

Hi Eugene, yes you should be able to do that sort of thing using hooks.

Ant
JUNE 13, 2012 AT 12:56 AM

Hi Justin,

Having trouble with DX9 PresentHook like a few others. I’ve narrow’d it down to
my implementation of RECT:

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}

As soon as I try to access either sourceRect or destRect (“ref RECT sourceRect, ref
RECT destRect”) it will crash the target application (presumably it’s throwing). Any
thoughts?

 Justin S.
JUNE 14, 2012 AT 7:10 PM

Hi Ant,

It is possible for both to be NULL if the entire surface is to be presented. I would


need to see more of your code to give you any further hints.

Cheers,
J

Roland Lu
JUNE 14, 2012 AT 5:11 PM

Hi, first I must thank you for creating this brilliant project and it’s very inspira-
tional to me. I run your demo successfully, and want to enhance it a bit. The first
thing is I want to make the in game overlay responds to mouse and keyboard input
so that I could create some menus, drop down list, etc, or even better an in-game
browser. Any idea on how could this be implemented, what library could be used?

 Justin S.
JUNE 14, 2012 AT 7:05 PM

Hi Roland,

Thanks. For the user input you will want to look at installing global
mouse/keyboard hooks. I have seen people attempting to “pause” rendering of
the game behind the overlay (I can’t remember how sorry).

For an in game browser take a look at the Chromium project, I believe this is
used in games such as EVE Online as the in game browser – not sure if Steam
also uses this.

Good luck! Feel free to post any updates to the GitHub repository, I would love
to get a proper overlay framework in place with it.

Cheers,
J

Roland Lu
JUNE 20, 2012 AT 4:13 PM

Hi Justin,

I am also looking at Chromium. The problem with current release is its .NET wrap-
per is outdated. The new candidate release 1.7 RC1 seems promising:

There’s still a couple things coming to the 1.7 branch (we may put out an RC2 to
handle these before the official launch)
Popup-menu handling (we broke it as we were wrapping up this package)
Context-menu handling
IME Input
Login authentication handling
Geolocation permission handling
Cookie manipulation
Mac OSX and Linux ports
Advanced Samples (WebUI is coming, baby!)
Updated wrappers for various 3D engines

If I could make it work, I will do a pull request on the Github repository.


Pause the game when rendering the overlay is not a very good idea to me because
it will give others advantage when playing online games.

Cheers,
Roland

 Justin S.
JUNE 27, 2012 AT 8:26 PM

Thanks for your input Roland, let me know if you sort something out!

Cheers,
J

Stanislav Chachkov (@vvertigov)


JUNE 27, 2012 AT 7:21 AM

Hi Justin,
Thanks for your code. I was learning Windows programming and that was very
useful. I did a little sceenshot app like Fraps. It works good with DX9, still some
problems with 10 and 11. Btw, I found it’s better to move DX9 FPS calculation to
Present hook, because some programs make 2 EndScene calls for 1 Present calls.
Not sure about Present signature, i’ve just put intptr and I use the shortest version
from SlimDx. I plan to put the code on github too.

Thanks
Stan

 Justin S.
JUNE 27, 2012 AT 8:17 PM

I’ll keep an eye out for it on github, or if you could let me know when its there..
Thanks!

Stanislav Chachkov (@vvertigov)


JUNE 28, 2012 AT 2:34 AM

Done. I don’t know git and github very well, I hope I did it right:
https://github.com/stani/GScreensTool

I will write about problems later

Kashmir
JULY 9, 2012 AT 3:13 AM

Ive been all around the internet to find a viable method to hook and display graph-
ics ontop of a game. and this helped alot.
though i’m stuck trying to figure out if its possible to draw a windows form and all
its poperties (drag n’ drop, clickable buttons, etc) could you give me any pointers?

 Justin S.
JULY 26, 2012 AT 11:56 AM

Hi Kashmir,

You have to implement your own drawing and passing through of events. Take a
look on gamedeception.net for “.NET Gui” under “Public Releases”. This is a sim-
ple class in Managed C++ that implements a windowing system for use in over-
lays but there is still a lot more you have to implement yourself.

fr500
JULY 15, 2012 AT 10:26 AM

Excellent howto, I’m trying to code a desktop/game streaming app (like onlive but
homebrew), I will use your method for an alternate capture method.

My current implementation gives me a frame at around 32ms. I wonder why does


this seem slower? you mention 50ms for DX9 apps, my preliminar testing showed
no measurable difference between DX9, a Windows Forms app and DX11.

My github page is here https://github.com/fr500/desktop_streamer in case it’s of


any interest

fr500
JULY 15, 2012 AT 10:29 AM

My biggest issue is that my method is skipping frames, it can’t keep up with the
display. Do you think I can at 60fp with this method?

 Justin S.
JULY 26, 2012 AT 8:51 AM

Yes – you will want to resize the textures within DX before completing the
capture.

 Justin S.
JULY 26, 2012 AT 8:50 AM
Yes, capture within DX9 is always faster for me, but DX10/11 allow you to
process the image in a separate thread so you can buffer a few captures and so
on.

To improve performance resize the image within DX (I only know who to do this
with DX9 at the moment), this significantly increases capture performance. Also
you can exclude the IPC overhead by including any logic within the injected as-
sembly as well – not always desirable of course.

Lefteris "Leftos" Aslanoglou


OCTOBER 4, 2012 AT 2:04 AM

Could you maybe guide me as to how to approach passing a few parameters to the
function that calls for the overlay to be drawn, so that the application using
ScreenshotInject can pass the string to be overlaid to ScreenshotInject?

e.g. Allow the user to enter a string, and overlay that string in the DX application.

 Justin S.
OCTOBER 4, 2012 AT 9:35 AM

Hi Leftos,

Take a look at the ScreenshotRequest object if you mean you would like the user
to be able to change the text at any time. This is the object passed through via
IPC to the injected assembly.

If you mean to only set the text at the start then you would add a parameter to
you Run method

Hope this helps – J

Kashmir
OCTOBER 8, 2012 AT 2:35 AM

Hi again, ive been trying to display a 2d image next to the FPS counter or dxd9,
though i always get an exception “D3DERR_INVALIDCALL: Invalid call
(-2005530516)” do you have any knowledge of that?

As I don’t want to load the image’s i’d like to display everytime its rendered, I need
to have the code for loading images somewhere else than in EndSceneHook,
where do you suggest i put that code? i moved it to Hook(), not sure if thats the
best place though
 Justin S.
OCTOBER 8, 2012 AT 10:36 AM

Hi Kashmir,

That error usually indicates some sort of problem with the combination of pa-
rameters u are passing e.g an incompatible texture or surface.

U will want to create a method to do the initialisation of the images and call it in
endscene if it isn’t already init’d. You can also do it in reset device.

Btw how did u go with the form overlay?

Cheers,
J

Kashmir
OCTOBER 9, 2012 AT 5:20 AM

Hi,
Thanks, I think it was a combination of wrong path, wrong extension (*.png)
and freak out as I didnt understand the exception 🙂

I havent had any luck with the forms yet, To be honest im quite new to
direct3d and hooking, things are very different compared to the window
forms and websites, ive been doing for some years. So im currently just exper-
imenting and really appreciate your feedback, even when it digress from the
original screen capture thread.

Kashmir
NOVEMBER 1, 2012 AT 6:01 AM

Hi again
ive started to look into forms and similar, so i found this thing called “squid”
however they have this renderer i need to load with the “device” though I
shouldn’t do this in endscenehook as its looped. are there any good places at
all i could assign this? yes im still looking for a good place to init my vars.

until now ive called a method in endsceenehook which checks if this is the
first time and if yes, do this..

Kashmir
NOVEMBER 2, 2012 AT 8:06 AM

Basically what I ask is,

This squid ui (ionstar.org/) uses a static reference, and if i define that in


endscene, all elements needs to be loaded on each cycle, which ofcourse
draws alot of memory and fps..
initially this reference is supposed to be defined in the initialization
method (when building a slimdx app from scratch) but afaik I don’t have
any initialization method available?

I’ve also tried to put it in BeginScene without any luck. In most cases it
crashes as the reference is null when program reaches EndScene

Terenz
OCTOBER 27, 2012 AT 5:34 PM

Hi,
Hope is not a too stupid question, but i’d like to if is possible to overay to a
Direct3D an external GUI of a software, so an precompiled .exe
Thanks

 Justin S.
OCTOBER 28, 2012 AT 2:27 PM

You probably could by capturing the visual output of that application and over-
laying that in the D3D device.

Terenz
OCTOBER 29, 2012 AT 8:47 PM

It’s really cool, too bad i don’t have the knowledge.


When you have some time maybe you can post an example or directly a binary
for check it out.
Have a nice day

 Justin S.
OCTOBER 31, 2012 AT 7:49 PM

There is a code repository with the source, this article isn’t really that useful
for non-programmers, although I would like to see a full screen capture ap-
plication implemented.

Arnaud Dovi
NOVEMBER 4, 2012 AT 9:03 PM

DXHookD3D11.cs error

_swapChainPointer that is checked in conditions is never assigned

May I recommand you ReSharper in Visual Studio, it highlights such inconcistency

Arnaud Dovi
NOVEMBER 4, 2012 AT 9:06 PM

(Sorry if double post, had javascript and cookies disabled first time)

DXHookD3D11.cs error

_swapChainPointer that is checked in conditions is never assigned

May I recommand you ReSharper in Visual Studio, it highlights such


inconcistencies

Arnaud Dovi
NOVEMBER 4, 2012 AT 9:18 PM

Feel free to delete my bug report here Justin, I will post cleaner way in the GitHub

Hooking in DirectX made that easy, still can’t believe it

 Justin S.
NOVEMBER 6, 2012 AT 8:35 AM

Thanks Arnaud

Arnaud Dovi
NOVEMBER 5, 2012 AT 11:13 PM

Btw I’m using EasyHook + SharpDX it works fine too, SharpDX seems more up to
date than SlimDX, it has already some Win8 stuffs ready

Code changes to apply to your tutorial Justin are really smalls

=)

 Justin S.
NOVEMBER 6, 2012 AT 8:34 AM
Hi Arnaud,

It would be great if you could post these changes to Git – I did try with SharpDX
a while ago but had some issues with com dereferences.

I agree SharpDX is a better library for this purpose.

Cheers,
J

Arnaud Dovi
NOVEMBER 6, 2012 AT 11:03 AM

There is some nice feature in as the option :


SharpDX.Configuration.EnableObjectTracking = True

so you can loop then a collection of Com object waiting to be disposed

For Each obj As SharpDX.Diagnostics.ObjectReference In


SharpDX.Diagnostics.ObjectTracker.FindActiveObjects()

Also in DX11, the swapchain.Device directly points to the D11 Device so its handy
to get the device from the swapchain in the Present() hook

 Justin S.
NOVEMBER 6, 2012 AT 1:06 PM

I’ll try with the latest SharpDX it could be that there were changes that now fix
the issues I was experiencing previously.

Alex
NOVEMBER 18, 2012 AT 7:02 PM

Hello,

Decided to give this another try, with updated code from GitHub. Able to run the
test app and successfully hook in to process, however getting stuck upon taking
screenshot getting the following exception:

6876:DXHookD3D9: EndSceneHook: Exeception:


SlimDX.Direct3D9.Direct3D9Exception: D3DERR_INVALIDCALL: Invalid call
(-2005530516)
I’ve read all posts above referencing this ex code, but non seemed relevant to my
situation. Any idea what would cause this or how to resolve?

Running on Win 7 64 bit, Jan 2012 rel. SlimDX

Thanks in advance.

 Justin S.
NOVEMBER 18, 2012 AT 7:05 PM

Hi Alex can you check if you have anti-aliasing turned on and if so try with it off.
Cheers,
J

Alex
NOVEMBER 19, 2012 AT 6:59 AM

Bingo – that did the trick! Thanks for the quick response.

Turning off anti-aliasing worked, able to take screenshots. In the description you
mentioned that anti-aliasing is supported for DX 10 & 11, does that mean it wont
work w/ DX 9?

The game I was testing on was Counter Strike Source (HL2 engine), just tried DX
11 based Call of Duty Black Ops 2 – and with this just hooking into the process
causes the target to crash. Any pointers on how to make it work ?

BTW really appreciate the quick replies, this is by far the most useful post on the
topic I was able to find!

 Justin S.
NOVEMBER 19, 2012 AT 4:36 PM

Yes you can capture anti-aliased in D3D9 – take a quick look at the Afterglow
project I linked to in another post and see the revised D3D9 capture in there. I
will try to get around to updating this project with it also.

 Justin S.
NOVEMBER 20, 2012 AT 8:37 AM

Just realized this was in another project that isn’t available online – I will up-
date the Direct3D project soon.
 Justin S.
NOVEMBER 19, 2012 AT 4:39 PM

I have not tried CoD but have with BF3 without any issues. Hard to say what the
problem is without more info – try to determine if it is the injection or the hook-
ing that is causing you issues.

 Justin S.
NOVEMBER 20, 2012 AT 9:56 AM

Hi Alex – I have updated the project to support anti-aliasing in DX 9, let me


know how it goes.

Alex
NOVEMBER 20, 2012 AT 2:30 PM

Justin – many thanks for supporting this project. I will take the latest from
GitHub and try out DX 9 with anti-aliasing.

I also preloaded a bunch of DX 10/11 games to test with, will share my find-
ings shortly.

Arnaud
NOVEMBER 19, 2012 AT 7:29 AM

have heard cod games have hooking preventions with all the aim bot hacks it has,
also cod and all valve games are VAC secured, just for you to know you cna get
troubles no matter what does the code

Alex
NOVEMBER 20, 2012 AT 2:40 PM

Arnaud, thanks for pointing this out. That may very well be the case for COD.

However FRAPS worked w/ COD. From my research they use a similar approach
by also hooking into the process but do so more aggressively, not sure what that
entirely means as I’m still very new to DLL hooking but a couple of posts men-
tioned that FRAPS hooks into every process to be fool proof.

Also just wanted to share that Justin’s method does work with Steam games, the
ones I tried were Counter Strike Source (I think its VAC enabled) and Dragon
Age II.
Arben
NOVEMBER 30, 2012 AT 1:44 AM

Is it possible to merge this project with a project of mine that is written in VB.NET?
if so, can you tell me how? My project is in C# as well, so I can merge it in C# as
well, but I’d prefer VB.NET (I would prefer using this from my app’s form1, not the
form1 of testscreenshot, but the thing is this project is so complicated). Also, when
I tried this in Dota2, there were 2 frame-rates that would be in the hundreds or so,
is it possible to just hide them, I don’t need to see the frame-rates, I just need to
capture the SS.

 Justin S.
DECEMBER 23, 2012 AT 8:20 AM

Yes u can use assemblies written in C# in you VB.NET project

MrPiet
DECEMBER 22, 2012 AT 8:19 PM

Pretty nice project you have there, would love to see a screen recorder though as
only screenshots seems a bit limited to me.

Cesar
JANUARY 30, 2013 AT 2:53 AM

Hi I’m getting this error


1712:Exception during device creation and hooking: D3DERR_INVALIDCALL:
Invalid call (-2005530516)
at SlimDX.Result.Throw[T](Object dataKey, Object dataValue)
at SlimDX.Result.Record[T](Int32 hr, Boolean failed, Object dataKey, Object
dataValue)
at SlimDX.Direct3D9.Device..ctor(Direct3D direct3D, Int32 adapter, DeviceType
deviceType, IntPtr controlHandle, CreateFlags createFlags, PresentParameters[]
presentParameters)
at ScreenshotInject.DXHookD3D9.Hook() in C:\Documents and
Settings\CYGNUX01\Escritorio\Direct3DHook-
master\ScreenshotInject\DXHookD3D9.cs:line 45
at ScreenshotInject.ScreenshotInjection.Run(IContext InContext, String channel-
Name, String strVersion, Boolean showOverlay) in C:\Documents and
Settings\CYGNUX01\Escritorio\Direct3DHook-
master\ScreenshotInject\ScreenshotInjection.cs:line 138
1712:DXHookD3D9: Hook: Device created
1712:DXHookD3D9: Hook: Before device creation
1712:DXHookD3D9: Hook: Begin
1712:Autodetect found Direct3D 9
1712:64-bit Process: False
1712:DLL Injection succeeded
I have an Intel 945 express card and Direct x 9.0c

MRmP
FEBRUARY 5, 2013 AT 6:04 AM

Are there a way to unhook, remove the hook from the application?

 Justin S.
FEBRUARY 5, 2013 AT 1:38 PM

You can dispose of the LocalHook and this will uninstall the hook.

You cannot un-inject the assembly unless a custom AppDomain is created and
then closed when ready to un-inject.

Arnaud Dovi
FEBRUARY 6, 2013 AT 4:15 AM

Justin, there is 3 methods of loading .net in a target process, you seem to use only
one which fails in a few app, ie Borderlands 2

I developed my own Library to Hook and Inject directly from C#, the only C++ part
uses this to load .NET in the target process

http://code.msdn.microsoft.com/CppHostCLR-e6581ee0 (2x methods,


borderlands2 fails)
http://code.msdn.microsoft.com/CppCallNETAssemblyWrapper-23cc3840 (1x
method, borderlands2 works)

I have all 3 methods inside one dll

Let me know if interested can share codes

 Justin S.
FEBRUARY 6, 2013 AT 6:28 AM

Hi Arnaud thanks I would love to see it.

 Justin S.
FEBRUARY 6, 2013 AT 6:37 AM

Ah yeah I have used inverse P/Invoke before and was planning on creating a ver-
sion for this project (or EasyHook) that uses C# and creative round tripping to
do a similar thing.

Thanks for the reminder about this approach and great sample!

Arnaud Dovi
FEBRUARY 6, 2013 AT 8:33 AM

http://code.google.com/p/csharp-hook-and-inject/downloads/list

basically if you manage to inject netloader32.dll or netloader64.dll in your target


process, this last will load .NET 4.0 Full, and will load netloaderdetoured.dll (any-
cpu) and show you a message box, with 3 differents methods of loading .NET I
haven’t seen it to fail yet and if it fails you will know which line failed exatcly.

 Justin S.
FEBRUARY 6, 2013 AT 4:53 PM

Looks good Arnaud, thanks for sharing.

Arnaud Dovi
FEBRUARY 6, 2013 AT 9:43 AM

By the way, I ‘m under Visual Studio 2012 so if you are looking to try the compiled
dlls you will need Framework 4.0 Full + VC 2012++ Redist

http://www.microsoft.com/en-us/download/details.aspx?id=30679

Paul
FEBRUARY 6, 2013 AT 12:49 PM

Have you seen OBSProject? Best d3d and OGL capture performance I’ve seen in
any application. Open source too. http://www.obsproject.com

 Justin S.
FEBRUARY 6, 2013 AT 4:27 PM

I’ll take a look, thanks Paul

Sousa
FEBRUARY 7, 2013 AT 4:24 AM
warning CS0168: The variable ‘re’ is declared but never used
warning CS0168: The variable ‘re’ is declared but never used
warning CS0649: Field ‘ScreenshotInject.DXHookD3D10._swapChainPointer’ is
never assigned to, and will always have its default value

i think you forgot to specify something, Work great with MW2 (DirectX 9), but
crash with MW3(DirectX 10/10.1). Can you check your code. I think these
swapChainPointer have something wrong.

Thanks anyway

 Justin S.
FEBRUARY 13, 2013 AT 6:55 PM

I’ve been using it with DirectX 10/10.1 a bit lately for a video capture project
without any issues, I’ll check if I have made any changes.

Sousa
FEBRUARY 26, 2013 AT 6:08 AM

I think that can be a easyhook problem, (MW3), The test program fail in injec-
tion. The game in task manager appear like iw5m.dat *32. I tried, iw5m.dat,
iw5m.dat *32, iw5m.dll, iw5mp.exe and crash.

Arnaud Dovi
FEBRUARY 7, 2013 AT 4:53 AM

hope you like it, basically if you would like to use as it is you will have to comment a
few ShowError() under method 1 and 2 to let it run all tests silently but honestly
for the moment I test this on a large panel of games I have 500+ on Steam, and
havent caught one yet failing at method 3, but a lot failures with 1 and 2

MRmP
FEBRUARY 8, 2013 AT 8:09 AM

Hi, this is a bit off topic but would appreciate your help.
As I’ve hooked into this application, Is it possible to find text written by the appli-
cation from the Device or Hook? or do i need to do screengrabs and advanced
OCR?

 Justin S.
FEBRUARY 8, 2013 AT 8:22 AM
If a standard API is being used e.g. The drawtext method in directx 9 or GDI+
then yes you can (or if u can determine the address of an internal method that
handles it)

I have done the OCR approach in the past with success but I would try looking
for an API call first.

MRmP
FEBRUARY 13, 2013 AT 5:20 AM

Yeah im using directx 9, would this be possible from the EndScene or do i need to
hook even deeper?

 Justin S.
FEBRUARY 13, 2013 AT 6:49 PM

EndScene won’t really give you what you need (except to do OCR), you are bet-
ter off starting with looking at ID3DXFont::DrawText. If hooking that doesn’t
help then it really depends on what the app is using, I suggest you use something
like API Monitor to see if that helps you find what API is being used to draw text.

Arnaud Dovi
FEBRUARY 15, 2013 AT 4:40 AM

Isn’t you developing EasyHook Justin ? Just to let you know in case you wonder,
Gearbox software redistributes EasyHook in Aliens Colonial Marines as
EasyHook32.dll

 Justin S.
FEBRUARY 15, 2013 AT 9:23 AM

Nice to know thanks – do you know what version was on the DLL?

Arnaud Dovi
FEBRUARY 16, 2013 AT 4:11 AM

after scanning steam rep it seems widely used in game industry, often the
same version in the same subfolders \Binaries\Win32\

Aliens Colonial Marines => 1.0.0.1


(md5:d3118c3594b44e9330c939ff76f9fe4d)
Borderlands2 => no assembly infos, seems recompiled,
(md5:8b58ded2f7267d1f81142ffdd732040e)
Dungeon Defenders => 1.0.0.1 digitally signed to Epic Games Inc
(md5:d3118c3594b44e9330c939ff76f9fe4d)
Special Forces Team X => 1.0.0.1 digitally signed to Epic Games
Inc(md5:d3118c3594b44e9330c939ff76f9fe4d)
XCom-Enemy-Unknown => no assembly infos, digitally signed to Epic Games
Inc, (md5:6de260691f7179572b54a1989347efd3)

Arnaud Dovi
FEBRUARY 16, 2013 AT 4:14 AM

btw sorry for not posting in the trees I figured out I had not enabled java-
script and cookies for your site hehe

Arnaud Dovi
FEBRUARY 15, 2013 AT 4:46 AM

Company assembly name : Christoph Husse

 Justin S.
FEBRUARY 15, 2013 AT 9:21 AM

Christoph is the original author of EasyHook. I took over development of the


project mid-2012 (with his blessing) after he had stopped maintaining it for
some time.

Arnaud Dovi
FEBRUARY 16, 2013 AT 4:10 AM

after scanning steam rep it seems widely used in game industry, often the
same version in the same subfolders \Binaries\Win32\

Aliens Colonial Marines => 1.0.0.1


(md5:d3118c3594b44e9330c939ff76f9fe4d)
Borderlands2 => no assembly infos, seems recompiled,
(md5:8b58ded2f7267d1f81142ffdd732040e)
Dungeon Defenders => 1.0.0.1 digitally signed to Epic Games Inc
(md5:d3118c3594b44e9330c939ff76f9fe4d)
Special Forces Team X => 1.0.0.1 digitally signed to Epic Games
Inc(md5:d3118c3594b44e9330c939ff76f9fe4d)
XCom-Enemy-Unknown => no assembly infos, digitally signed to Epic Games
Inc, (md5:6de260691f7179572b54a1989347efd3)

Platon
MARCH 19, 2013 AT 8:16 AM
Dear Justin,

Thank you for creating this blog, it helped me a lot in my current project where I
had to add a text overlay in dx9/11 games.

For dx11 I used a technique described here http://www.aaronblog.us/?p=36.

I’ve split the code from above-mentioned program into initialization and present
functions inside DXHookD3D11 class as follows:

Initialization:

private static SlimDX.Direct3D10_1.Device1 device10;


private static SlimDX.Direct2D.Factory d2Factory;
private static SlimDX.DirectWrite.TextFormat textFormat;
private static SlimDX.Direct2D.RenderTargetProperties rtp;
private static BlendStateDescription bsd;
private static ShaderBytecode shaderByteCode;
private static DataStream verticesText;

public DXHookD3D11(ScreenshotInterface.ScreenshotInterface ssInterface)


: base(ssInterface)
{
Factory1 factory1 = new Factory1();

Adapter1 adapter1 = factory1.GetAdapter1(0);

device10 = new SlimDX.Direct3D10_1.Device1(adapter1,


SlimDX.Direct3D10.DriverType.Hardware,
SlimDX.Direct3D10.DeviceCreationFlags.BgraSupport,
SlimDX.Direct3D10_1.FeatureLevel.Level_10_0);

// Direct2D Factory
d2Factory = new SlimDX.Direct2D.Factory(
SlimDX.Direct2D.FactoryType.SingleThreaded,
SlimDX.Direct2D.DebugLevel.Information
);

// Direct Write factory


SlimDX.DirectWrite.Factory dwFactory = new SlimDX.DirectWrite.Factory(
SlimDX.DirectWrite.FactoryType.Isolated
);
// The textFormat we will use to draw text with
textFormat = new SlimDX.DirectWrite.TextFormat(
dwFactory,
“Arial”,
SlimDX.DirectWrite.FontWeight.Normal,
SlimDX.DirectWrite.FontStyle.Normal,
SlimDX.DirectWrite.FontStretch.Normal,
16,
“en-US”
);

rtp = new SlimDX.Direct2D.RenderTargetProperties();


rtp.MinimumFeatureLevel = SlimDX.Direct2D.FeatureLevel.Direct3D10;
rtp.Type = SlimDX.Direct2D.RenderTargetType.Hardware;
rtp.Usage = SlimDX.Direct2D.RenderTargetUsage.None;
rtp.PixelFormat = new SlimDX.Direct2D.PixelFormat(Format.Unknown,
SlimDX.Direct2D.AlphaMode.Premultiplied);

// Think of the shared textureD3D10 as an overlay.


// The overlay needs to show the text but let the underlying triangle (or whatever)
// show thru, which is accomplished by blending.
bsd = new BlendStateDescription();
bsd.RenderTargets[0].BlendEnable = true;
bsd.RenderTargets[0].SourceBlend = BlendOption.SourceAlpha;
bsd.RenderTargets[0].DestinationBlend = BlendOption.InverseSourceAlpha;
bsd.RenderTargets[0].BlendOperation = BlendOperation.Add;
bsd.RenderTargets[0].SourceBlendAlpha = BlendOption.Zero;
bsd.RenderTargets[0].DestinationBlendAlpha = BlendOption.Zero;
bsd.RenderTargets[0].BlendOperationAlpha = BlendOperation.Add;
bsd.RenderTargets[0].RenderTargetWriteMask = ColorWriteMaskFlags.All;

// Load Effect. This includes both the vertex and pixel shaders.
// Also can include more than one technique.
shaderByteCode = ShaderBytecode.CompileFromFile(
“effectDx11.fx”,
“fx_5_0”,
ShaderFlags.EnableStrictness,
EffectFlags.None);

// create text vertex data, making sure to rewind the stream afterward
// Top Left of screen is -1, +1
// Bottom Right of screen is +1, -1
verticesText = new DataStream(VertexPositionTexture.SizeInBytes * 4, true, true);
verticesText.Write(new VertexPositionTexture(new Vector3(-1, 1, 0), new
Vector2(0, 0f)));
verticesText.Write(new VertexPositionTexture(new Vector3(1, 1, 0), new
Vector2(1, 0)));
verticesText.Write(new VertexPositionTexture(new Vector3(-1, -1, 0), new
Vector2(0, 1)));
verticesText.Write(new VertexPositionTexture(new Vector3(1, -1, 0), new
Vector2(1, 1)));
verticesText.Position = 0;

factory1.Dispose();
adapter1.Dispose();
dwFactory.Dispose();
}

Present:

int PresentHook(IntPtr swapChainPtr, int syncInterval,


SlimDX.DXGI.PresentFlags flags)
{
……
#region TODO: Draw overlay (after screenshot so we don’t capture overlay as
well)
if (this.ShowOverlay)
{
Texture2D backBuffer = Texture2D.FromSwapChain(swapChain, 0);
SlimDX.Direct3D11.Device device11 = backBuffer.Device;

// setting a viewport is required if you want to actually see anything


var context = device11.ImmediateContext;

if (device11 == null)
this.DebugMessage(“NULL”);

SlimDX.Direct3D11.Texture2D texture11 = new Texture2D(device11, new


Texture2DDescription()
{
Width = backBuffer.Description.Width,
Height = backBuffer.Description.Height,
MipLevels = 1,
ArraySize = 1,
Format = Format.B8G8R8A8_UNorm,
SampleDescription = new SlimDX.DXGI.SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.KeyedMutex
});

SlimDX.DXGI.Resource sharedResource = new


SlimDX.DXGI.Resource(texture11);
SlimDX.Direct3D10.Texture2D texture10 =
device10.OpenSharedResource(sharedResource.SharedHandle);

KeyedMutex mutex10 = new KeyedMutex(texture10);


KeyedMutex mutex11 = new KeyedMutex(texture11);

// Query for a IDXGISurface.


// DirectWrite and DirectX10 can interoperate thru DXGI.
Surface surface = texture10.AsSurface();
SlimDX.Direct2D.RenderTarget dwRenderTarget =
SlimDX.Direct2D.RenderTarget.FromDXGI(d2Factory, surface, rtp);

// Brush used to DrawText


SlimDX.Direct2D.SolidColorBrush brushSolidWhite = new
SlimDX.Direct2D.SolidColorBrush(
dwRenderTarget,
System.Drawing.Color.Red
);

BlendState BlendState_Transparent = BlendState.FromDescription(device11,


bsd);

Effect effect = new Effect(backBuffer.Device, shaderByteCode);

// create the text vertex layout and buffer


InputLayout layoutText = new InputLayout(device11,
effect.GetTechniqueByName(“Text”).GetPassByIndex(0).Description.Signature,
VertexPositionTexture.inputElements);
verticesText.Seek(0, SeekOrigin.Begin);
SlimDX.Direct3D11.Buffer vertexBufferText = new
SlimDX.Direct3D11.Buffer(device11, verticesText, (int)verticesText.Length,
ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None,
ResourceOptionFlags.None, 0);

mutex10.Acquire(0, 100);
dwRenderTarget.BeginDraw();
dwRenderTarget.Clear(new Color4(0, 0, 0, 0));
string text = “TEST”;
dwRenderTarget.DrawText(text, textFormat, new System.Drawing.Rectangle(100,
100, 300, 300), brushSolidWhite);
dwRenderTarget.EndDraw();
mutex10.Release(0);

// Draw the shared texture2D onto the screen


// Need to Aquire the shared texture for use with DirectX11
mutex11.Acquire(0, 100);
ShaderResourceView srv = new ShaderResourceView(device11, texture11);
effect.GetVariableByName(“g_textOverlay”).AsResource().SetResource(srv);
context.InputAssembler.InputLayout = layoutText;
context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleStrip;
context.InputAssembler.SetVertexBuffers(0, new
VertexBufferBinding(vertexBufferText, VertexPositionTexture.SizeInBytes, 0));
context.OutputMerger.BlendState = BlendState_Transparent;
EffectTechnique currentTechnique = effect.GetTechniqueByName(“Text”);
for (int pass = 0; pass < currentTechnique.Description.PassCount; ++pass)
{
EffectPass Pass = currentTechnique.GetPassByIndex(pass);
System.Diagnostics.Debug.Assert(Pass.IsValid, "Invalid EffectPass");
Pass.Apply(context);
context.Draw(4, 0);
}
srv.Dispose();
mutex11.Release(0);

vertexBufferText.Dispose();
layoutText.Dispose();
effect.Dispose();

mutex10.Dispose();
mutex11.Dispose();
texture10.Dispose();
texture11.Dispose();
sharedResource.Dispose();
surface.Dispose();
dwRenderTarget.Dispose();
brushSolidWhite.Dispose();
BlendState_Transparent.Dispose();
backBuffer.Dispose();
device11.Dispose();
}
#endregion
…..
}

For this to run 'effectDx11.fx' file must be present at the location of hooked
executable.

I would assume that this can still be optimized further and would love to hear your
opinion on that matter.

Still from many techniques that I tried which included:


* using a library from http://fw1.codeplex.com/ with an additional c# wrapper class
* drawing characters from texture file

this method seemed to be the fastest one.

I hope it helps you and hope that you will incorporate it into the project.

 Justin S.
MARCH 19, 2013 AT 9:48 PM

Thanks for that, I will definitely take a closer look and incorporate something
into the project – I have actually started doing something for it in DX11 using
GDI+ to create a texture for the specified font and then rendering those directly
to the surface, but I think it would be better to go the shared surface/resource
route like you have here.

Thanks again for posting your examples.


Cheers,
Justin

Platon
APRIL 17, 2013 AT 10:59 PM

Hi Justin,

I’ve noticed you have uploaded new version with DX11 overlay.
However it doesn’t work for me, even tho I clearly see that overlayEngine is being
initialized and drawn – no text or fps is being shown on screen.
Can you confirm that it is still in development or it’s something wrong on my side.

Thanks,
Platon
 Justin S.
APRIL 22, 2013 AT 7:53 PM

Hi Platon,

Yes it is still in development, however I have had it working fine here…

It sounds like perhaps the font engine is failing – I’ll take a look at it and see if
there is anything obvious going wrong for you.

Cheers,
Justin

MRmP
APRIL 28, 2013 AT 9:49 PM

As my UI platform is not supporting SharpDX, would it be difficult to replace


ShartDX with slimdx on your new version, or do I need to stick to an older version?

 Justin S.
APRIL 29, 2013 AT 12:23 AM

Very easy – just have to a couple of renames and you will be fine. Compare
against previous will sort it for you. May I ask what platform you are referring
to? I was pretty sure sharp dx was good to go on them all. Oh the actual UI
framework u mean? Nevermind.

MRmP
APRIL 29, 2013 AT 5:01 AM

Hi, yeah, I found the Squid UI to be very neat, the developer are daily on the
forums to help out, http://www.ionstar.org/. He also said he would make it
work with ShartDX, so maybe I don’t have to change it back to SlimDX 🙂

 Justin S.
APRIL 29, 2013 AT 8:53 AM

That’s great news I’ll go check it out when I find some free time. Thanks for
the link.
Cheers,
Justin

Stevo5800
JULY 3, 2013 AT 1:37 AM

Hey, I’ve tried this code. I downloaded the latest from your repo. But it doesn’t
seem to work properly. I tried it with Black Ops II worked no problem. All my other
games it gives me an error “Additional information: Injection to the target process
failed. See InnerException for more detail.” Well the other games I’ve tried was
War Of The Roses, Battlefield 3 and Borderlands all give me that error stopped
trying other games because it’s discouraging lol

 Justin S.
JULY 3, 2013 AT 9:08 AM

Hey stevo, I will be looking at this but not for some time – I have a few pots bub-
bling away that is taking all my free time right at the moment. Let me know if you
make any progress. I’ll be looking at it later in the year.
Cheers, J

Morten
JULY 24, 2013 AT 6:28 AM

Hi Justin
Thanks for this awesome code:)
Could use some pointers dough….hoping you could help me.
I am trying to display dynamic text overlay in i DX11 game.
I have added / uncommented the follwing line in “DXHookD3D11.cs”

new Capture.Hook.Common.TextElement(new System.Drawing.Font(“Times New


Roman”, 22)) { Text = “Test”, Location = new System.Drawing.Point(200, 200), Color
= System.Drawing.Color.Yellow, AntiAliased = false},

And
new Capture.Hook.Common.FramesPerSecond(new System.Drawing.Font(“Arial”,
16)) { Location = new System.Drawing.Point(10,10), Color =
System.Drawing.Color.Red, AntiAliased = true }

And now it displays the FPS and static “Test” how can i make that text dynamic
from my class?

I am also trying to use:

captureInterface.DisplayInGameText(“Test text from Main”,new


TimeSpan(0,0,30));
And
_captureProcess.CaptureInterface.DisplayInGameText(“Test text from Main 2”);
But i get no respond on those..

Reg. Morten

 Justin S.
JULY 24, 2013 AT 9:43 AM

Hi Morten, I’m away on business at the moment but will try to get around to an-
swering your questions next week.
Cheers,
Justin

Daniel Tian
AUGUST 10, 2013 AT 6:51 AM

I’m working on an Ambilight project and I’m trying to use


captureProcess.CaptureInterface.BeginGetScreenshot() to capture screenshots
repeatedly. This works, but whenever I hook into an application and begin the cap-
ture, the memory usage rapidly increases until I get an OutOfMemoryException
and the host process crashes. I’ve tried to add in delay, only capture a new screen-
shot when the previous one is done processing, and slow it down to only 1 capture
per second, but in all cases, the application eventually crashes.

I believe this is due to a memory leak somewhere in the application, but I’m not
skilled enough to make heads or tails out of the source. In the meantime, I’m look-
ing at your Afterglow project, but I was wondering if I’m doing something wrong
which is leading to the OutOfMemoryException? I’d include my source but it’s ba-
sically just captureProcess.CaptureInterface.BeginGetScreenshot(), then in the
event handler I call EndGetScreenshot(), then do a Console.WriteLine() without
processing the screenshot at all.

Daniel Tian
AUGUST 10, 2013 AT 7:32 AM

An update: I tried using the Direct3DCapture library in Afterglow 0.2. I added a


GetCapture() method that returns the FastBitmap, and then I call
ReleaseCapture() once I’m done processing the FastBitmap. The code is some-
thing like this:

while (true)
{
var bitmap = capture.GetCapture();
if (bitmap != null)
{
var color = bitmap.GetPixel(200, 200);
Console.WriteLine(color);
}

capture.ReleaseCapture();
}

Unfortunately, I still run into the same problem, after a few seconds the memory
usage shoots through the roof and I get the OutOfMemoryException.

 Justin S.
AUGUST 10, 2013 AT 12:11 PM

Let’s take the discussion to the afterglow site – perhaps u could paste some of
your code of the getcapture and releasecapture so we can help u out further.

Pingback: Unity3D, Oculus Rift and the fullscreen problem

Pingback: Rendering from WPF’s internals to a Directx application | TechwikiHow

asdasdffasdiuiz
JANUARY 3, 2014 AT 1:40 AM

Can you tell me how I can use this from some kind of command line? Or is there a
simple class to get the screenshot without using the GUI. C# is not my language of
choise, so I am a bit lost here.

I just want to get a 2d Array of the bitmap data like: Screenshot screenshot =
takeScreenshot(“asdf.exe”);

 Justin Stenning
JANUARY 12, 2014 AT 9:40 AM

You would need to wrap the library within a console application.

The folks at http://www.donationcoder.com did a similar thing for a Direct3D


capture test for their screenshot application.

jake072
OCTOBER 7, 2014 AT 6:50 AM

I’ve tried testing your code on bf4. I’m trying to make a program that randomnly
captures screenshots to test for cheaters for my clan, however, in all my tests, I
keep getting an error: { DirectX funtion “screen->swapChain-
>ResizeBuffers(renderer->m_settings->getTripleBufferingEnable() ? 3 : 2, screen-
>info.windowWidth, screen->info.windowHeight,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCHED)” failed with
DXGI_ERROR_INVALID_CALL (“The application provided invalided parameter
data; this must be debugged and fixed before the application is released.”). GPU:
“NVIDIA GeForce GTX 760”, Driver: 34411 }

 Justin Stenning
OCTOBER 7, 2014 AT 7:29 AM

Is this using the test screenshot app or some of your custom logic? I have an ex-
ample app that is for that exact purpose as well, ill try to get that posted for you.

jake072
OCTOBER 8, 2014 AT 5:02 AM

That was with the test screenshot app compiled from your code. The only
thing I changed was adding a button with a file picker to make entering the
window to capture easier.

 Justin Stenning
OCTOBER 13, 2014 AT 7:28 PM

I’ve done a quick test and have also experienced some issues, although not
the same errors you listed. I’ll try to look at it soon.

jake072
OCTOBER 16, 2014 AT 11:45 PM

Justin,

I found some issues in battlelog forums saying that this might be related
to language options. I’ve changed my options to English US, but I get the
same errors still. The Debug window shows that it was injected into the
process, however, whenever I hit “Request Capture”, I get the aforemen-
tioned errors.
Not sure if that helps, but I have no idea how to fix this, really hoping you
can help out.

Thanks,
Jake

jake072
OCTOBER 16, 2014 AT 11:53 PM

Justin,

Ok, I tried manually selecting Direct3D 11, and it doesn’t fail, however,
nothing gets rendered or anything. It did crash under a load test of 100
captures, and eventually crashed bf4 too. Hope that helps.

Thanks again,

Jake

eddy
OCTOBER 15, 2014 AT 1:34 AM

Hi Justin,

When I try to save a screenshot from a directx 11 game to the hard drive in a png
format, the screenshot’s colors are “washed out”. But the picture appears fine in
picturebox1 of the form.
I tried it with MetroLL, Bioshock Infinite and Watchdogs. This doesn’t happen for
other formats regardless of directx version.
I’m referencing DXHookD3D11.cs
Added 2 lines:
FileStream fs = new FileStream(@”c:\temp.png”, FileMode.Create);
Texture2D.ToStream(textureDest.Device.ImmediateContext,
textureDest,ImageFileFormat.Png, fs);

 Justin Stenning
OCTOBER 15, 2014 AT 4:52 PM

You’ll probably find that the image captured is slightly transparent. Could you
please check what the alpha looks like in the resulting image?

eddy
OCTOBER 15, 2014 AT 10:11 PM
Thanks Justin for taking a look at this.
I’ve uploaded 4 .png formats from 3 different directx 11 titles.

Bioshock Infinite: persistent rectangle. If you capture early, during menu screens,
you’ll notice that they stack up…what you capture “now” has remnants from previ-
ous screen on the captured png.
http://i60.tinypic.com/2nuufwx.png
http://i58.tinypic.com/2wp2eqr.png

Metro Last Light:


http://i60.tinypic.com/2ll2bra.png

Watch Dogs:
http://i59.tinypic.com/wqxyeb.png

Alpha is as set in R8G8B8A8_UNorm format. No other format worked.

I tried capturing without copying to memory stream.


I tried capturing before destination texture was created.
Same results.

 Justin Stenning
OCTOBER 16, 2014 AT 8:03 PM

These all seem like artefacts of the way these games are performing their ren-
dering, e.g. they might have more than one swapchain and so on. I would need to
take a closer look at these games to work it out, but don’t have any of them at
the moment sorry. Did you say that the preview shows correctly, what happens
if you save as BMP instead?

eddy
OCTOBER 17, 2014 AT 12:20 AM

Saving as BMP in any directx version yields no issues.


Saving as JPG in any directx version yields no issues.
Saving as PNG in directx 9 and 10 yields no issues.
The only anomaly is when capturing/saving as PNG in directx 11.
Preview shows fine.

It’s not a big deal since it works fine in bmp and jpg.
It must be, like you said, the way the games are rendering…I’ll go down this road
and post back if successful.

Many thanks
regame
OCTOBER 27, 2014 AT 1:51 PM

works fine! and many comments in source.. it’s very helpful.


i’ll follow your github.

thanks

eddy
NOVEMBER 11, 2014 AT 3:15 AM

I was able to solve the issue above…saving pngs to hard drive was not working.
I’ll post the code here…maybe it’ll help someone. I looked at several projects on
github using Justin’s code but with some enhancements.

DXHookD3D11.cs

using System.Drawing;
using System.Drawing.Imaging;

private byte[] dd;


Texture2D textureDest;

int PresentHook(IntPtr swapChainPtr, int syncInterval,


SharpDX.DXGI.PresentFlags flags)
{
var theTexture = texture;

// If texture is multisampled, then we can use ResolveSubresource to copy it into a


non-multisampled texture
Texture2D textureResolved = null;
if (texture.Description.SampleDescription.Count > 1)
{
this.DebugMessage(“PresentHook: resolving multi-sampled texture”);
// texture is multi-sampled, lets resolve it down to single sample
textureResolved = new Texture2D(texture.Device, new Texture2DDescription()
{
CpuAccessFlags = CpuAccessFlags.None,
Format = texture.Description.Format,
Height = texture.Description.Height,
Usage = ResourceUsage.Default,
Width = texture.Description.Width,
ArraySize = 1,
SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0), // Ensure sin-
gle sample
BindFlags = BindFlags.None,
MipLevels = 1,
OptionFlags = texture.Description.OptionFlags
});
// Resolve into textureResolved
texture.Device.ImmediateContext.ResolveSubresource(texture, 0, textureRe-
solved, 0, texture.Description.Format);

// Make “theTexture” be the resolved texture


theTexture = textureResolved;
}

// Create destination texture


if (textureDest == null)
{
textureDest = new Texture2D(texture.Device, new Texture2DDescription()
{
CpuAccessFlags = CpuAccessFlags.Read,//CpuAccessFlags.Read,
Format = SharpDX.DXGI.Format.R8G8B8A8_UNorm, // Supports BMP/PNG
Height = regionToCaptureDest.Height,
Usage = ResourceUsage.Staging,// ResourceUsage.Default,
Width = regionToCaptureDest.Width,
ArraySize = 1,//texture.Description.ArraySize,
SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),//
texture.Description.SampleDescription,
BindFlags = BindFlags.None,
MipLevels = 1,//texture.Description.MipLevels,
OptionFlags = texture.Description.OptionFlags //|
ResourceOptionFlags.GdiCompatible
});
}

Texture2D theTexture2 = new Texture2D(texture.Device, new


Texture2DDescription()
{
CpuAccessFlags = CpuAccessFlags.None,
Format =
SharpDX.DXGI.Format.R8G8B8A8_UNorm,//texture.Description.Format,
Height = regionToCaptureDest.Height,
Usage = ResourceUsage.Default,
Width = regionToCaptureDest.Width,
ArraySize = 1,
SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0), // Ensure sin-
gle sample
BindFlags = BindFlags.None,
MipLevels = 1,
OptionFlags = texture.Description.OptionFlags //|
ResourceOptionFlags.GdiCompatible
});

SharpDX.Direct3D11.Resource.LoadTextureFromTexture(texture.Device.Immedi
ateContext, theTexture, theTexture2,
new TextureLoadInformation()
{
SourceRegion = new ResourceRegion()
{
Top = regionToCapture.Top,
Bottom = regionToCapture.Bottom,
Left = regionToCapture.Left,
Right = regionToCapture.Right,
Front = 0,
Back = 1 // Must be 1 or only black will be copied
},
DestinationRegion = new ResourceRegion()
{
Top = regionToCaptureDest.Top,
Bottom = regionToCaptureDest.Bottom,
Left = regionToCaptureDest.Left,
Right = regionToCaptureDest.Right,
Front = 0,
Back = 1 // Must be 1 or only black will be copied
},
ElementCount = 1,
Filter = FilterFlags.Linear,
FirstDestinationElement = 0,
FirstDestinationMip = 0,
FirstSourceElement = 0,
FirstSourceMip = 0,
MipCount = 1,
MipFilter = FilterFlags.Linear
});

// Copy the subresource region, we are dealing with a flat 2D texture with no
MipMapping, so 0 is the subresource index
theTexture.Device.ImmediateContext.CopySubresourceRegion(theTexture2, 0,
new ResourceRegion()
{
Top = regionToCaptureDest.Top,
Bottom = regionToCaptureDest.Bottom,
Left = regionToCaptureDest.Left,
Right = regionToCaptureDest.Right,
Front = 0,
Back = 1 // Must be 1 or only black will be copied
}, textureDest, 0, 0, 0, 0);
theTexture.Device.ImmediateContext.CopyResource(theTexture, textureDest);

DataStream dstream;
DataBox box =
textureDest.Device.ImmediateContext.MapSubresource(textureDest, 0, 0,
SharpDX.Direct3D11.MapMode.Read, SharpDX.Direct3D11.MapFlags.None, out
dstream);

IntPtr data = dstream.DataPointer;

int width = textureDest.Description.Width;


int height = textureDest.Description.Height;

if (bitmap == null)
{
bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
dd = new byte[width * height * 4];
}
Marshal.Copy(data, dd, 0, dd.Length);

textureDest.Device.ImmediateContext.UnmapSubresource(textureDest, 0);

for (int i = 0; i < dd.Length; i += 4)


{
byte tmp = dd[i];
dd[i] = dd[i + 2];
dd[i + 2] = tmp;
}

BitmapData bd = bitmap.LockBits(new System.Drawing.Rectangle(0, 0,


bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat);

Marshal.Copy(dd, 0, bd.Scan0, dd.Length);


bitmap.UnlockBits(bd);

}
//save it…
FileStream fs = new FileStream(@Path + "\\Screenshots\\" + thisgame +
DateTime.Now.ToString("-yyyy-MM-dd@hh.mm.ss") + ".png", FileMode.Create);
bitmap.Save(fs, System.Drawing.Imaging.ImageFormat.Png);

I also applied this to d3d10 but with some minor changes.

Thanks

Vlad
NOVEMBER 23, 2014 AT 9:54 PM

Hello,
I have problem, with EasyHook: “System.IO.FileLoadException”
All show the error can not, cause it is in Russian.

 Justin Stenning
NOVEMBER 29, 2014 AT 8:17 PM

Hi Vlad, please make sure you have ALL the EasyHook binaries in your target
build directory.

Sergey
DECEMBER 12, 2014 AT 11:01 AM

Yes, I encountered the same problem.


2013 VS, Windows 8.1

Lines

_captureProcess = new CaptureProcess(process, cc, captureInterface);

Sergey
DECEMBER 12, 2014 AT 8:30 PM

Yes, I encountered the same problem

Line:

_captureProcess = new CaptureProcess(process, cc, captureInterface);

VS 2013 Windows 8.1


Sergey
DECEMBER 12, 2014 AT 11:29 PM

this happens because in

public CaptureProcess(Process process, CaptureConfig config, CaptureInterface


captureInterface) {

// Initialise the IPC server (with our instance of _serverInterface)


_screenshotServer = RemoteHooking.IpcCreateServer(
ref _channelName,
WellKnownObjectMode.Singleton,
_serverInterface);


}

and on RemoteHooking

#region Assembly EasyHook.dll, v2.5.0.0


// C:\work\development\Direct3DHook_2011-03-14\Direct3DHook-
master\bin\EasyHook.dll
#endregion

we have another instance

public static IpcServerChannel IpcCreateServer(ref string RefChannelName,


WellKnownObjectMode InObjectMode, params WellKnownSidType[]
InAllowedClientSIDs) where TRemoteObject : MarshalByRefObject;

how this fix ? or project reference use wrong version EasyHook.dll?

raistlinthewiz
JANUARY 20, 2015 AT 11:46 PM

anyone know how to draw an image overlay?

 Justin Stenning
JANUARY 22, 2015 AT 6:58 PM
Load an image into a D3D texture, and then render that to a quad either
fullscreen or whatever. Look for D3D render to screen-aligned quad or similar
(my book covers it), I am working on an example to implement GPU resizing of
captured images but will take me a while to find the time to complete.

Pingback: rendering an image within c# & sharpdx dirext3d9 [game overlay] | DL-UAT

Pingback: Ceiba3D Studio | rendering an image within c# & sharpdx dirext3d9 [game
overlay]

James
JANUARY 27, 2015 AT 6:16 PM

If it returns error “not supported,” then nothing can be done, correct? The program
was written in a way to block this sort of interaction? Thanks.

 Justin Stenning
FEBRUARY 19, 2015 AT 5:47 PM

I would probably need to see more about why you received “not supported” to
rule out any incorrect behaviour on behalf of the library.

abo
FEBRUARY 15, 2015 AT 11:26 PM

when drawing text in directx 11, does you method natively support formatting like
BottomLeft, TopRight, NoClip…etc. I’m trying to draw text in corners.
I’ve included ContentAlignment and StringFormatFlags in TextElements.cs and up-
dated DrawString() function in DXSprite.cs and updated the line where elements
are drawn in Present() but those changes are ignored.

 Justin Stenning
FEBRUARY 19, 2015 AT 5:46 PM

My implementation is fairly basic and doesn’t support any anchors, shouldn’t be


too difficult to add however.

Abo
MARCH 17, 2015 AT 5:38 AM

Hi Justin,
Thank you. I was able to solve it by measuring textElement width and height
and then taking the values and subtracting them from _renderTarget width
and height. It works on multilines and even when textElement width changes
each frame.

I am now facing another challenge. On a bunch of DX11 games, changing reso-


lution leaves the games either frozen or with a black screen (with overlay still
showing) *only if I draw the overlay*. If I uncheck the option, changing resolu-
tion succeeds. This has nothing to do with measuring textElement because it
also happens using original code.

I read that we must dispose of all resources associated with the swap chain
prior to changing resolution, and your code is doing that. Games are running
full-screen also so I don’t think hooking ResizeBuffers is needed although I
have tried it.

DXFont.cs and DXSprite.cs dispose of all assets…I made no changes here


DXOverlayEngine.cs…only change I made is dispose both _renderTarget and
_renderTargetView

Grateful for any tip.

 Justin Stenning
MARCH 19, 2015 AT 8:30 PM

Hi Abo, can you try turning on the overlays, then turning them off in code
before resolution change, then turning on again after resolution change.
This might help us work out what is happening.

abo
MARCH 22, 2015 AT 5:03 AM

Hi Justin,

Thank you, yes I can. My version implements a keyboard hook.

One hotkey hooks the DX11 game.


Another hotkey toggles the overlay on / off.

I am *almost* certain that this is due to text drawing because if I don’t


draw (comment out all draw calls), just hook and take screenshots then
resolution change succeeds.
Trying out what you requested:
Launch the game (draw calls uncommented), hotkey hooks game, overlay
is on, hotkey turns overlay off, attempt resolution change: different out-
comes depending on which game:
a. user interface elements are now offset. To click an element with the
pointer, you have to place it away from the element…as if resolution is
way larger than the screen…in fact some elements become cut off
b. completely frozen screen…no way to accept/reject new resolution
(pointer moves but elements are unresponsive)

Turning on the overlay after a or b will show a garbled overlay…fps


counter painting over itself

After Ctrl+Alt+Del out of the game, starting it again shows the requested
resolution which had failed earlier.

If needed, I can upload pictures.


Many other DX11 games work fine.

Luke
FEBRUARY 21, 2015 AT 9:01 AM

Hi Justin,

I’ve been working with your library for about a day now and it seems pretty nifty,
but I’m not quite sure how you intended people to use it.

What I want to do is display a simple image overlay in a DirectX9 game. I’ve played
around with the TestScreenshot application that you provided so I know that this
is possible, but I’m not sure where my code should go. Did you intend people to put
custom overlay code in the EndSceneHook() method ? (Or perhaps
DoCaptureRenderTarget().)

Since this is an internal class in the library it sort of feels wrong to plop my own
code in there, but given the nature of the application I understand if this is the sim-
plest solution. Any help is much appreciated.

 Justin Stenning
FEBRUARY 23, 2015 AT 4:39 PM

Hi Luke,

It is really only meant to be an example of how it can be done and act as a start-
ing point, from there pull apart the code and do what you need to do with it 🙂
If you want to leave most of the library unchanged, I would probably do your
changes within DoCaptureRenderTarget, then you can ignore most of the hook-
ing / other logic necessary and focus on your task. Perhaps write your code in
another class and call it from DoCaptureRenderTarget (or from where ever
DoCaptureRenderTarget is called if you want it to make more sense :).

Good luck and cheers!


Justin

Luke
FEBRUARY 25, 2015 AT 8:49 AM

Hi again,

So I’ve been messing around with TestScreenshot a bit more and I appear to
have run into some synchronization issues. I want to send a string from my
host application to the target one so I’ve been using
CaptureInterface.DisplayInGameText() to see when it can be called, since this
does essentially the same thing. I’ve found that calling it after initializing the
CaptureProcess leads to some issues. For example, if I try to call this method
at the end of AttachProcess() in Form1.cs then nothing happens – the text
isn’t displayed in the overlay. More specifically, the TextDisplay in the corre-
sponding BaseDXHook is never set, probably because the event handler
never gets called. However, if I call DisplayInGameText() from the click han-
dler for the Request Capture button after the injection is complete, then the
text does get displayed in the overlay.

It seems to me like the source of the issue is that something asynchronous is


going on. If I had to guess I’d say that the IPC channel isn’t set up immediately
when the CaptureProcess is created, which would explain why the event han-
dler for DisplayInGameText() isn’t getting called. I imagine that there’s a simi-
lar problem if you try to call other methods in CaptureInterface like
GetScreenshot() immediately after creating the CaptureProcess, although I
haven’t verified this myself. Is there an easy way to synchronize the two
processes?

 Justin Stenning
FEBRUARY 28, 2015 AT 8:24 PM

What is happening is that you are calling the method before the hook has
completed installing (which is happening in your remote process – so yes
definitely asynchronous). You could create an event on the interface that is
triggered after hooking has completed (within the Run method of the entry
point in the Capture project).

altairattano
MAY 16, 2015 AT 2:53 AM

Hey, thanks for the awesome work. Screenshotting works perfect, however for
capturing video the whole process is kind of slow. I mean, if I just keep querying for
screenshots and feeding them to ffmpeg or whatever, my resulting FPS won’t ex-
ceed 10-15. Is there any chance of getting proper video recording support?

Once again, thank you for your work, much appreciated. Cheers.

 Justin Stenning
JUNE 3, 2015 AT 7:03 PM

Hi, you need to do this differently, but changing the capture library to hook mul-
tiple frames, rather than requesting each individually.

I semi-started this piece of work, and have implemented a circular-buffer (ring-


buffer) using shared memory to help with this (see
sharedmemory.codeplex.com).

Still plenty of work needed however.

Squall124
JUNE 14, 2015 AT 12:20 AM

Hi !

I’m trying to learn how to display a steam-like overlay using C#, that’s why I ended
up on your post.
First, thank you for this post, it’s very helpfull !

But I still have some trouble. With your code, we can display something on top of
games, but what I mean by “steam-like overlay” is an overlay I can interact with.

My ultimate goal is to display an ingame web browser.

Any advice how to make the overlay clickable ?

Or if you know how to have a web browser on top of fullscreen apps / games, it
would be very appreciated !
Thank you, and sorry for my bad english.

 Justin Stenning
JUNE 15, 2015 AT 7:20 PM

To do this you could render your browser control to an image (or a DX surface
perhaps), and then intercept the mouse and keyboard events using Global
Hooks and then push those events to your browser control.

Abhimanyu Gangwar
APRIL 4, 2017 AT 11:26 PM

Hey Justin!

Thanks for your wonderful post. I’m stuck in a similar situation where I want
to implement a steam like overlay on a game. Overwolf does it too. You say,
that I can render my browser control on a DX surface and that might do it. Did
you happen to try anything in similar context? I don’t have much experience
with DirectX so it would be helpful if you can point me in the right direction.

Thanks again!

 Justin Stenning
APRIL 4, 2017 AT 11:57 PM

Yes, using CefSharp you can render to offscreen browser and then render
with the resulting bitmap as a texture.

You can take a look at my SharedMemory library for quick xfer of image
data between processes if you don’t want to host CEF in your target
process.

Abhimanyu Gangwar
APRIL 5, 2017 AT 1:15 AM

Thanks a lot for responding. Where can I find your SharedMemory


library?

Abhimanyu Gangwar
APRIL 5, 2017 AT 1:16 AM

I just found it out. Thanks again. I’ll try this stuff 🙂


Sebastian
SEPTEMBER 12, 2015 AT 8:03 AM

Hi Justin!

First of all, thank you for your wonderful work! I appreciate it and
I implemented it in my new application.

I have a question though.

In DxHookD3D9.cs in the PresentHook (parameter “IntPtr windowOverride”)


function I get automatically from the calling Main Window and/or Child Window
of the game the Window Handle.

So my question is, how I’m gonna get the (Child) Window Handle from the calling
window of the game in In DxHookD3D10.cs and In DxHookD3D11.cs in
PresentHook, because there is no Parameter “IntPtr windowOverride”.

I know, I can loop the Current Process Threads through and get those Handles in a
List, but I need to identify the calling Window and get the current Window Handle
of it.

Hope you can help.

Thanx in advance.

Cheers,

Sebastian

 Justin Stenning
SEPTEMBER 20, 2015 AT 11:20 AM

You can use the WinAPI to determine which HWND is for which thread, e.g.
GetWindowThreadProcessId. You may need to first iterate each child window
handle for the process and call that method, the return value is the thread id, the
out param is the process id.

Sebastian
SEPTEMBER 20, 2015 AT 9:30 PM

Thanx for the reply Justin.


But how I’m gonna get then the Thread.Id of the Current Calling Child
Window in PresentHook to compare it with the Child Window Thread Ids that
you suggested?

The game has a lot of Child Windows, that’s why I need to know, which win-
dow exactly is calling PresentHook, because I need the Window Handle and
the Window Title of it to add it in a list, and if the user clicks one of the Entries
in that List in my app, he would see a stream of Jpgs in my app from the game
of that Child Window.

Here is the function I call to get the Child Window Handles and their Thread
Ids in PresentHook:

[DllImport(“user32.dll”)]
static extern bool EnumThreadWindows(int dwThreadId,
EnumThreadDelegate lpfn, IntPtr lParam);

[DllImport(“user32.dll”)]
private static extern bool IsWindowVisible(int hWnd);

[DllImport(“user32.dll”, CharSet = CharSet.Auto)]


private static extern int GetWindowText(int hWnd, StringBuilder title, int
size);

delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);

int PresentHook(IntPtr swapChainPtr, int syncInterval,


SlimDX.DXGI.PresentFlags flags)
{

getWindowhandle();

}

public void getWindowhandle()


{
if (gameProcess == null)
{
return;
}

foreach (ProcessThread processThread in gameProcess.Threads)


{
EnumThreadWindows(processThread.Id,
(windowhandle, lParam) =>
{
if (!IsWindowVisible((int)windowhandle))
{
return true;
}

StringBuilder title = new StringBuilder(256);


GetWindowText((int)windowhandle, title, 256);

if (title.Length == 0)
{
return true;
}

// QUESTION:
// ———————————————————————————–
// How Im gonna get the Thread Id of the current calling Window in
// PresentHook?

if (processThread.Id == CurrentCallingWindowThreadId)
{
Yes, thats the Child Window Handle Im looking for!
}
//————————————————————————————

return true;

}, IntPtr.Zero);
}
}

Sebastian
SEPTEMBER 27, 2015 AT 12:40 AM

I could solve my problem. Yeah!

For people in need who needs the Handle to/of the current calling Window
in PresentHook in DXHookD3D10.cs or DXHookD3D11.cs too, just use in
the PresentHook function this code:

This is already written there:


——————————————————————-
SlimDX.DXGI.SwapChain swapChain =
SlimDX.DXGI.SwapChain.FromPointer(swapChainPtr);
——————————————————————-

And add this below:


———————————————————————-
windowOverride = swapChain.Description.OutputHandle;
———————————————————————-

Have a nice coding!

Sebastian

Daniel
OCTOBER 9, 2015 AT 3:32 PM

Hello Justin,

i’m also working with your code and startet to develop a HUD overlay for a
FlightSimulator (DCS) who is running in Oculus Rift in extended mode. I draw a
overlay to the backbuffer and it worked fine (check video on youtube). Since
Oculus swaped to Direct driver mode in version 0.7, i can still draw the overlay, but
it was just displayed on the mirrored picture in a window not in the oculus rift.

Question: do you have an idea how to get the texture for left and right eye who is
displayed in oculus rift and how to draw a overlay there?

Here you can see how it looks in extended mode with the old oculus runtime <0.7.
http://youtu.be/MEEaXmRm7Vg

Thank you for any hint…

Daniel
OCTOBER 9, 2015 AT 3:37 PM

oh i forgot, thanks for your wonderful work, it helped me a lot to digin to this
project i just startet. By the way, the project (JHMCS for DCS) is just a work-
around to have the possibility to read some flight datas, because the gauges are
so small an bad to read inside the rift.
Thanks again for your great work!

 Justin Stenning
OCTOBER 9, 2015 AT 4:28 PM
Hi Daniel, glad you have found this helpful.

I haven’t played with Oculus – I would love to but unfortunately it is a little


lower down the priority list, anyway keep in mind I have zero experience with
their API. I took a very briefly look at the Oculus API and think you would be
able to hook into the ovr_CreateSwapTextureSetD3D11 (or something similar)
to gain access to the textures needed (Rendering to the Oculus ). With access to
each texture you should be able to then do your rendering to each eye.

Your project looks interesting – good luck! Let me know when it is up and run-
ning and you have a location I can point to.

Btw if anybody has a spare Oculus they want to unload give me a PM 😛

Sebastian
OCTOBER 17, 2015 AT 8:59 PM

Hi Justin!

I’m kinda lost when it comes to D10/D11 image streaming via Thread,
BackgroundWorker, DoWork or ThreadPool.QueueUserWorkItem in
DXHookD3D10.cs/DXHookD3D11.cs in PresentHook. No matter which one of
those (thread, bw or threadpool) I use, I get in Visual Studio either

– Unhandled Exception or
– Access Violation Exception or
– SlimDX Device was removed (in Debug.WriteLine)

after some time or right away and the game crashes! Without Threading it works
fine, but the game lags (as your comment in code says “delay in the rendering pipe-
line”).
Also the images in my app from the game change colors and look distorted after
some time.

I think it has something to do with object relocation or disposal through the


Garbage Collector, because the Access Violation is here in PresentHook:

ThreadPool.QueueUserWorkItem(delegate
{
using (MemoryStream ms = new MemoryStream())
{

// ACCESS VIOLATION HERE WITH textureDest:


Texture2D.ToStream(textureDest, ImageFileFormat.Bmp, ms);
//—

ms.Position = 0;

SendResponse(ms, requestId);
}
textureDest.Dispose();
textureDest = null;
});

Any ideas how to solve this Access Violation Exception?

Thanx in advance!

Cheers,

Sebastian

 Justin Stenning
OCTOBER 18, 2015 AT 6:32 PM

Hi Sebastian, I would make sure you have tried with the latest version on GitHub
that uses SharpDX, the SlimDX version is quite old now.

Sebastian
OCTOBER 20, 2015 AT 8:17 PM

Hi Justin!
Thanx. I’ve tried it with both SlimDX and SharpDX. Further tests showed me
that it is NOT the variable Texture2D textureDest but just the function
Texture2D.toStream(…) itself (only when called from a
Thread/Task/ThreadPool/BackgroundWorker) which causes the Access
Violation. Any further ideas how to solve this?

 Justin Stenning
OCTOBER 23, 2015 AT 4:41 PM

The device lost error occurs if the window is resized (or fullscreen is
brought to foreground etc).

I’ve changed the approach a little for D3D11 in the latest code on GitHub,
where it now uses a shared texture. Can you confirm you are using latest ex-
ample it has changed A LOT since it used SlimDX.
Sebastian
OCTOBER 24, 2015 AT 8:25 AM

Yup, I’ve tried DX10 (DX11 only with SlimDX) with SlimDX, SharpDX 242
and SharpDX 263. I’ve seen the new D11 Class. It has a new function
EnsureResources and KeyMutex etc. But I did not try that yet with D11,
because I think, when I solve the problem with D10, it will work also with
D11 automatically. So I focus on D10 for now.

I have to say, that your original project with with Load Test and the 100
Images or more works (but if I click a 2nd (or more) time after it finished,
the game lags – but no Exceptions at all) but if I change the Request call to
my custom one (cuz the Request mechanism is a bit different) then the
above described errors occur (just with threads). Maybe you could give
me some hints here what to consider. (I investigated it already, but I don’t
see anything wrong there.)

I do not resize the game window while I stream those bitmaps (I resized it
just once at the very beginning and it stays with that Width and Height all
the time (and your Load Test works without any errors too)).
I also don’t use fullscreen, but I do bring the game window to front just
once for hooking.

Sebastian
OCTOBER 25, 2015 AT 1:35 AM

Ok Justin. I know now why your app “TestScreenshot” (with SharpDX 242 & 263)
did not crash the game and mine did. It is because of the GUI-Logs. In my app I
have no Logs at all.
So I commented out/removed in your app in class DXHookD3D10.cs (SharpDX
242 & 263) all the Logs (“this.DebugMessage…”) and it crashed the game right
away (just few images were streamed of course) at
“Texture2D.ToStream(textureDest, ImageFileFormat.Bmp, ms);” with an Access
Violation after clicking on “Load Test”. Also those few streamed images got dis-
torted and changed colors too like in my app. I checked it with my Laptop (inte-
grated graphic card) and desktop (not integrated graphic card) and on both it
crashed. Would be interesting if that happens also on your computer. Can you test
it and let me know?

To prove that more I added also GUI-Logs for showing in my app window and it
took some long time till the game finally crashed (it was not right away like before).
So it is not about how I make the Frame Request, it is about the timing and the
Threadpool, because the Logs slow down the Frame-Requests process.
And here is what I figured out with the help of the Logs: when the line
“Texture2D.ToStream(textureDest, ImageFileFormat.Bmp, ms);” is called at the
same time when “SwapChain swapChain =
(SharpDX.DXGI.SwapChain)swapChainPtr;” is called, the game crashes with
Access Violation.

I have some ideas and if they solve that I’ll let you know what I did.
If you have a work around too, please let me know. Thank you.

Cheers,

Sebastian

Sebastian
NOVEMBER 1, 2015 AT 2:58 AM

Hi Justin!

I’ve tested your App (with SharpDX 263 and uncommented Debugs) with D11 and
it works fine! No game crash. Thats why I added the function “EnsureResources”
and the Locks from DXHookD3D11.cs to DXHookD3D10.cs but I get an exception
in EnsureResources in

“_resolvedRT = ToDispose(new Texture2D(device, new Texture2DDescription()…”:

“SharpDX.SharpDXException: HRESULT: [0x80070057] : Invalid Arguments …


SharpDX.Direct3D10.Device.CreateTexture2D(…)…”

I guess it has something to do with “OptionFlags =


ResourceOptionFlags.SharedKeyedmutex” but I would like to know where and
why exactly.

So I enabled in VS “Native Code Debugging” and in DirectX SDK “Force On” and
added my app to the list but still cannot see any output in VS.

Is there something I’m missing? How do you debug DirectX? Can’t find anything
helpful on the net…

Cheers,

Sebastian

Luis Mesas
NOVEMBER 3, 2015 AT 10:21 AM

Hi I got an error after that texture creation when trying to get the shared
handler:

Debug: DXHookD3D11: PresentHook: Exeception:


SharpDX.SharpDXException: SharpDX.SharpDXException: HRESULT:
[0x80070057], Module: [General], ApiCode: [E_INVALIDARG/Invalid
Arguments], Message: The parameter is incorrect.
at SharpDX.Result.CheckError()
at SharpDX.Direct3D11.Device.OpenSharedResource(IntPtr hResource, Guid
returnedInterface, IntPtr& resourceOut)
at SharpDX.Direct3D11.Device.OpenSharedResource[T](IntPtr resourceHan-
dle)
at Capture.Hook.DXHookD3D11.EnsureResources(Device device,
Texture2DDescription description, Rectangle captureRegion,
ScreenshotRequest request) in
C:\Projects\Direct3DHook\Capture\Hook\DXHookD3D11.cs

Hook injection works correctly, as I can see the FPS overlay.

(I’m on Windows 10 and working with a DX11 32 bits game)

Reading the docs of SharpDX, it suggets to use Resource1.CreateSharedHandle


to create a sharedhandle instead of recovering it using GetSharedHandle but I
cannot find a way to get the resource as a Resource1 class instead of a Resource
class.

Any tips on where to follow?

 Justin Stenning
NOVEMBER 17, 2015 AT 11:25 AM

Hi Luis, you could try using QueryInterface on the Resource instance, other-
wise it will be related to how it is being created to begin with.

Mike
NOVEMBER 29, 2015 AT 11:17 PM

Justin,

Hoping you can help… I get this error when sporadically when the client closes. It’s
for a 64-bit DX11 game:
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.InvalidOperationException
Stack:
at SharpDX.ComObject.SharpDX.IUnknown.Release()
at SharpDX.Direct3D11.DeviceChild.Dispose(Boolean)
at SharpDX.DisposeBase.CheckAndDispose(Boolean)
at SharpDX.DisposeCollector.DisposeAndClear()
at SharpDX.DisposeCollector.Dispose(Boolean)
at SharpDX.DisposeBase.Finalize()

Any suggestions for this error? I appreciate any insight you can provide.

 Justin Stenning
DECEMBER 5, 2015 AT 12:13 PM

Looks like an error while cleaning up some resources, can you confirm if this is
happening while disposing of the DX11 hook?

Perhaps try using a try..catch in your dispose?

Mike
DECEMBER 11, 2015 AT 8:06 PM

Justin, yes, this error occurs when I call this line:


“_captureProcess.CaptureInterface.Disconnect();”
on a DX11 hook.

Michael
DECEMBER 10, 2015 AT 7:20 AM

I’m attempting to modify the program to inject an off-screen rendered CEFSharp


window. But to include CEF sharp I need to configure the project to build for
x86/x64 as it doesn’t support AnyCPU according to
https://github.com/cefsharp/CefSharp/wiki/Trouble-Shooting

When I do this however I get an error: “STATUS_INVALID_PARAMETER_4: The


given 32-Bit library does not exist! (Code: 2)”

When calling RemoteHooking.Inject

The path to the Capture.dll seems fine though and the dll is there. Thoughts?
 Justin Stenning
DECEMBER 11, 2015 AT 6:02 PM

Is the EasyLoad32.dll also there? RemoteHooking.Inject starts by injecting


EasyLoad32/64.dll which in turn loads your target assembly.

Michael Ellis
DECEMBER 12, 2015 AT 4:34 AM

I must have been missing it, I made sure to copy all of the dlls again and it
worked this time. However the code I am trying to run depends on CefSharp
and now the DirectX host app I am hooking is complaining it can’t find one of
the CefSharp dll files. I tried placing them in the same directory as the DirectX
application, as well as registering them with the gacutil. It’s still unable to find
the dll files though. I read the tutorial pdf for easyhook but my impression was
I just needed to register the dlls in the GAC or place them in the same direc-
tory as the app I was hooking…

 Justin Stenning
DECEMBER 24, 2015 AT 3:42 PM

Best to not use the GAC as it just complicates the whole process. Ensure
EasyHook is completely unregistered from the GAC, and see how you go
then.

Avi S.
DECEMBER 24, 2015 AT 3:10 PM

Hi Justin,

I would very much appreciate your help with some hardships I face trying to run
TestScreenshot.

I’ve been trying to run the most recent version on Windows 10 out of VS2012 and
had no luck so far. The build goes smoothly, and It looks like all Dlls are in the bin
folder, including the newly generated capture Dll. I try to hook to two very basic
demo applications, both in the same bin folder. One is based on DirectX 10 and the
other on DirectX 11.

Once I run the application and call for “Inject”, in either Win32 or X64 mode, the
application waits for 5 seconds and then breaks on the InjectionFailedException
exception, with the inner exception stating “Unable to wait for service application
due to timeout”. (As I see, this comes from the WOW64Bypass class in EasyHook).
The thing that gets more strange is that when I try to reproduce this now, a day af-
ter, the inner exception shows now “STATUS_INVALID_PARAMETER_4: The given
32-Bit library does not exist! (Code: 2)”.

I am pretty stuck at the moment and not sure how to get this to run.

Thank you very much,


Avi S.

 Justin Stenning
DECEMBER 24, 2015 AT 3:41 PM

Make sure you have all the 32- and 64-bit versions of the EasyHook binaries
(e.g. easyhook32/64svc.exe and easyhook32/64.dll and easyload32/64.dll)

Avi Steiner
JANUARY 1, 2016 AT 4:27 PM

Hi Justin, thanks a lot! One of the Dlls was indeed missing, and some paths
were incorrect. After fixing this – I got the example to work on Windows 10!
Thank you very much!

While I was trying to run the project on Windows 7 as well, I managed to eas-
ily hook to a simple DirectX10 window, but when I tried to hook to a simple
DirectX11 window, the target window became unresponsive, followed by the
message “Display Driver AMD stopped responding, and was successfully re-
stored”. The project itself kept running, and threw debug messages. The prob-
lem seems to be related to SharpDX and calling “draw” to the overlayEngine,
but I am still not very familiar with the code.

Please let me know if you can help. I really appreciate it.

Have a great year to come!


Avi

This is the debug dump. The first long debug message was thrown 8 times in
the activation:
Debug: DXHookD3D11: PresentHook: Exeception:
SharpDX.SharpDXException: SharpDX.SharpDXException: HRESULT:
[0x887A0005], Module: [SharpDX.DXGI], ApiCode:
[DXGI_ERROR_DEVICE_REMOVED/DeviceRemoved], Message: Unknown
at SharpDX.Result.CheckError()
at SharpDX.Direct3D11.DeviceContext.FinishCommandListInternal(Bool re-
storeDeferredContextState, CommandList& commandListOut)
at SharpDX.Direct3D11.DeviceContext.FinishCommandList(Boolean re-
storeState)
at Capture.Hook.DX11.DXOverlayEngine.End() in c:\Cyndr\Direct3DHook-
master\Capture\Hook\DX11\DXOverlayEngine.cs:line 168
at Capture.Hook.DX11.DXOverlayEngine.Draw() in c:\Cyndr\Direct3DHook-
master\Capture\Hook\DX11\DXOverlayEngine.cs:line 161
at Capture.Hook.DXHookD3D11.PresentHook(IntPtr swapChainPtr, Int32
syncInterval, PresentFlags flags) in c:\Cyndr\Direct3DHook-
master\Capture\Hook\DXHookD3D11.cs:line 538
Debug: DXHookD3D11: Hook: Device created
Debug: DXHookD3D11: Hook: Before device creation
Debug: DXHookD3D11: Hook: Begin
Debug: Autodetect found Direct3D 11
Information: Remote process is a 32-bit process.
Information: Injected into process Id:73912.

 Justin Stenning
JANUARY 1, 2016 AT 4:32 PM

“DeviceRemoved” sounds like the device was disposed of. Are you using the
latest version of the source located in the GitHub repository? Does it work
fine elsewhere or with other DirectX11 apps on your Win7 machine? Also it
might be easier to log it on the GitHub repository as an issue.

Avi Steiner
JANUARY 13, 2016 AT 9:53 AM

Hi Justin, Thank you for always responding right away, and sorry it took
me a while to write you back.

I am using the latest version of the GitHub source. It works fine when I
use it with DirectX9, 10, and 11 on Windows 10. It also works fine when I
use it with DirectX 9 and 10 on Windows 7.

It is only DirectX 11 on Windows 7 that causes the crash.

I will post the issue up.

Thank you very much!


Avi

Avi Steiner
MAY 9, 2016 AT 5:18 PM

Hi Justin,

Hope you’ve been doing well.

I’ll really appreciate if you can please help me with this problem I’ve been strug-
gling with:

I am using Direct3DHook DLL (Capture.DLL) and building a wrapper DLL around it


in order to be able to use the Direct3DHook from C++ code. I am using a public ref
class for this, and the whole thing works fine on Visual Studios 2015.

The calls sequence goes like: (My Main C++ function)–>(My


Capture_DLL_Wrapper functions)–>(Capture.DLL HookIntoProcess function)…
Then EasyHook DLLs are called. This works very nicely on Visual Studios 2015
and I can see the FPS for hooked games.

Now, I am trying to get this same sequence to work in QT Creator. I added mes-
sage boxes along the calls path and I can see that the call to
“RemoteHooking.Inject” crashes from within EasyHook with the error:
“STATUS_INTERNAL_ERROR Unknown error in injected c++ completion 15”.

I added the following definitions to the .pro file:


CONFIG(debug, debug|release) {
LIBS += “C:/Users/Andrei/Desktop/Projects/QT/build-
sAvi/debug/CaptureDllWrapper.lib”
LIBS += “C:/Users/Andrei/Desktop/Projects/QT/build-
sAvi/debug/CaptureDllWrapper.dll”
LIBS += “C:/Users/Andrei/Desktop/Projects/QT/build-sAvi/debug/capture.dll”
LIBS += “C:/Users/Andrei/Desktop/Projects/QT/build-sAvi/debug/EasyHook.dll”
LIBS += “C:/Users/Andrei/Desktop/Projects/QT/build-
sAvi/debug/EasyHook32.dll”
LIBS += “C:/Users/Andrei/Desktop/Projects/QT/build-
sAvi/debug/EasyLoad32.lib”
}

I made sure that all files are in the folder, but still.. I get this exception.

I’ll really appreciate if you can give me some advise, as I’ve been struggling with
the “dll hell” for quite a while. Thank you very much!
Avi

Ahmet
SEPTEMBER 29, 2016 AT 11:30 PM

Hi, Sometimes I get this error.

What’s the problem? can you help me?

DXHookD3D9: SharpDX.SharpDXException: HRESULT: [0x8876086C], Module:


[SharpDX.Direct3D9], ApiCode: [D3DERR_INVALIDCALL/InvalidCall], Message:
Unknown
at SharpDX.Result.CheckError()

at SharpDX.Direct3D9.Device.StretchRectangle(Surface sourceSurfaceRef,
Nullable`1 sourceRectRef, Surface destSurfaceRef, Nullable`1 destRectRef,
TextureFilter filter)
at SharpDX.Direct3D9.Device.StretchRectangle(Surface sourceSurfaceRef,
Surface destSurfaceRef, TextureFilter filter)

at Capture.Hook.DXHookD3D9.DoCaptureRenderTarget(Device device, String


hook) in C:\Users\DelphiCoder\Desktop\Direct3DHook-
master\Capture\Hook\DXHookD3D9.cs:line 341

 Justin Stenning
DECEMBER 2, 2016 AT 12:30 PM

Hi Ahmet, this could be some incompatibility with the two surface descriptions.
The error is happening internally to Direct3D, if this is your 3D app then you
could use a debug DirectX device and get some additional details, otherwise it
may require you to investigate the details of the two surfaces, and the capabili-
ties of the Direct3D device that was created by the target application.

Riley
DECEMBER 24, 2016 AT 10:18 AM

Hey Justin, Thanks for the awesome work, this is awesome!

I was having trouble getting it to work with UWP Apps. Notably Microsoft’s
Solitaire Collection. Have you run into this at all?

(I forget the exact error right now but while I was here I figured I would mention
it!)

 Justin Stenning
JANUARY 8, 2017 AT 6:10 PM
Hi Riley, it is very difficult to inject into UWP Apps. Not impossible but you may
need to locate your DLLs within a system directory in order to do so
(LoadLibrary does not support paths within UWP).

I haven’t looked into this much further than some precursory reading.

Good luck and feel free to comment back here as to how you go.

andy
JANUARY 23, 2017 AT 2:25 AM

So, I just quickly downloaded the Git repo and compiled and ran… no overlays are
happening on D3D9 application. I’m trying to follow your code, but am having a
tough time. I set breakpoints where i think it should be setting the overlay, but
they never get hit.

Does the current version just not call the methods that apply the overlay?

andy
JANUARY 23, 2017 AT 3:00 AM

never mind.. it’s getting hit, it’s just not showing the overlay. I am assuming it has
to do with that I am running Win7x64 from Parallels on a mac. I’ll have to try on
a different computer.

Jimmy
FEBRUARY 19, 2018 AT 3:34 PM

Have you got any clue what was going wrong? I am having a similar problem
for a D3D9 game. Screen capture works fine, no error messages, but no over-
lays at all. I am running Win10x64 from BootCamp on a macbook.

Pingback: C# – Screen capture with Direct3D 9 API Hooks - Spazzarama

Anny
MARCH 16, 2018 AT 8:50 AM

Is it possible to use this project to display winform/wpf as overlay to the fullscreen


game?
If yes, how? Can someone explain me process of displaying winform elements as
overlay? I understand the concept of drawing text, but how can I display real form?
 Justin Stenning
MARCH 16, 2018 AT 12:41 PM

You could render the form to an image and then display that upon the overlay.

Oleg
SEPTEMBER 5, 2018 AT 7:38 AM

Is it possible to bring a polygon into the game using this project?


Please show an example.

 Justin Stenning
SEPTEMBER 5, 2018 AT 10:30 PM

Yes. Take a look at the Direct3DHook project on GitHub and the overlay engine.
It is only rendering quads but it should give you a starting point.

Oleg
SEPTEMBER 15, 2018 AT 10:09 PM

How to do it? Can you give an example?

Oleg
SEPTEMBER 16, 2018 AT 10:57 AM

The game crashes, after frequent use of


_captureProcess.CaptureInterface.DrawOverlayInGame (new
Capture.Hook.Common.Overlay {}).
How can I call DrawOverlayInGame once and change the text?

Tuyen Doan
DECEMBER 27, 2018 AT 8:22 PM

Hi,
Thanks for the great product.
I run demo success on windows 10 pro 64.
But on windows 10 enterprise 64, it had error “STATUS_NO_MEMORY: Unable to
allocate memory in target process. (Code: 5)”. i use process game fifa online 4. Can
you check help me cause the error ?
Thanks .

 Justin Stenning
DECEMBER 27, 2018 AT 8:34 PM
Hi Tuyen, this error is typical when the target employs memory protection tech-
niques like you would find in anticheat libraries. In this instance you may need to
try different injection techniques, or you can use the Desktop Duplication API to
record (but even this can also be blocked).

Tuyen Doan
DECEMBER 28, 2018 AT 11:59 AM

Thanks Justin Stenning,


I will try some solutions.

Mike
JANUARY 19, 2019 AT 12:43 AM

Justin, my overlay disappears when I ALT+TAB with a DX11 game.

I start in full screen mode, and both the hook and on-screen display are working
beautifully.

However, when I ALT+TAB to the Windows 10 desktop, and then return back to
the full screen game, ResizeTargetHook gets called, but then PresentHook ap-
pears to not be getting called again after that, and my overlay disappears.

Any Idea/suggestion?

Please let me know, and best regards!

Arnold
APRIL 8, 2019 AT 7:00 PM

I recently tried this tool on Battlefield V and a few days later I received a message
from EA that my game got permanently blocked for breaking the rules in online
play.

After emailing EA they refused to lift the permanent block because I have violated
their user agreement which was most likely caused by this tool because I had no
other fps tools running at the time.

I just wanted to share this warning that you need to be very careful when you use
this tool in online games that have an anti-cheat system in place, especially in EA /
Origin games because they are unforgiving and their support is not listening to
reason.
 Justin Stenning
APRIL 8, 2019 AT 7:15 PM

Thanks for sharing your experiences Arnold. This is actually the first instance of
a ban due to simple overlays using this example that has been reported to me.

Fizz Areh
JANUARY 10, 2021 AT 1:42 AM

Hi, is it neccessary for my IOvelayElement implementations to be Serializable?


Because without this attribute they dont work. It limits me hardly (because I cant
use any non-serializable objects as fields) and dont get the reason behind that…

 Justin Stenning
FEBRUARY 10, 2021 AT 8:12 AM

I think due to the way we send IOverlayElement over IPC this is required
(MarshalByRef).

GrigLog
JANUARY 10, 2021 AT 4:27 AM

And also im for some reason unable to call methods from my main thread, f.e. i
have a main class with a field List elements = new List(); (those elements are later
passed into captureProcess.CaptureInterface.DrawOverlayInGame(new Overlay
{Elements = elements, Hidden = false}); ). And if I write
MainClass.elements.remove(this) in the code of my element implementation, it
simply not happens. And I cant call any methods from MainClass, if I do this, over-
lay is just not working (neither my elements, not FramesPerSecond).

 Justin Stenning
FEBRUARY 10, 2021 AT 8:29 AM

So the element is sent to the overlay, and then within there it tries to call back to
your host app? Sounds like IPC setup issues. .NET remoting will be removed
from EasyHook in a future version in favour of whatever user supplied approach
you wish to use (e.g. signalR, pipes, https, whatever).

This site uses Akismet to reduce spam. Learn how your comment data is processed.

You might also like