2016-06-20 7 views
0

Я пытаюсь захватить только определенное окно на рабочем столе, но я получаю смешанное изображение, часть окна и части рабочего стола.Захват экрана окна с помощью дескриптора

Что мне не хватает?

Вот мой код:

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); 
+0

Crystal Ball говорит, что вы забыли [объявить свое приложение dpiAware] (http://stackoverflow.com/a/13228495/17034). –

ответ

3

Я думаю, что проблема в вашем коде эта линия:

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; 
} 
+0

Спасибо, это намного лучший метод. – Jack

+0

. Я быстро отвечу на ваш ответ, так как мне позволено снова подняться ... слишком много upvotes сегодня haha – Jack

1

Я на улучшение ответа PixelZerg, который не включает в себя необходимость использования и внешние ссылки ...

Чтобы использовать этот код, просто создать экземпляр класса ScreenCapture и передать хэндл C# Окно, сформированное Winforms, в процедуру GetScreenshot. Это возвращает объект растрового изображения. Для того, чтобы написать, что в файл JPG, передать объект растрового изображения методом WriteBitmapToFile:

Добавить, используя заявление, которое ссылается на свой класс ScreenCapture:

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); 
     } 
    } 
}