2

Is it possible to render the desktop into a screen shot when using a full screen 3D-application (such as a game)? Or does windows close the rendering engine while the game is running?

I am looking for ways to render the desktop into a texture in my game. Can RDP like protocols be a solution?

Edit: To clarify, is there any deep level api mechanism to force rendering into another buffer such as when screen shots are made. Doesn't matter if it is only windows 7 or Windows 8/9.

NeutronCode
  • 365
  • 2
  • 13
  • We're talking "Unity" as in the game engine? If so, the correct tag is [unity3d]. – Bart Aug 26 '14 at 07:48
  • @Bart Thank you, yes. Not very related to the game engine but I thought Id tag it if somehow it mattered. – NeutronCode Aug 26 '14 at 09:18
  • So you're asking if you can still render the desktop view (in a texture) when the game is running in fullscreen? My first guess is "not possible" but I have not enough info to back that up with. P.s. if Unity is not really relevant, remove the tag. If you're looking for a solution that works with Unity however, just leave it in place. – Bart Aug 26 '14 at 09:25
  • @Bart yes, I understand the normal screen shot routines won't work. But maybe there is a way in the winapi to force a redraw into another invisible buffer (not the screen). Unity might be relevant in matters of how it is rendering. For example in windowed mode it might be possible by hiding the game window, forcing a redraw to another buffer and then continue it. – NeutronCode Aug 26 '14 at 09:34
  • try taking the screenshot of the desktop before the app enters fullscreen mode – CodeSmile Sep 05 '14 at 13:04

1 Answers1

6

You can get a screenshot by calling the PrintWindow Win32 API function on the hWnd of the desktop window. I tried this on Windows 7 and Windows 8.1, it worked even when another application was running (VLC Player) on full screen, so there's a chance it will work with games as well. This will only get you the image of the desktop without the taskbar, but none of the other visible running applications will be shown on it. If you need those as well then you need to get their HWND as well (e.g. by enumerating all the running processes and getting their window handle) and then use the same method.

using System;
using System.Drawing; // add reference to the System.Drawing.dll
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;

namespace DesktopScreenshot
{
  class Program
  {
    static void Main(string[] args)
    {
        // get the desktop window handle without the task bar
        // if you only use GetDesktopWindow() as the handle then you get and empty image
        IntPtr desktopHwnd = FindWindowEx(GetDesktopWindow(), IntPtr.Zero, "Progman", "Program Manager");

        // get the desktop dimensions
        // if you don't get the correct values then set it manually
        var rect = new Rectangle();
        GetWindowRect(desktopHwnd, ref rect);

        // saving the screenshot to a bitmap
        var bmp = new Bitmap(rect.Width, rect.Height);
        Graphics memoryGraphics = Graphics.FromImage(bmp);
        IntPtr dc = memoryGraphics.GetHdc();
        PrintWindow(desktopHwnd, dc, 0);
        memoryGraphics.ReleaseHdc(dc);

        // and now you can use it as you like
        // let's just save it to the desktop folder as a png file
        string desktopDir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
        string screenshotPath = Path.Combine(desktopDir, "desktop.png");
        bmp.Save(screenshotPath, ImageFormat.Png);
    }

    [DllImport("User32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool PrintWindow(IntPtr hwnd, IntPtr hdc, uint nFlags);

    [DllImport("user32.dll")]
    static extern bool GetWindowRect(IntPtr handle, ref Rectangle rect);

    [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
    static extern IntPtr GetDesktopWindow();

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle); 
  }
}
Bedford
  • 1,136
  • 2
  • 12
  • 36