I'm working with a system that has 4 outputs (monitors) with e.g. 1280x1024 pixels for each output. I need a screenshot of the whole desktop and all open applications on it.
I tried GetDesktopWindow()
(MSDN) but it doesn't work properly. Some forms don't shown on the captured picture.
Of course not.
The
GetDesktopWindow
function returns a handle to the desktop window. It doesn't have anything to do with capturing an image of that window.Besides, the desktop window is not the same thing as "the entire screen". It refers specifically to the desktop window. See this article for more information and what can go wrong when you abuse the handle returned by this function.
This is relatively simple to do in the .NET Framework using the
Graphics.CopyFromScreen
method. You don't even need to do any P/Invoke!The only trick in this case is making sure that you pass the appropriate dimensions. Since you have 4 monitors, passing only the dimensions of the primary screen won't work. You need to pass the dimensions of the entire virtual screen, which contains all of your monitors. Retrieve this by querying the
SystemInformation.VirtualScreen
property, which returns the bounds of the virtual screen. As the documentation indicates, this is the bounds of the entire desktop on a multiple monitor system.Sample code:
Edit:
Hmm, I didn't see a WPF tag on the question or mentioned anywhere in the body.
No matter, though. The code I posted works just fine in a WPF application, as long as you add the appropriate references and using declarations. You will need
System.Windows.Forms
andSystem.Drawing
. There might be a more WPF-esque way of doing this that doesn't require a dependency on these WinForms assemblies, but I wouldn't know what it is.It even works on another thread. There is nothing here that would require the UI thread.
Yes, I tested it. Here is my full test code: