对非顶端窗口截图

如何截取非前端窗体的截图

首先说一下PrintWindow这个API的使用

       public static Bitmap GetWindowCapture(IntPtr hWnd)
        {
            IntPtr hscrdc = GetWindowDC(hWnd);
            RECT windowRect = new RECT();
            GetWindowRect(hWnd, ref windowRect);
            int width = windowRect.right – windowRect.left;
            int height = windowRect.bottom – windowRect.top;

            IntPtr hbitmap = CreateCompatibleBitmap(hscrdc, width, height);
            IntPtr hmemdc = CreateCompatibleDC(hscrdc);
            SelectObject(hmemdc, hbitmap);
            PrintWindow(hWnd, hmemdc, 0);
            Bitmap bmp = Bitmap.FromHbitmap(hbitmap);
            DeleteDC(hscrdc);//删除用过的对象
            DeleteDC(hmemdc);//删除用过的对象
            return bmp;
        }

        [DllImport("user32.dll")]
        public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);

        [DllImport("gdi32.dll")]
        public static extern IntPtr CreateDC(
         string lpszDriver,         // driver name驱动名
         string lpszDevice,         // device name设备名
         string lpszOutput,         // not used; should be NULL
         IntPtr lpInitData   // optional printer data
         );
        [DllImport("gdi32.dll")]
        public static extern int BitBlt(
         IntPtr hdcDest, // handle to destination DC目标设备的句柄
         int nXDest,   // x-coord of destination upper-left corner目标对象的左上角的X坐标
         int nYDest,   // y-coord of destination upper-left corner目标对象的左上角的Y坐标
         int nWidth,   // width of destination rectangle目标对象的矩形宽度
         int nHeight, // height of destination rectangle目标对象的矩形长度
         IntPtr hdcSrc,   // handle to source DC源设备的句柄
         int nXSrc,    // x-coordinate of source upper-left corner源对象的左上角的X坐标
         int nYSrc,    // y-coordinate of source upper-left corner源对象的左上角的Y坐标
         UInt32 dwRop   // raster operation code光栅的操作值
         );

        [DllImport("gdi32.dll")]
        public static extern IntPtr CreateCompatibleDC(
         IntPtr hdc // handle to DC
         );

        [DllImport("gdi32.dll")]
        public static extern IntPtr CreateCompatibleBitmap(
         IntPtr hdc,         // handle to DC
         int nWidth,      // width of bitmap, in pixels
         int nHeight      // height of bitmap, in pixels
         );

        [DllImport("gdi32.dll")]
        public static extern IntPtr SelectObject(
         IntPtr hdc,           // handle to DC
         IntPtr hgdiobj    // handle to object
         );

        [DllImport("gdi32.dll")]
        public static extern int DeleteDC(
         IntPtr hdc           // handle to DC
         );

        [DllImport("user32.dll")]
        public static extern bool PrintWindow(
         IntPtr hwnd,                // Window to copy,Handle to the window that will be copied.
         IntPtr hdcBlt,              // HDC to print into,Handle to the device context.
         UInt32 nFlags               // Optional flags,Specifies the drawing options. It can be one of the following values.
         );

        [DllImport("user32.dll")]
        public static extern IntPtr GetWindowDC(
         IntPtr hwnd
         );

 

 

很遗憾,上面的确可以截取非前端窗体的截图,但是非GDI的程序是无法截图的比如DirectX

下面说一下BitBlt这个API的使用

 

    /// <summary>
    /// 提供全屏和指定窗口的截图 以及保存为文件的类
    /// </summary>
    public class ScreenCapture
    {
        /// <summary>
        /// 全屏截图 
        /// </summary>
        /// <returns></returns>
        public Image CaptureScreen()
        {
            return CaptureWindow(User32.GetDesktopWindow());
        }
        /// <summary>
        /// 指定窗口截图
        /// </summary>
        /// <param name="handle">窗口句柄. (在windows应用程序中, 从Handle属性获得)</param>
        /// <returns></returns>
        public Image CaptureWindow(IntPtr handle)
        {
            IntPtr hdcSrc = User32.GetWindowDC(handle);
            User32.RECT windowRect = new User32.RECT();
            User32.GetWindowRect(handle, ref windowRect);
            int width = windowRect.right – windowRect.left;
            int height = windowRect.bottom – windowRect.top;
            IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
            IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, width, height);
            IntPtr hOld = GDI32.SelectObject(hdcDest, hBitmap);
            GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, GDI32.SRCCOPY);
            GDI32.SelectObject(hdcDest, hOld);
            GDI32.DeleteDC(hdcDest);
            User32.ReleaseDC(handle, hdcSrc);
            Image img = Image.FromHbitmap(hBitmap);
            GDI32.DeleteObject(hBitmap);
            return img;
        }
        /// <summary>
        /// 指定窗口截图 保存为图片文件
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="filename"></param>
        /// <param name="format"></param>
        public void CaptureWindowToFile(IntPtr handle, string filename, ImageFormat format)
        {
            Image img = CaptureWindow(handle);
            img.Save(filename, format);
        }
        /// <summary>
        /// 全屏截图 保存为文件
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="format"></param>
        public void CaptureScreenToFile(string filename, ImageFormat format)
        {
            Image img = CaptureScreen();
            img.Save(filename, format);
        }

        /// <summary>
        /// 辅助类 定义 Gdi32 API 函数
        /// </summary>
        private class GDI32
        {

            public const int SRCCOPY = 0x00CC0020;
            [DllImport("gdi32.dll")]
            public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest,
                int nWidth, int nHeight, IntPtr hObjectSource,
                int nXSrc, int nYSrc, int dwRop);
            [DllImport("gdi32.dll")]
            public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth,
                int nHeight);
            [DllImport("gdi32.dll")]
            public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
            [DllImport("gdi32.dll")]
            public static extern bool DeleteDC(IntPtr hDC);
            [DllImport("gdi32.dll")]
            public static extern bool DeleteObject(IntPtr hObject);
            [DllImport("gdi32.dll")]
            public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
        }

        /// <summary>
        /// 辅助类 定义User32 API函数
        /// </summary>
        private class User32
        {
            [StructLayout(LayoutKind.Sequential)]
            public struct RECT
            {
                public int left;
                public int top;
                public int right;
                public int bottom;
            }
            [DllImport("user32.dll")]
            public static extern IntPtr GetDesktopWindow();
            [DllImport("user32.dll")]
            public static extern IntPtr GetWindowDC(IntPtr hWnd);
            [DllImport("user32.dll")]
            public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
            [DllImport("user32.dll")]
            public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
        }
    }

 

 

