Revuen Ben Dror
Revuen Ben Dror

Reputation: 237

How can i capture the screen without the Form?

This is a class i'm using to capture my screen and mouse cursour as screenshot. But i want to make somehow that if the Form is in the middle of the screen don't capture it captrue the screen and the area behind the Form but not the Form it self.

Even if the form is in the front and i click on buttons or change something in the Form while the application is running do not capture it just keep capture the screen the area behind the Form like the Form is not there.

using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

namespace ScreenShotDemo
{
    public class ScreenCapture
    {
        [StructLayout(LayoutKind.Sequential)]
        struct CURSORINFO
        {
            public Int32 cbSize;
            public Int32 flags;
            public IntPtr hCursor;
            public POINTAPI ptScreenPos;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct POINTAPI
        {
            public int x;
            public int y;
        }

        [DllImport("user32.dll")]
        static extern bool GetCursorInfo(out CURSORINFO pci);

        [DllImport("user32.dll")]
        static extern bool DrawIcon(IntPtr hDC, int X, int Y, IntPtr hIcon);

        const Int32 CURSOR_SHOWING = 0x00000001;

        public static Bitmap CaptureScreen(bool CaptureMouse)
        {
            Bitmap result = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);

            try
            {
                using (Graphics g = Graphics.FromImage(result))
                {
                    g.CopyFromScreen(0, 0, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);

                    if (CaptureMouse)
                    {
                        CURSORINFO pci;
                        pci.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(CURSORINFO));

                        if (GetCursorInfo(out pci))
                        {
                            if (pci.flags == CURSOR_SHOWING)
                            {
                                DrawIcon(g.GetHdc(), pci.ptScreenPos.x, pci.ptScreenPos.y, pci.hCursor);
                                g.ReleaseHdc();
                            }
                        }
                    }
                }
            }
            catch
            {
                result = null;
            }

            return result;
        }
    }

What i mean is that i will see the Form when it's running and i will be able to change things click buttons but the captured screenshot if i will edit it with Paint i will not see the Form .

This is in Form1 how i make the capture:

private void StartRecording_Click(object sender, EventArgs e)
        {
            timer1.Enabled = true;
        }

And timer1 tick event:

private void timer1_Tick(object sender, EventArgs e)
        {
            using (bitmap = (Bitmap)ScreenCapture.CaptureScreen(true))
            {
                ffmp.PushFrame(bitmap);
            }       
        }

This line make the actual capture: using (bitmap = (Bitmap)ScreenCapture.CaptureScreen(true))

Upvotes: 3

Views: 2223

Answers (2)

salluc 1
salluc 1

Reputation: 63

using System.Drawing.Imaging;
using System.Drawing;
using System.Runtime.InteropServices;

namespace Sshot
{
    internal class screenShot
    {
        [DllImport("user32.dll")]
        public static extern IntPtr GetDesktopWindow();
        [DllImport("user32.dll")]
        public static extern IntPtr GetWindowDC(IntPtr hWnd);
        [DllImport("gdi32.dll")]
        public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
        [DllImport("gdi32.dll")]
        public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
        [DllImport("gdi32.dll")]
        public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
        [DllImport("gdi32.dll")]
        public static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);
        [DllImport("gdi32.dll")]
        public static extern IntPtr DeleteObject(IntPtr hObject);
        [DllImport("user32.dll")]
        public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
        [DllImport("gdi32.dll")]
        public static extern bool DeleteDC(IntPtr hdc);
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }
        //https://learn.microsoft.com/en-us/windows/win32/gdi/ternary-raster-operations
        const int SRCCOPY = 0x00CC0020;
        static string CaptureScreenshot()
        {
            IntPtr hWnd = GetDesktopWindow();
            IntPtr hDC = GetWindowDC(hWnd);
            IntPtr hMemDC = CreateCompatibleDC(hDC);
            RECT rect;
            GetClientRect(hWnd, out rect);
            int width = rect.Right;
            int height = rect.Bottom;
            IntPtr hBitmap = CreateCompatibleBitmap(hDC, width, height);
            IntPtr hOld = SelectObject(hMemDC, hBitmap);
            BitBlt(hMemDC, 0, 0, width, height, hDC, 0, 0, SRCCOPY);
            Bitmap bmp = Image.FromHbitmap(hBitmap);
            SelectObject(hMemDC, hOld);
            DeleteObject(hBitmap);
            DeleteDC(hMemDC);
            ReleaseDC(hWnd, hDC);

            using (MemoryStream ms = new MemoryStream())
            {
                bmp.Save(ms, ImageFormat.Png);
                byte[] imageBytes = ms.ToArray();
                return Convert.ToBase64String(imageBytes);
            }
        }
    }
}

The code captures a screenshot of the entire desktop by using P/Invoke to call several Windows API functions. It begins by obtaining a handle to the desktop window and its device context, then creates a compatible device context and bitmap to store the screenshot. The BitBlt function is used to copy the pixel data from the desktop device context to the compatible device context. Once the screenshot is captured, it's saved as a bitmap image. Finally, the code releases all allocated resources to ensure there are no memory leaks.

Upvotes: -1

Aniket Inge
Aniket Inge

Reputation: 25723

Um.. Hide the form?

this.Visible = false; and THEN run the screenshot method.

Like this:

protected Bitmap TakeScreenshot(bool cursor)
{
   Bitmap bitmap;
   this.Visible = false;
   bitmap = CaptureScreen(cursor);
   this.Visible = true;
   return bitmap;
}

and use it in your code the way you wanted:

 private void timer1_Tick(object sender, EventArgs e)
 {
    using (bitmap = (Bitmap)ScreenCapture.TakeScreenshot(true))
    {
        ffmp.PushFrame(bitmap);
    }       
 }

Upvotes: 9

Related Questions