C# – Screen capture with Direct3D

After finally installing Vista Home Premium at home, I found that a C# utility I had created for capturing a region of the screen suddenly stopped working reliably for windowed Direct3D applications.


Update: 2010-06-21: Applied fix as pointed out within the comments by digitalutopia1 (lines 71-74)

Update: 2010-03-29: An example of hooking the Direct3D API directly in C#: http://spazzarama.com/2010/03/29/screen-capture-with-direct3d-api-hooks/

Note: If you are on Vista you may like to check this instead.

My code was previously using the GDI32 BitBlt method (see http://www.pinvoke.net/default.aspx/gdi32/BitBlt.html) which worked perfectly on Windows XP but was having intermittent issues with capturing windowed Direct3D applications on Windows Vista.

I took a quick look around, and decided that the most reliable approach would be to try and capture the image using the Direct3D API instead.

I am a DirectX novice, so this took a fair amount of cruising around forums and articles (the GameDev.net forums prooved to be a treasure trove of information). The gist of it was that I would need to capture the image by using the Direct3D devices front buffer.

Finding C# examples was a little difficult, and the Managed DirectX libraries were not an option as they are not being maintained past .NET 1.1. I then stumbled across “SlimDX” which provides a managed wrapper around DirectX 9 and 10. The original idea was posted here SlimDX — A Prototype MDX Replacement Library and now has an official website here SlimDX homepage.

I could now easily implement my screen capture code, and after only a few minor false starts around getting the initialisation properties correct, it was smooth sailing and required only a small amount of code to implement.

Here is a complete example extracted from my application (it requires a reference to the “SlimDX assembly”).

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;

namespace Spazzarama.ScreenCapture
{
    public static class Direct3DCapture
    {
        private static SlimDX.Direct3D9.Direct3D _direct3D9 = new SlimDX.Direct3D9.Direct3D();
        private static Dictionary<IntPtr, SlimDX.Direct3D9.Device> _direct3DDeviceCache = new Dictionary<IntPtr, SlimDX.Direct3D9.Device>();

        /// <summary>
        /// Capture the entire client area of a window
        /// </summary>
        /// <param name="hWnd"></param>
        /// <returns></returns>
        public static Bitmap CaptureWindow(IntPtr hWnd)
        {
            return CaptureRegionDirect3D(hWnd, NativeMethods.GetAbsoluteClientRect(hWnd));
        }

        /// <summary>
        /// Capture a region of the screen using Direct3D
        /// </summary>
        /// <param name="handle">The handle of a window</param>
        /// <param name="region">The region to capture (in screen coordinates)</param>
        /// <returns>A bitmap containing the captured region, this should be disposed of appropriately when finished with it</returns>
        public static Bitmap CaptureRegionDirect3D(IntPtr handle, Rectangle region)
        {
            IntPtr hWnd = handle;
            Bitmap bitmap = null;

            // We are only supporting the primary display adapter for Direct3D mode
            SlimDX.Direct3D9.AdapterInformation adapterInfo = _direct3D9.Adapters.DefaultAdapter;
            SlimDX.Direct3D9.Device device;

            #region Get Direct3D Device
            // Retrieve the existing Direct3D device if we already created one for the given handle
            if (_direct3DDeviceCache.ContainsKey(hWnd))
            {
                device = _direct3DDeviceCache[hWnd];
            }
            // We need to create a new device
            else
            {
                // Setup the device creation parameters
                SlimDX.Direct3D9.PresentParameters parameters = new SlimDX.Direct3D9.PresentParameters();
                parameters.BackBufferFormat = adapterInfo.CurrentDisplayMode.Format;
                Rectangle clientRect = NativeMethods.GetAbsoluteClientRect(hWnd);
                parameters.BackBufferHeight = clientRect.Height;
                parameters.BackBufferWidth = clientRect.Width;
                parameters.Multisample = SlimDX.Direct3D9.MultisampleType.None;
                parameters.SwapEffect = SlimDX.Direct3D9.SwapEffect.Discard;
                parameters.DeviceWindowHandle = hWnd;
                parameters.PresentationInterval = SlimDX.Direct3D9.PresentInterval.Default;
                parameters.FullScreenRefreshRateInHertz = 0;

                // Create the Direct3D device
                device = new SlimDX.Direct3D9.Device(_direct3D9, adapterInfo.Adapter, SlimDX.Direct3D9.DeviceType.Hardware, hWnd, SlimDX.Direct3D9.CreateFlags.SoftwareVertexProcessing, parameters);
                _direct3DDeviceCache.Add(hWnd, device);
            }
            #endregion

            // Capture the screen and copy the region into a Bitmap
            using (SlimDX.Direct3D9.Surface surface = SlimDX.Direct3D9.Surface.CreateOffscreenPlain(device, adapterInfo.CurrentDisplayMode.Width, adapterInfo.CurrentDisplayMode.Height, SlimDX.Direct3D9.Format.A8R8G8B8, SlimDX.Direct3D9.Pool.SystemMemory))
            {
                device.GetFrontBufferData(0, surface);

                // Update: thanks digitalutopia1 for pointing out that SlimDX have fixed a bug
                // where they previously expected a RECT type structure for their Rectangle
                bitmap = new Bitmap(SlimDX.Direct3D9.Surface.ToStream(surface, SlimDX.Direct3D9.ImageFileFormat.Bmp, new Rectangle(region.Left, region.Top, region.Width, region.Height)));
                // Previous SlimDX bug workaround: new Rectangle(region.Left, region.Top, region.Right, region.Bottom)));

            }

            return bitmap;
        }
    }

    #region Native Win32 Interop
    /// <summary>
    /// The RECT structure defines the coordinates of the upper-left and lower-right corners of a rectangle.
    /// </summary>
    [Serializable, StructLayout(LayoutKind.Sequential)]
    internal struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;

        public RECT(int left, int top, int right, int bottom)
        {
            this.Left = left;
            this.Top = top;
            this.Right = right;
            this.Bottom = bottom;
        }

        public Rectangle AsRectangle
        {
            get
            {
                return new Rectangle(this.Left, this.Top, this.Right - this.Left, this.Bottom - this.Top);
            }
        }

        public static RECT FromXYWH(int x, int y, int width, int height)
        {
            return new RECT(x, y, x + width, y + height);
        }

        public static RECT FromRectangle(Rectangle rect)
        {
            return new RECT(rect.Left, rect.Top, rect.Right, rect.Bottom);
        }
    }

    [System.Security.SuppressUnmanagedCodeSecurity()]
    internal sealed class NativeMethods
    {
        [DllImport("user32.dll")]
        internal static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

        /// <summary>
        /// Get a windows client rectangle in a .NET structure
        /// </summary>
        /// <param name="hwnd">The window handle to look up</param>
        /// <returns>The rectangle</returns>
        internal static Rectangle GetClientRect(IntPtr hwnd)
        {
            RECT rect = new RECT();
            GetClientRect(hwnd, out rect);
            return rect.AsRectangle;
        }

        /// <summary>
        /// Get a windows rectangle in a .NET structure
        /// </summary>
        /// <param name="hwnd">The window handle to look up</param>
        /// <returns>The rectangle</returns>
        internal static Rectangle GetWindowRect(IntPtr hwnd)
        {
            RECT rect = new RECT();
            GetWindowRect(hwnd, out rect);
            return rect.AsRectangle;
        }

        internal static Rectangle GetAbsoluteClientRect(IntPtr hWnd)
        {
            Rectangle windowRect = NativeMethods.GetWindowRect(hWnd);
            Rectangle clientRect = NativeMethods.GetClientRect(hWnd);

            // This gives us the width of the left, right and bottom chrome - we can then determine the top height
            int chromeWidth = (int)((windowRect.Width - clientRect.Width) / 2);

            return new Rectangle(new Point(windowRect.X + chromeWidth, windowRect.Y + (windowRect.Height - clientRect.Height - chromeWidth)), clientRect.Size);
        }
    }
    #endregion
}