上面的类 使用了BitBlt这个API 可以截取GDI或者非GDI图形 只不过,非前端窗体图形不能截获…

下面说一下不使用API 最简单的全屏截图方案

 

        public static Bitmap CopyPrimaryScreen()
        {
            Screen s = Screen.PrimaryScreen;
            Rectangle r = s.Bounds;
            int w = r.Width;
            int h = r.Height;
            Bitmap bmp = new Bitmap(w, h);
            Graphics g = Graphics.FromImage(bmp);
            g.CopyFromScreen
            (
            new Point(0, 0),
            new Point(0, 0),
            new Size(w, h)
            );
            return bmp;
        }

 

最后,试试下面这个办法:

 

只要窗体的visable为true,即使它在屏幕的外面也可以抓到图。如果为false,就是一张黑图了,赫赫。
 
public static Bitmap GetWindow(IntPtr hWnd)
  {
   IntPtr hscrdc = GetWindowDC(hWnd);
   Control control = Control.FromHandle(hWnd);
   IntPtr hbitmap = CreateCompatibleBitmap(hscrdc, control.Width, control.Height);
   IntPtr hmemdc = CreateCompatibleDC(hscrdc);
   SelectObject(hmemdc, hbitmap);
   PrintWindow(hWnd, hmemdc, 0);
   Bitmap bmp = Bitmap.FromHbitmap(hbitmap);
   DeleteDC(hscrdc);//删除用过的对象
   DeleteDC(hmemdc);//删除用过的对象
   return bmp;
  }

API声明

[DllImport("gdi32.dll")]
  public static extern IntPtr CreateDC(
   string lpszDriver,        // driver name驱动名
   string lpszDevice,        // device name设备名
   string lpszOutput,        // not used; should be NULL
   IntPtr lpInitData  // optional printer data
   );
  [DllImport("gdi32.dll")]
  public static extern int BitBlt(
   IntPtr hdcDest, // handle to destination DC目标设备的句柄
   int nXDest,  // x-coord of destination upper-left corner目标对象的左上角的X坐标
   int nYDest,  // y-coord of destination upper-left corner目标对象的左上角的Y坐标
   int nWidth,  // width of destination rectangle目标对象的矩形宽度
   int nHeight, // height of destination rectangle目标对象的矩形长度
   IntPtr hdcSrc,  // handle to source DC源设备的句柄
   int nXSrc,   // x-coordinate of source upper-left corner源对象的左上角的X坐标
   int nYSrc,   // y-coordinate of source upper-left corner源对象的左上角的Y坐标
   UInt32 dwRop  // raster operation code光栅的操作值
   );

  [DllImport("gdi32.dll")]
  public static extern IntPtr CreateCompatibleDC(
   IntPtr hdc // handle to DC
   );

  [DllImport("gdi32.dll")]
  public static extern IntPtr CreateCompatibleBitmap(
   IntPtr hdc,        // handle to DC
   int nWidth,     // width of bitmap, in pixels
   int nHeight     // height of bitmap, in pixels
   );

  [DllImport("gdi32.dll")]
  public static extern IntPtr SelectObject(
   IntPtr hdc,          // handle to DC
   IntPtr hgdiobj   // handle to object
   );

  [DllImport("gdi32.dll")]
  public static extern int DeleteDC(
   IntPtr hdc          // handle to DC
   );

  [DllImport("user32.dll")]
  public static extern bool PrintWindow(
   IntPtr hwnd,               // Window to copy,Handle to the window that will be copied. 
   IntPtr  hdcBlt,             // HDC to print into,Handle to the device context. 
   UInt32 nFlags              // Optional flags,Specifies the drawing options. It can be one of the following values. 
   );

  [DllImport("user32.dll")]
  public static extern IntPtr GetWindowDC(
   IntPtr hwnd
   );

Leave a Reply