none
Capture screenshot of entire desktop - multiple monitors RRS feed

  • Question

  • Hi,

    I'm trying to capture a screenshot of the entire desktop. I have 3 monitors and the 3rd one is on different graphics card than the other two. When I use the following code, I only get a screenshot of the 2 monitors that are on the same graphics card and it does omit the 3rd one although VirtualScreen.Width/Height are correct:

            public static Bitmap CaptureDesktopImage()
            {
                var currentImage = new Bitmap(SystemInformation.VirtualScreen.Width, SystemInformation.VirtualScreen.Height);

                using (Graphics currentImageGraphic = Graphics.FromImage(currentImage))
                {
                    IntPtr currentImageHdc = IntPtr.Zero;
                    IntPtr desktopHdc = IntPtr.Zero;

                    try
                    {
                        currentImageHdc = currentImageGraphic.GetHdc();
                        if (currentImageHdc == IntPtr.Zero)
                        {
                            throw new Exception("Unable to get HDC for current image");
                        }

                        desktopHdc = GetDC(IntPtr.Zero);
                        if (desktopHdc == IntPtr.Zero)
                        {
                            throw new Exception("Unable to get desktop HDC : " + Marshal.GetLastWin32Error());
                        }
                        else
                        {
                            if (!BitBlt(currentImageHdc,
                                        0, 0,
                                        currentImage.Width,
                                        currentImage.Height,
                                        desktopHdc,
                                        0, 0,
                                        0x00CC0020))
                            {
                                throw new Exception("Error while calling BitBlt : " + Marshal.GetLastWin32Error());
                            }

                            return currentImage;
                        }
                    }
                    finally
                    {
                        if (currentImageHdc != IntPtr.Zero)
                        {
                            currentImageGraphic.ReleaseHdc();
                        }
                        if (desktopHdc != IntPtr.Zero)
                        {
                            ReleaseDC(IntPtr.Zero, desktopHdc);
                        }
                    }
                }
            }

    Any idea what might be going on here?

    Thanks,

    Tom
    Tuesday, July 29, 2008 2:11 PM

Answers

  • Yes, that's your problem.  Your 3rd screen will have negative coordinates if it is placed to the left of the main screen.  You can iterate all available screens with the Screen.AllScreens property:

          Rectangle bounds = new Rectangle();
          foreach (Screen scr in Screen.AllScreens) {
            bounds = Rectangle.Union(bounds, scr.Bounds);
          }


    Hans Passant.
    Wednesday, July 30, 2008 1:43 PM
    Moderator

All replies

  • Do you see the desktop background where the 3rd monitor is supposed to go?  You should also specify CAPTUREBLT so you'll blit layered windows as well (0x40000000).  I'd normally recommend Graphics.CopyFromScreen() but it is bugged right now.
    Hans Passant.
    Wednesday, July 30, 2008 2:50 AM
    Moderator
  • Hi,

    thanks for your reply.
    No, I don't see any empty space for the 3rd desktop background, however the dimensions in VirtualScreen are correct and account for all 3 monitors. I'm guessing it might have to do with the 3rd screen having a negative X offset.
    Any other ideas what I can do?

    Thanks,

    Tom
    Wednesday, July 30, 2008 1:24 PM
  • Yes, that's your problem.  Your 3rd screen will have negative coordinates if it is placed to the left of the main screen.  You can iterate all available screens with the Screen.AllScreens property:

          Rectangle bounds = new Rectangle();
          foreach (Screen scr in Screen.AllScreens) {
            bounds = Rectangle.Union(bounds, scr.Bounds);
          }


    Hans Passant.
    Wednesday, July 30, 2008 1:43 PM
    Moderator
  • Thanks, I adjusted the code, now it works fine:

            public static Bitmap CaptureDesktopImage()
            {
                Rectangle bounds = new Rectangle();
                foreach (Screen scr in Screen.AllScreens)
                    bounds = Rectangle.Union(bounds, scr.Bounds);

                var currentImage = new Bitmap(bounds.Width, bounds.Height);

                using (Graphics currentImageGraphic = Graphics.FromImage(currentImage))
                {
                    IntPtr currentImageHdc = IntPtr.Zero;
                    IntPtr desktopHdc = IntPtr.Zero;

                    try
                    {
                        currentImageHdc = currentImageGraphic.GetHdc();
                        if (currentImageHdc == IntPtr.Zero)
                        {
                            throw new Exception("Unable to get HDC for current image");
                        }

                        desktopHdc = GetDC(IntPtr.Zero);
                        if (desktopHdc == IntPtr.Zero)
                        {
                            throw new Exception("Unable to get desktop HDC : " + Marshal.GetLastWin32Error());
                        }
                        else
                        {
                            if (!BitBlt(currentImageHdc,
                                        0, 0,
                                        currentImage.Width,
                                        currentImage.Height,
                                        desktopHdc,
                                        bounds.X, 0,
                                        0x00CC0020))
                            {
                                throw new Exception("Error while calling BitBlt : " + Marshal.GetLastWin32Error());
                            }

                            return currentImage;
                        }
                    }
                    finally
                    {
                        if (currentImageHdc != IntPtr.Zero)
                        {
                            currentImageGraphic.ReleaseHdc();
                        }
                        if (desktopHdc != IntPtr.Zero)
                        {
                            ReleaseDC(IntPtr.Zero, desktopHdc);
                        }
                    }
                }
            }
    Wednesday, July 30, 2008 2:49 PM