none
Capture contents of current window RRS feed

  • Question

  • I need to be able to capture the contents of a current window as a bitmap about two times a second from a windows forms window and display the picture in a WPF window.

    Its a temporary fix for a COM object I am using that isn't playing well with my WPF app, but I need the visual data from it.

    My plan for now is to manipulate the control and capture the control's screen output and display it in a WPF picture frame.

    How would I go about capturing the inside contents of a window? Minus the window frame?
    Friday, July 18, 2008 3:19 PM

Answers

  • Since the Control.DrawToBitmap() includes the frame and titlebar when called from a Form instance I've included a variant that just makes a copy of the client portion of a Form.
    This little code snippet uses the SendMessage win API to send a WM_PRINT message that copies the forms visual content. The same functionality is utilized in the built in DrawToBitmap(), but includs the PRF_NONCLIENT flag which includes the titlebar and frame in the copy.
    Simply copy the code to the form that you want to be able to take snapshots of. If you cannot modify the form's code you can easily modify the function so that is takes a window handle of the Form instead.

            private const int WM_PRINT = 0x317;  
            private const int PRF_NON_CLIENT = 0x02;  
            private const int PRF_CLIENT = 0x04;  
            private const int PRF_ERASEBKGND = 0x08;  
            private const int PRF_CHILDREN = 0x10;  
     
            [DllImport("USER32.DLL")]  
            private static extern int SendMessage(HandleRef hWnd, int Msg, IntPtr wParam, int lParam);  
     
            public Image DrawToBitmap()  
            {  
                Bitmap image = new Bitmap(this.ClientSize.Width, this.ClientSize.Height,   
                    System.Drawing.Imaging.PixelFormat.Format32bppArgb);  
                  
                using (Graphics graphics = Graphics.FromImage(image))  
                {  
                    IntPtr hDC = graphics.GetHdc();  
                    SendMessage(new HandleRef(thisthis.Handle), WM_PRINT, hDC, PRF_CLIENT | PRF_CHILDREN | PRF_ERASEBKGND);  
                    graphics.ReleaseHdc(hDC);  
                }  
                return image;  
            } 

    /Calle
    Sunday, July 20, 2008 8:57 PM

All replies

  • Since the Control.DrawToBitmap() includes the frame and titlebar when called from a Form instance I've included a variant that just makes a copy of the client portion of a Form.
    This little code snippet uses the SendMessage win API to send a WM_PRINT message that copies the forms visual content. The same functionality is utilized in the built in DrawToBitmap(), but includs the PRF_NONCLIENT flag which includes the titlebar and frame in the copy.
    Simply copy the code to the form that you want to be able to take snapshots of. If you cannot modify the form's code you can easily modify the function so that is takes a window handle of the Form instead.

            private const int WM_PRINT = 0x317;  
            private const int PRF_NON_CLIENT = 0x02;  
            private const int PRF_CLIENT = 0x04;  
            private const int PRF_ERASEBKGND = 0x08;  
            private const int PRF_CHILDREN = 0x10;  
     
            [DllImport("USER32.DLL")]  
            private static extern int SendMessage(HandleRef hWnd, int Msg, IntPtr wParam, int lParam);  
     
            public Image DrawToBitmap()  
            {  
                Bitmap image = new Bitmap(this.ClientSize.Width, this.ClientSize.Height,   
                    System.Drawing.Imaging.PixelFormat.Format32bppArgb);  
                  
                using (Graphics graphics = Graphics.FromImage(image))  
                {  
                    IntPtr hDC = graphics.GetHdc();  
                    SendMessage(new HandleRef(thisthis.Handle), WM_PRINT, hDC, PRF_CLIENT | PRF_CHILDREN | PRF_ERASEBKGND);  
                    graphics.ReleaseHdc(hDC);  
                }  
                return image;  
            } 

    /Calle
    Sunday, July 20, 2008 8:57 PM
  • Hope it works, very few ActiveX controls implement WM_PRINT properly, if at all.  Graphics.CopyFromScreen() is unattractive, even if it didn't have the .NET 2.0 SP1 / V3.5 handle leak bug.  WPF has some WF interop capabilities, post in the WPF forum if necessary.
    Hans Passant.
    Sunday, July 20, 2008 9:27 PM
    Moderator
  • Thank you, Calle - much appreciated.
    Monday, July 21, 2008 3:26 PM
  • Great example, but I am not able to get child windows such as a drop down list box in WebBrowser control to show up in screenshot.  Do you know how I can get these child windows into the screenshot?

    Thanks in advance,

    Robert
    Thursday, March 19, 2009 5:04 PM
  • Can we simulate just a keyboard command "Alt+PrintScreen"...
    And then Clipboard.GetImage();

    Best regards, Sergiu
    Thursday, March 19, 2009 6:00 PM