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:
- 100% C# implementation
- Added Direct3D 10 and 11 support
- Capturing multi-sampled/anti-aliased images (for 10 & 11) is supported
- Re-organised code making it easier to support multiple D3D versions
- Implemented a new and improved test bed application
- Provided example overlays for D3D 9 and 10
- Improved debug messaging from Target application to Host (mostly removed when compiled with “Release” configuration)
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:
protected IntPtr[] GetVTblAddresses(IntPtr pointer, int numberOfMethods)
{
List vtblAddresses = new List();
IntPtr vTable = Marshal.ReadIntPtr(pointer);
for (int i = 0; i < numberOfMethods; i++)
vtblAddresses.Add(Marshal.ReadIntPtr(vTable, i * IntPtr.Size)); // using IntPtr.Size allows us to support both 32 and 64-bit processes
return vtblAddresses.ToArray();
}
Adding Direct3D 10 and 11 Support
Direct3D 10 and Direct3D 11 have a completely different rendering pipeline compared 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 impact to the frame rate.
We are also able to copy only the region of the backbuffer that we are actually interested 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 resolve a multi-sampled texture down into a single sample for copying into a Bitmap.
D3D 10 code:
// 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 a 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 SlimDX.DXGI.SampleDescription(1, 0), // Ensure single sample
BindFlags = BindFlags.None,
MipLevels = 1,
OptionFlags = texture.Description.OptionFlags
});
// Resolve into textureResolved
texture.Device.ResolveSubresource(texture, 0, textureResolved, 0, texture.Description.Format);
}
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.
#region Example: Draw Overlay (after screenshot so we don't capture overlay as well)
#region Draw fading lines based on last screencapture request
if (_lastRequestTime != null && _lineVectors != null)
{
TimeSpan timeSinceRequest = DateTime.Now - _lastRequestTime.Value;
if (timeSinceRequest.TotalMilliseconds < 1000.0)
{
using (Line line = new Line(device))
{
_lineAlpha = (float)((1000.0 - timeSinceRequest.TotalMilliseconds) / 1000.0); // This is our fade out
line.Antialias = true;
line.Width = 1.0f;
line.Begin();
line.Draw(_lineVectors, new SlimDX.Color4(_lineAlpha, 0.5f, 0.5f, 1.0f));
line.End();
}
}
else
{
_lineVectors = null;
}
}
#endregion
#region Draw frame rate
using (SlimDX.Direct3D9.Font font = new SlimDX.Direct3D9.Font(device, new System.Drawing.Font("Times New Roman", 16.0f)))
{
if (_lastFrame != null)
{
font.DrawString(null, String.Format("{0:N1} fps", (1000.0 / (DateTime.Now - _lastFrame.Value).TotalMilliseconds)), 100, 100, System.Drawing.Color.Red);
}
_lastFrame = DateTime.Now;
}
#endregion
#endregion
The D3D 10 example simply displays the current date and time:
#region Example: Draw overlay (after screenshot so we don't capture overlay as well)
using (Texture2D texture = Texture2D.FromSwapChain(swapChain, 0))
{
if (_lastFrame != null)
{
FontDescription fd = new SlimDX.Direct3D10.FontDescription()
{
Height = 16,
FaceName = "Times New Roman",
IsItalic = false,
Width = 0,
MipLevels = 1,
CharacterSet = SlimDX.Direct3D10.FontCharacterSet.Default,
Precision = SlimDX.Direct3D10.FontPrecision.Default,
Quality = SlimDX.Direct3D10.FontQuality.Antialiased,
PitchAndFamily = FontPitchAndFamily.Default | FontPitchAndFamily.DontCare
};
using (Font font = new Font(texture.Device, fd))
{
DrawText(font, new Vector2(100, 100), String.Format("{0}", DateTime.Now), new Color4(System.Drawing.Color.Red));
}
}
_lastFrame = DateTime.Now;
}
#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
- 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)
- No example overlay for Direct3D 11 yet
- If you try to inject / capture using the wrong Direct3D version you could crash your host or target application
- 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 response ~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 response ~70-80ms
- Total time to request and retrieve a capture ~150-200ms
Examples
Direct3D 9: SDK Sample Blobs
Direct3D 10: SDK Sample CubeMapGS
Direct3D 11: SDK Sample SubD11
Download
You can download the updated sample here
It’s also recommended you read the previous post






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?
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. http://www.youtube.com/watch?v=1lLgUqGjDBk
Not sure when I will get to it due to current busyness tho.
Cheers,
J
Hell,
I’d very interested in desktop capture using this method as well. I’m investigating low-latency desktop capture like this – lots of exciting possibilities…
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?
Hi Michael,
Yes I have been able to hook Present. Can you post the code you are using including method signature for Present?
Does it crash when trying to hook, or when the hooked method is called?
Cheers,
J
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.
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
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!
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 directory), and run without having to install anything other than the EasyHook assembly to the GAC. Otherwise you can spend quite a bit of time debugging 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 contact page and subsequently email through a project or something.
Cheers,
J
Hi Michael,
Try the following:
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] delegate int Direct3D9Device_PresentDelegate(IntPtr device, ref RECT sourceRect, ref RECT destRect, IntPtr destWindowOverride, IntPtr pRgnData); int PresentHook(IntPtr devicePtr, ref RECT sourceRect, ref RECT destRect, IntPtr destWindowOverride, IntPtr pRgnData) { using (Device device = Device.FromPointer(devicePtr)) { //this.DebugMessage("PresentHook"); using (Region region = Region.FromHrgn(pRgnData)) { return device.Present(Rectangle.FromLTRB(sourceRect.left, sourceRect.top, sourceRect.right, sourceRect.bottom), Rectangle.FromLTRB(destRect.left, destRect.top, destRect.right, destRect.bottom), destWindowOverride, region).Code; } } }Cheers,
J
Hey Justin, that code doesn’t work for me. How is your RECT struc?
I did make it work. Dunno what was the problem. I’m using Int32 in the RECT struct.
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.
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
Yes, I’ve used Direct3D 9.
My D3D Hook in c++ works fine with Wow.
Mybe we can write in icq?
376916619
I’ve compiled the project with Visual studio 2010.
Maybe it dont work with vs 2010 ?
I use VS 2010 as well.
After chatting with Justin, we have found the problem.
You must type the process name without extensions.
So not Wow.exe but Wow.
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.
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 sometimes 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
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
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
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
i run this program in two conditions .one is win 7 ,in this condition the program works fine and i can run directx sdk samples in Direct3D10.another condition 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
Hi Chen,
Windows XP only supports up to Direct3D 9. To use D3D 10 or above you must have Vista or later.
Cheers,
J
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
Hi Chen, I’m not really sure what is happening here, I can’t remember getting 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
hi justin,now the progarm can work now,i install the related softwares again.so it can work.thanks for guiding
Glad to hear it and good luck!
Cheers,
J
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
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
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 successfully, however I never seen the captured screen images yet.
Thanks.
It appears in the dialog box itself.
Play with the different DirectX versions, and if that still doesn’t get you anywhere you will be able to remotely debug the injected process and add breakpoints 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
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 surface it works fine, but when it is playing this movie a on a right, second screen (secondary-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
Try specifying the coordinates for the capture with this in mind, does it then work correctly?
Cheers,
J
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 consideration 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.
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 between 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 impressed. Respect bro!
Thanks once again!
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
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 window sized incorrectly for the image aspect ratio the black would appear elsewhere 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
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.
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
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 screenshot test bed and it should capture fine for you.
Good luck!
J
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.ComPointer, 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.
My guess is that the error is actually around the creation of the temporary device 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 tracing and be able to see the actual errors that are occurring under the hood.
Cheers,
J
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 reason 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!
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
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 happens 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 software easier to use and manage
…and to bring a user totally new dimension of a movie view in his own home cinema. 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 extra 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
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 similar), 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
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 bitmap 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
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.
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/IMPORTANT_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
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
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 requirements 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 platform 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 channels 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 important, 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 created 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 diagram.
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 enter 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 expected 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 previous 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 blinkings, 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 advanced 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!
Hey Silas,
Although we haven’t yet gone to the level of detail you have for the various 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 implement that one. We actually are using a stream to USB serial so any hardware 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
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
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,
….
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.
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 application, 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
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
If I remove the Present() hook, then other hooks work pretty well. I’ll try to debug it today. Thank you very much!
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
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.
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
I add “3704:DXHookD3D9: Insert Present Hook” in Hook() method.
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.
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 foreground no matter what after hooking.
Were you experiencing the same thing? Is there any way to address this?
Thanks in advance.
Hi Alex,
Yes I have experienced this, and had found a way around it by changing foreground 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
I have a problem when i try to build it : “ResGen.exe” exited with code 2
can anybody help me?
Not sure.. sounds like the kind of error you get when converting the solution file to a new VS version.
Yes, but how can i fix it?
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();
}
I can’t make it work with Day of Defeat Source at full screen. No snapshot is captured.
Any idea how can I debug it?
I’ve already found the answer here at the comments.
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
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 creating it on every EndScene call?
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
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!
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
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.
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
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
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 programming 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
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 transparency 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 concepts of the program ;]]]
Thanks again for your time ;]
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 overlay doesn’t disappear.
Do you have a solution or does anyone have the same problem?
Thanks
Martin
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 attempting 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
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
Thank you for sharing this code. Very tricky stuff and I haven’t come across anything 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?
Hi mouser,
Yes, I do this in my local version now. Here is a snippet of what I do (you will notice I no longer pass the directx version from the host application).
public void Run( RemoteHooking.IContext InContext, String channelName) { // NOTE: We are now already running within the target process try { _interface.OnDebugMessage(RemoteHooking.GetCurrentProcessId(), "DLL Injection succeeded"); bool isX64Process = RemoteHooking.IsX64Process(RemoteHooking.GetCurrentProcessId()); _interface.OnDebugMessage(RemoteHooking.GetCurrentProcessId(), "64-bit Process: " + isX64Process.ToString()); IntPtr d3D9Loaded = IntPtr.Zero; IntPtr d3D10Loaded = IntPtr.Zero; IntPtr d3D10_1Loaded = IntPtr.Zero; IntPtr d3D11Loaded = IntPtr.Zero; IntPtr d3D11_1Loaded = IntPtr.Zero; int delayTime = 100; int retryCount = 0; while (d3D9Loaded == IntPtr.Zero && d3D10Loaded == IntPtr.Zero && d3D11Loaded == IntPtr.Zero) { retryCount++; d3D9Loaded = GetModuleHandle("d3d9.dll"); d3D10Loaded = GetModuleHandle("d3d10.dll"); d3D10_1Loaded = GetModuleHandle("d3d10_1.dll"); d3D11Loaded = GetModuleHandle("d3d11.dll"); d3D11_1Loaded = GetModuleHandle("d3d11_1.dll"); Thread.Sleep(delayTime); if (retryCount * delayTime > 5000) { _interface.OnDebugMessage(RemoteHooking.GetCurrentProcessId(), "Unsupported Direct3DVersion, or Direct3D DLL not loaded within 5 seconds."); return; } } Direct3DVersion version = Direct3DVersion.Unknown; if (d3D9Loaded != IntPtr.Zero) { version = Direct3DVersion.Direct3D9; } else if (d3D10Loaded != IntPtr.Zero) { version = Direct3DVersion.Direct3D10; } else if (d3D10_1Loaded != IntPtr.Zero) { version = Direct3DVersion.Direct3D10_1; } else if (d3D11Loaded != IntPtr.Zero) { version = Direct3DVersion.Direct3D11; } else if (d3D11_1Loaded != IntPtr.Zero) { version = Direct3DVersion.Direct3D11_1; } switch (version) { case Direct3DVersion.Direct3D9: _directXHook = new DXHookD3D9(_interface); break; case Direct3DVersion.Direct3D10: _directXHook = new DXHookD3D10(_interface); break; //case Direct3DVersion.Direct3D10_1: // _directXHook = new DXHookD3D10_1(_interface); // return; case Direct3DVersion.Direct3D11: _directXHook = new DXHookD3D11(_interface); break; //case Direct3DVersion.Direct3D11_1: // _directXHook = new DXHookD3D11_1(_interface); // return; default: _interface.OnDebugMessage(RemoteHooking.GetCurrentProcessId(), "Unsupported Direct3DVersion"); return; }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 directx modules got loaded — is no longer need. your solution looks better. thanks for sharing that.
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.
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
Thanks Justin! Looking forward to any updates.
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 display 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 registration 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 working 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.
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 directory 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 directory 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 injection 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
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 attempting this, or am I in the wrong neck of the woods?
Hi Devon,
Yes, this example code will help you along the way. The only part not covered is displaying the captured image as an overlay, but everything up to the capture of it is covered.
Cheers,
J
Thanks for the quick reply. One question though, when you mention permanently 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
Yeah I use the gacutil.exe. I haven’t used the method you linked, but that would probably suffice as well.
Cheers,
J
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.