Note: before working with DirectX I strongly suggest having the DirectX SDK installed, know how to enable DirectX debug dll’s and logging, and have DebugView handy (see the debugging tutorial linked in resources below). WARNING! remember to turn off the debug dll’s and logging when finished, otherwise the next time you try to play your favourite Direct3D game it will crawl along at a snail pace (took me two days before I realised what was wrong – doh!).

Note 2: to capture images in full screen Direct3D applications requires the Direct3D device to be in cooperative mode. The only way to achieve this if the application doesn’t have cooperative mode set by default, is to implement a Direct3D hook which intercepts the API calls and changes the setting on the way through. As I was happy to continue in windowed mode I had no need to continue down that road – but it was an interesting read. I’m pretty sure that this is how applications like FRAPS would do it. These two pages should help you along if this is what you are after: GameDev.net: C++ Direct3D hooking sample, and Direct3d 9 hook v1.1

Resources:

  1. SlimDX – managed wrapper for DirectX 9/10
  2. http://www.gamedev.net – lots of info here
  3. http://directxcapture.wikidot.com/ – another managed wrapper for DirectX 9
  4. DirectX 9 Tutorials – Debug Info

61 thoughts on “C# – Screen capture with Direct3D”

  1. This is great, i just tried it out.

    One question. I am pretty new to D3D programming. I am using Vista and a Window’d application, and this works. But if i drag another window over the top of the window i am capturing from, that window is also captured.

    Pretty sure its related to Vista being D3D, but there probably is a way to get what i want. There has to be… since if i hover my mouse over the taskbar on the application i get a preview window that is unobstructed. know what i mean?

    Anyways let me know if anyone has a thought on this.

    Thanks,
    Bobby

  2. Hi, Justin!
    Sorry for my english.
    Thanks for great article. It works really fine, but i experience serious performance slowdowns, when capturing. Everything freezes for about 0.2 sec. My old BitBlt based program works fine, but it has no chance on Vista.

    I need to take a capture of desktop about 4 times per second, perform some simple calculations on that data and put results to some hardware. (one day it will be an Philips Ambilight clone).
    And all of this actions must be innoticeable to user.

    Can you give me some advice?

    1. Hey Lockie,

      I didn’t notice such a significant performance hit during my testing… Can you isolate where the time is being spent? E.g. is it the actual capture, or when you save the resulting bitmap somewhere?

      I’ll have to take a look at it again and do some more checks. In the meantime do you think the Vista DWM would help you out? I have a link to a good example in another post here. My app actually does a check and uses BitBlt still when on XP and uses the Direct3D method on Vista. I will probably be switching to using the DWM on Vista at some point also – when I do I’ll post a small self-contained example.

      Cheers,
      J

      1. I remember having some performance issues as well. The line that takes a while is:

        Sufrace.fromSurface()

        what worked much much better was

        Device.StretchRectangle()

        note that the parameters are switched for these two.

        Hope that helps.

      2. Lags happens in GetFrontBufferData(0, surface);
        Now i see lots of bad performance reports on this function. And since same thing in MSDN:
        http://msdn.microsoft.com/en-us/library/bb174388(VS.85).aspx
        Quote:”This function is very slow, by design, and should not be used in any performance-critical path.”

        It seems that the only way to increase performance is to use GetRenderTargetData() or GetBackBuffer(). But since this is my 1st DX application, i cannot adapt examples that i have to screen capturing. :(
        Here’s the one of them:
        http://www.mdxinfo.com/resources/screencapture.php

        Switching between BitBlt on XP and DWM on Vista it is a kind of worst case. Because i need fullscreen d3d applications as well. So it will be like XP->BitBlt, Vista->DWM, and Game->d3d. I hope there is some other way.

        PS.
        Quote from FRAPS changelog for Version 1.9С 23/12/2002:
        A few observations on the changes in DirectX 9 and how it relates to Fraps:
        The GOOD: DirectX9 adds a function GetRenderTargetData which is explicitly designed to copy the frame buffer data from the video card to system memory. This form of transfer has been very poorly supported in the past causing slow readback speeds. Hopefully all drivers will soon support GetRenderTargetData with DMA, resulting in fast video capture for everyone (not just Nvidia owners).
        The BAD: Capture performance with anti-aliasing (multisampling) enabled is atrocious. DirectX9 now prohibits you from accessing multisampled surfaces directly, with the only way to get the frame buffer data via the slow GetFrontBufferData function. The speed difference capturing video with one of the SDK samples:
        DX8 – 640x480x32 with 4xAA – 30 fps
        DX9 – 640x480x32 with 4xAA – 6 fps

        1. Hey Lockie,

          My captures were about 100-130ms (for the entire CaptureRegionDirect3D method) – not counting the first which is a little slower for the device creation etc. For my purposes this is fine as I am not creating video. The GetFrontBufferData call itself was between 50-70ms.

          I was able to get it running without errors using the GetRenderTarget / GetRenderTargetData – however my tests only returned black pixels in the result. This could be specific to my environment, not sure. The performance was between 10-30ms.

          The code was (note: the coordinates need to be client not screen so you will need to offset them):

          using (SlimDX.Direct3D9.Surface surface = device.GetRenderTarget(0))
          {
          using (SlimDX.Direct3D9.Surface surface2 = SlimDX.Direct3D9.Surface.CreateOffscreenPlain(device, surface.Description.Width, surface.Description.Height, surface.Description.Format, SlimDX.Direct3D9.Pool.SystemMemory))
          {
          device.GetRenderTargetData(surface, surface2);
          // You have to use client coordinates here
          bitmap = new Bitmap(SlimDX.Direct3D9.Surface.ToStream(surface2, SlimDX.Direct3D9.ImageFileFormat.Bmp, new Rectangle(region.Left, region.Top, region.Right, region.Bottom)));
          }
          }

          Hope this helps

          Cheers,
          J

          1. Hi Justin,

            I’m looking for a fast way to get a bitmap of a given layered window (using a window handle). The window is a semi-transparent WPF window, and the application is running under Windows XP (not Vista or 7, this is a strong requirement).

            .NET libraries (RenderTargetBitmap, etc.) are not fast enough by far.

            So, I was looking for some kind of fast capture function (~20-30ms) and I thought maybe DirectX could be a solution. Having no experience at all with DirectX, I tried a couple of things but nothing worked the way I expected :)

            The best I could came up was using your code. This is indeed quite fast (~25ms) but… it doesn’t work. All I get (saving the bitmap to a file to check), is some incoherent stuff with bits and pieces of my window randomly cut and laid out plus other stuff from somewhere else. When the transparent mode if off, it get something better : the proper capture but outdated (from a former execution). Very strange for a DirectX beginner ;)

            Any help would be greatly appreciated!

            Fabrice

          2. Hi Fabrice,

            Sounds like an interesting problem. I’ll forward an email in the next day or so requesting some more details and a screenshot to see if I can help you.

            An alternative to using Direct3D on Windows XP is to use the GDI32 BitBlt function. It has been quite some time since I’ve used the code, but I should have it lying around somewhere if you are interested in taking a look.

            Cheers,
            J

  3. Hey guys,

    when using GetFrontBufferData I get an exception, or black image, if i switch to fullscreen.

    when using GetRenderTargetData I always get an exception, even when using DeviceEx with it:

    D3DERR_INVALIDCALL: Invalid call (-2005530516)

    SlimDX.Direct3D9.Direct3D9Exception was unhandled
    Message=”D3DERR_INVALIDCALL: Invalid call (-2005530516)”
    Source=”SlimDX”
    StackTrace:
    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.GetRenderTargetData(Surface renderTarget, Surface destinationSurface)
    at GetPixelColorByCoordinatesDX(Int32 x, Int32 y) in Stuff.cs:line 139
    at check() in test.cs:line 56
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    at System.Threading.ThreadHelper.ThreadStart()
    InnerException:

    1. If the Direct3D device is not in “cooperative mode” you will not be able to capture anything in fullscreen.

      For the D3D error, install the DirectX SDK and enable debugging (see links at end of the post on a debug tutorial). This will tell you exactly what it is that is causing the issue (e.g. an unexpected parameter value, or wrong Surface dimensions etc…)

      Cheers,
      J

      1. Hey!

        Could you provide some information on how to hook into the DLL and set the device in “cooperative mode”? I have looked into the link you have provided, but don’t seem to understand them a whole lot.

        Thanks in advance!

        1. Hi,

          I haven’t performed any DLL hooking myself, since windowed mode was always acceptable for my needs.

          I might look into it further at some point but it will most probably be a fair way off. There are a number of C/C++ examples out there, and I think I compiled one successfully, but never actually used it to intercept the Direct3D device creation and force it to cooperative mode.

          Good luck, and I would be interested in any findings!

          Cheers,
          J

          1. I abandoned the idea for now. I did a silly workaround that works fine for me (I only need fullscreen shots while a certain game is running). What I did is use the print-screen of Windows and took the image from there. You may be surprised, but it is faster than GetFrontBufferData, so it is good enough for me.

  4. Hi!
    Finally, i decided to use this screen capturing method instead of BitBlt:

    public virtual Bitmap CapturePic()
    {
    Rectangle rc = SystemInformation.VirtualScreen;
    Bitmap memoryImage = new Bitmap(rc.Width, rc.Height, PixelFormat.Format32bppArgb);

    using (Graphics memoryGrahics = Graphics.FromImage(memoryImage))
    {
    memoryGrahics.CopyFromScreen(rc.X, rc.Y, 0, 0, rc.Size);
    }
    return memoryImage;
    }

    This one provides acceptable performance (31ms@1680×1050) under XP-2003 platform, and requires .NET 3.5 SP1(!). But, when i tried this code on Vista, i get noticeable slowdown (150-170ms), even with 3.5 SP1.

    Then i’ve looked on http://spazzarama.wordpress.com/2009/02/12/screen-capture-with-vista-dwm/
    But i can’t even compile those example, because of wrong version of SlimDX.

    So, Justin, could you please post some actually working code of VistaDWM capturing?

    And again, sorry for my english. :)

    1. Hey Lockie,

      I was able to compile that linked DWM example without any problems.

      However I am planning to do a small example that uses the Vista DWM approach, and with some holidays coming up I should get around to it within 2 or 3 weeks.

      Btw I used to use the CopyFromScreen method a while back (before using Vista) but had some HDC leaking issues – I guess those are corrected in 3.5 SP1?

      Cheers,
      J

      1. Thanks, Justin, I’ll wait for your example.
        HDC leaking was fixed in SP1 (that’s why i’ve downloaded it), and now CopyFromScreen() seems to work fine.

  5. Justin,

    I had been searching for a C# example to do screen capturing and this code is exactly what I was looking for. Thanks for blogging your code. This is extremely helpful.

    I was trying to build upon your code to create an API which will perform a video recording of the screen activities. So, I was trying to snapshot the full screen at regular intervals. Exactly after 100 snapshots, an ExternalException is thrown at line #71, when trying to create a new bitmap. A generic error occurred in GDI+. My guess is that somewhere a memory overflow has occurred. I am not sure exactly where it is. This is my first experience with DirectX and I do not have any knowledge to figure out what is happening. Kindly help me out in this.

    My screen resolution is 1680×1050.

    Thanks in advance.

    Balaji

    1. Hey Balaji,

      Without seeing your code I am guessing that it is that you are not calling Dispose on the bitmap that is returned to release the unmanaged resources.

      e.g.
      using (Bitmap myBitmap = CaptureWindow(myHWnd)) {
      // Use the bitmap here
      }

      or

      Bitmap myBitmap = CaptureWindow(myHWnd);
      // do stuff with myBitmap
      myBitmap.Dispose();

      Cheers,
      J

      1. Hey Justin,

        Thanks. I did not call Dispose on Bitmap as rightly pointed out by you. I was able to complete my screen video capture API. But, I was able to achieve a max of only 6-7 fps. This is due to the use of GetFrontBuffer() which is very slow. So, I had to look for other options for screen recording. Then I used WMEncoder for capturing.

        http://www.codeproject.com/KB/audio-video/CaptureScreenAsVideo.aspx?display=PrintAll&fid=129831&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2692180

        I got exactly what I wanted with very minimal effort.

        Thanks for your help Justin.

  6. Hey justin.
    Fisrt then all, this is a greate realese, thank you!

    I need help from you,
    I made this code using you’r class:

    Bitmap bitmap;
    IntPtr iptr = new IntPtr();
    bitmap = Direct3DCapture.CaptureWindow(iptr);

    bitmap.Save(“D://test2.jpg”);

    And after I compile it (when it open the dos window) it opens me a “Send / Don’t Send” Message box, and give an error in the dos window:
    Unhandled Exception: SlimDX.Direct3D9.Direct3D9Exception: D3DERR_INVALIDCALL: In
    valid call (-2005530516)
    at SlimDX.Result.Throw[T](Object dataKey, Object dataValue)
    at SlimDX.Result.Record[T](Int32 hr, Boolean failed, Object dataKey, Object d
    ataValue)
    at SlimDX.Direct3D9.Device..ctor(Direct3D direct3D, Int32 adapter, DeviceType
    deviceType, IntPtr controlHandle, CreateFlags createFlags, PresentParameters pr
    esentParameters)
    at PrintScreen.Direct3DCapture.CaptureRegionDirect3D(IntPtr handle, Rectangle
    region) in C:Documents and SettingsEladMy DocumentsVisual Studio 2008Proje
    ctsPrintScreenPrintScreenDirect3DCapture.cs:line 61
    at PrintScreen.PrintScreen.Main(String[] args) in C:Documents and SettingsE
    ladMy DocumentsVisual Studio 2008ProjectsPrintScreenPrintScreenProgram.cs:
    line 15

    Do you have any idea why?
    Thanks in additoion,
    Elad.

    1. Hi Elad,

      I think that you are not passing in a valid handle to the window you want to capture.

      You will need to do something more like the following:

      public class MainClass
      
          // Declare external functions.
          [DllImport("user32.dll")]
          private static extern IntPtr GetForegroundWindow();
      
          public static void Main() {
              // Obtain the handle of the current foreground window.
              IntPtr handle = GetForegroundWindow();
      
              Bitmap bitmap;
              bitmap = Direct3DCapture.CaptureWindow(handle);
      
              bitmap.Save(@"D:test2.jpg");
          }
      }
      

      Note: take a look at the other window finding methods in user32.dll for obtaining the handle (e.g. FindWindow: http://www.pinvoke.net/default.aspx/user32.FindWindow)

  7. Hi Jusin,
    while i’m using your code with out open anything its works find and printscreen half of my screen.

    while i’m open fullscreen game (like Counter Strike)
    its give me this error:
    D3DERR_DEVICELOST: Device lost (-2005530520)

    in line 62+63:
    device = new SlimDX.Direct3D9.Device(_direct3D9, adapterInfo.Adapter, SlimDX.Direct3D9.DeviceType.Hardware, hWnd, SlimDX.Direct3D9.CreateFlags.SoftwareVertexProcessing, parameters);

    1. Hey Gal,

      Currently it only works for windowed Direct3D applications (you pass in the hwnd of the window to capture), fullscreen isn’t an option without doing some DirectX API hooking (see http://www.codeplex.com/easyhook). I will not be looking into the fullscreen option for the time being, but would still be interested in any example someone has working.

      Cheers,
      J

    2. Hi Gal,

      Re: D3DERR_DEVICELOST – this error often occurs in DirectX when switching between Windowed and Fullscreen.

      It is probably necessary to reattach to the hwnd (assuming the app is in cooperative mode for fullscreen)

      Cheers,
      J

  8. Hey Justin – Thanks for you’r reply.
    Is there any reason that this code won’t support VISTA/Windows7?
    Because in XP it’s work fine – in VISTA/Windows7 it returns error. (Send/Don’tSend)

    1. Elad,

      I have a Vista version working (see the Vista DWM post), and I have a Windows 7 Virtual Machine setup that I will be working on over the next few weeks to get it working there.

      Cheers,
      J

  9. It appears that you’ve got a bug there with CaptureRegionDirect3D.

    You’ve got the wrong format for the rectangle. You’ve got:

    ….new Rectangle(region.Left, region.Top, region.Right, region.Bottom)));

    When the correct format should be:

    ….new Rectangle(region.Left, region.Top, region.Width, region.Height)));

    This way the bitmap returned will be the same size as the rectangle passed to the function.

    1. Thanks for pointing this out, it was originally this way to work around a bug in SlimDX where it was expecting the Rectangle structure to be the same as the native RECT structure. I did notice this was fixed in a more recent release of SlimDX but fixing this here slipped my mind.
      Thanks, J

  10. Does anyone know if this code can/should work in Windows 7? I just tried it and the line devEx.CreateTexture(…) in public DwmCapture(IntPtr hWnd) is giving a pTexture == 0.

    Not sure if this is a local problem or something with Windows 7.

  11. hi
    im new in directx and its my first sample!!
    i have this exception:
    “The type initializer for ‘screenshotdirectx.Class1’ threw an exception.”
    i dont install directx sdk in my system yet.
    whats my wrong?
    code:
    pictureBox1.Image= Class1.CaptureWindow(this.Handle);

    1. Where did you get Class1 from? Perhaps try with the static class in the blog post instead and see what happens?

      If I understand correctly, you are wanting to capture a hidden window, which will not work with the approach shown here, you would need to use the API hook example (which currently does require the SDK to be installed by the way), and I think only if it is a DirectX application.

      Cheers,
      J

      1. hi justin
        tnx.
        i fixed this problem.i had to install directx.
        and i need to use directx because that the win api like BitBlt or printwindow unable to capture hidden windows,
        tnx alot for your response and im realy sorry for my english!

  12. hi justin
    i have another question.i want to capture a minimized window and i used this code
    but i have this exception when i want to capture the a minimized window :
    D3DERR_INVALIDCALL: Invalid call (-2005530516)
    on this line(line 75):
    bitmap = new Bitmap(SlimDX.Direct3D9.Surface.ToStream(surface, SlimDX.Direct3D9.ImageFileFormat.Bmp, new Rectangle(region.Left, region.Top, region.Width, region.Height)));

  13. and one more thing,this class capture an image from everything that showed on desktop not from a special window that we handled to it!isnt it?
    for example if i say to capture from a minimized window it cant do!
    what should i do if i want to capture an image from a minimized window?

    1. My understanding is that you cannot capture from a minimized window, even a DirectX one, as the application actually stops generating the images for the window.

      This is the case with all the capture methods I have attempted to date.

      Regards,
      J

  14. im realy thank you for your help.because its very very important to me to capture the hidden or minimized window.
    i cant undrstand in this line:
    “” device = new SlimDX.Direct3D9.Device(_direct3D9, adapterInfo.Adapter, SlimDX.Direct3D9.DeviceType.Hardware, hWnd, SlimDX.Direct3D9.CreateFlags.SoftwareVertexProcessing, parameters);””
    whats usage of hwnd in this line???!!!!i want to say capture exactly from a form that handle by hwnd!!!!!
    tnx again.

      1. Hi Mahboob,

        I don’t think I understand what you are trying to do exactly. How about you send me an email via the contact page with more details and code examples and I can get back to you there rather than clutter up the comments here. Be sure to include an email address that works.

        Cheers,
        J

    1. You need to pass in the window handle (hwnd) of the window you wish to capture.

      If the form is within your application then:

      In WinForms this would be myForm.Handle and in WPF this would be something like: IntPtr windowHandle = new WindowInteropHelper(Application.Current.MainWindow).Handle;

      If the form is an external application you need to use the Win32 interop calls to retrieve the windows handle for the desired form (e.g. GetForegroundWindow / GetWindow / and so on).

  15. Hi everybody

    I really need to use this resource in order to capture the screen and generate an image. I’ve already tried others resoures which I’ve found in google, but nothing has worked to me.

    Using this above code, it works fine when I run the project in visual studio, but after publish in IIS 7 I get an error in the line 036:

    SlimDX.Direct3D9.AdapterInformation adapterInfo = _direct3D9.Adapters.DefaultAdapter;

    Error: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index

    Can somebody help me? I need it so much!!

    Hope somebody can…

    Regards

    Renato Tozzi
    From Brazil

    1. Hi Renato,

      You cannot capture the screen from within a IIS 7 worker process as they do not interact with a UI session, i.e. there is no adapter to retrieve in your example.

      You would instead need to have an application running within a desktop login session that your code running on the webserver on the same machine communicates with (via remoting or named pipes etc..). Although even then it would probably be easier to implement a simple TCP/HTTP server within your application and make your TCP/HTTP request straight to that.

      Cheers,
      J

  16. Hi, thank you for the code.

    I’m trying to video record a specific program (for example iexplore.exe).
    I am able to find the mainWindowHandle and pass it to parameters.DeviceWindowHandle but somehow it’s still recording the foreground and not the iexplore process. Any idea how to solve this?

    Thanks!

    1. Hi,

      You can try some of the other DirectX examples on this blog, but generally they only work with DirectX applications (the Vista example uses DWM and works for any window).

      Cheers,
      J

  17. Hi, special thanks for your awesome work OO.

    But i have à probleme :
    When i use
    Hwnd = FindWindow(“triuiScreen”, namePrivate);
    Bitmap image = Direct3DCapture.CaptureWindow(Hwnd);
    I have image of my game, it’s okay.

    But qhen i try
    Hwnd = FindWindow(“triuiScreen”, namePrivate);
    Rectangle region = new Rectangle(100, 100, 100, 100);
    Bitmap image = Direct3DCapture.CaptureRegionDirect3D(handle, region);

    I have a image but since coordinate of my screen, not of my game. You understand me ?

    Can somebody help me?

    PS : Im sorry for my english.

    thanks !!

      1. Thanks, but I’m still learning things. I have looked at yours ‘Direct3dHook’ at github. It was a truly amazing work. Before I find it I searched everywhere but no one had written a thing like that. So i’m using it and modifying things to understand, as i’m self-learning. So I wanted to know how did you really achieve it? I know it’s not a one day work but weeks/months. It’d be great if you could make some tutorial for the direct3dhook, from the beginning.

        Thanks

        1. Glad you find it useful, I am planning to write a tutorial for it, however I have a few other things I’m doing first (e.g. I want to capture as a video stream first and the like).

          Cheers,
          J

  18. Hello Justin,
    Thanks much for sharing this, works well and found useful in 2017. I also discovered Slimdx and Sharpdx today!
    In case if you still follow the comments here, I do have a question regarding capturing only the output of a specific window. Currently I can see (Windows 10) any window rendered in the specified rectangle region is getting captured. Do you think it is possible to capture only a specific window output?

    Best Regards,
    Rajeesh

    1. Might be better to look at GDI capture approach if normal windows. If Direct3D apps then you can look at the C# – Screen capture and Overlays for Direct3D 9, 10 and 11 post.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.