通过句柄捕获Window的屏幕

时间:2016-06-20 20:39:19

标签: c# windows screen-capture

我尝试仅捕获桌面中的特定窗口,但我得到的是混合图像,窗口和部分桌面区域的一部分。

我错过了什么?

这是我的代码:

RECT rect = new RECT();

if (!SetForegroundWindow(handle))
    throw new Win32Exception(Marshal.GetLastWin32Error());

if (!GetWindowRect(handle, out rect))
    throw new Win32Exception(Marshal.GetLastWin32Error());

Thread.Sleep(500);

Rectangle windowSize = rect.ToRectangle();
Bitmap target = new Bitmap(windowSize.Width, windowSize.Height);
using (Graphics g = Graphics.FromImage(target))
{
    g.CopyFromScreen(0, 0, 0, 0, new Size(windowSize.Width, windowSize.Height));
}

target.Save("foo.png", System.Drawing.Imaging.ImageFormat.Png);

2 个答案:

答案 0 :(得分:6)

我认为代码中存在的问题是这一行:

g.CopyFromScreen(0, 0, 0, 0, new Size(windowSize.Width, windowSize.Height));

应该是:

g.CopyFromScreen(windowSize.X, windowSize.Y, 0, 0, new Size(windowSize.Width, windowSize.Height));

以下是我个人用来获取特定窗口图像的方法 - 它可能会派上用场:

public Bitmap GetScreenshot()
{
    IntPtr hwnd = ihandle;//handle here

    RECT rc;
    Win32.GetWindowRect(new HandleRef(null, hwnd), out rc);

    Bitmap bmp = new Bitmap(rc.Right - rc.Left, rc.Bottom - rc.Top, PixelFormat.Format32bppArgb);
    Graphics gfxBmp = Graphics.FromImage(bmp);
    IntPtr hdcBitmap;
    try
    {
        hdcBitmap = gfxBmp.GetHdc();
    }
    catch
    {
        return null;
    }
    bool succeeded = Win32.PrintWindow(hwnd, hdcBitmap, 0);
    gfxBmp.ReleaseHdc(hdcBitmap);
    if (!succeeded)
    {
        gfxBmp.FillRectangle(new SolidBrush(Color.Gray), new Rectangle(Point.Empty, bmp.Size));
    }
    IntPtr hRgn = Win32.CreateRectRgn(0, 0, 0, 0);
    Win32.GetWindowRgn(hwnd, hRgn);
    Region region = Region.FromHrgn(hRgn);//err here once
    if (!region.IsEmpty(gfxBmp))
    {
        gfxBmp.ExcludeClip(region);
        gfxBmp.Clear(Color.Transparent);
    }
    gfxBmp.Dispose();
    return bmp;
 }

答案 1 :(得分:2)

我改进了PixelZerg的答案,其中没有包含必要的使用和外部参考......

要使用下面的代码,只需创建一个ScreenCapture类实例,并将C#Winforms生成的窗口的句柄传递给GetScreenshot例程。这将返回一个位图对象。要将其写入JPG文件,请将位图对象传递给WriteBitmapToFile方法:

添加一个引用ScreenCapture类的using语句:

using StackOverflow.Example.Utility;

现在实例化ScreenCapture并按如下所示使用它:

var sc = new ScreenCapture();
var bitmap = sc.GetScreenshot(parentContainer.Handle);
sc.WriteBitmapToFile("temp.jpg", bitmap);

以下是ScreenCapture类的完整,可编译的代码:

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

namespace StackOverflow.Example.Utility
{

    public class ScreenCapture
    {
        [DllImport("user32.dll")]
        static extern int GetWindowRgn(IntPtr hWnd, IntPtr hRgn);

        //Region Flags - The return value specifies the type of the region that the function obtains. It can be one of the following values.
        const int ERROR = 0;
        const int NULLREGION = 1;
        const int SIMPLEREGION = 2;
        const int COMPLEXREGION = 3;

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);

        [DllImport("gdi32.dll")]
        static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);

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

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left, Top, Right, Bottom;

            public RECT(int left, int top, int right, int bottom)
            {
                Left = left;
                Top = top;
                Right = right;
                Bottom = bottom;
            }

            public RECT(System.Drawing.Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom) { }

            public int X
            {
                get { return Left; }
                set { Right -= (Left - value); Left = value; }
            }

            public int Y
            {
                get { return Top; }
                set { Bottom -= (Top - value); Top = value; }
            }

            public int Height
            {
                get { return Bottom - Top; }
                set { Bottom = value + Top; }
            }

            public int Width
            {
                get { return Right - Left; }
                set { Right = value + Left; }
            }

            public System.Drawing.Point Location
            {
                get { return new System.Drawing.Point(Left, Top); }
                set { X = value.X; Y = value.Y; }
            }

            public System.Drawing.Size Size
            {
                get { return new System.Drawing.Size(Width, Height); }
                set { Width = value.Width; Height = value.Height; }
            }

            public static implicit operator System.Drawing.Rectangle(RECT r)
            {
                return new System.Drawing.Rectangle(r.Left, r.Top, r.Width, r.Height);
            }

            public static implicit operator RECT(System.Drawing.Rectangle r)
            {
                return new RECT(r);
            }

            public static bool operator ==(RECT r1, RECT r2)
            {
                return r1.Equals(r2);
            }

            public static bool operator !=(RECT r1, RECT r2)
            {
                return !r1.Equals(r2);
            }

            public bool Equals(RECT r)
            {
                return r.Left == Left && r.Top == Top && r.Right == Right && r.Bottom == Bottom;
            }

            public override bool Equals(object obj)
            {
                if (obj is RECT)
                    return Equals((RECT)obj);
                else if (obj is System.Drawing.Rectangle)
                    return Equals(new RECT((System.Drawing.Rectangle)obj));
                return false;
            }

            public override int GetHashCode()
            {
                return ((System.Drawing.Rectangle)this).GetHashCode();
            }

            public override string ToString()
            {
                return string.Format(System.Globalization.CultureInfo.CurrentCulture, "{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom);
            }
        }
        public Bitmap GetScreenshot(IntPtr ihandle)
        {
            IntPtr hwnd = ihandle;//handle here

            RECT rc;
            GetWindowRect(new HandleRef(null, hwnd), out rc);

            Bitmap bmp = new Bitmap(rc.Right - rc.Left, rc.Bottom - rc.Top, PixelFormat.Format32bppArgb);
            Graphics gfxBmp = Graphics.FromImage(bmp);
            IntPtr hdcBitmap;
            try
            {
                hdcBitmap = gfxBmp.GetHdc();
            }
            catch
            {
                return null;
            }
            bool succeeded = PrintWindow(hwnd, hdcBitmap, 0);
            gfxBmp.ReleaseHdc(hdcBitmap);
            if (!succeeded)
            {
                gfxBmp.FillRectangle(new SolidBrush(Color.Gray), new Rectangle(Point.Empty, bmp.Size));
            }
            IntPtr hRgn = CreateRectRgn(0, 0, 0, 0);
            GetWindowRgn(hwnd, hRgn);
            Region region = Region.FromHrgn(hRgn);//err here once
            if (!region.IsEmpty(gfxBmp))
            {
                gfxBmp.ExcludeClip(region);
                gfxBmp.Clear(Color.Transparent);
            }
            gfxBmp.Dispose();
            return bmp;
        }

        public void WriteBitmapToFile(string filename, Bitmap bitmap)
        {
            bitmap.Save(filename, ImageFormat.Jpeg);
        }
    }
}