对指定IntPtr窗口截图(C#)


简介

使用IntPtr方式对窗口截图,可以避免被其它窗体遮挡而影响截图效果的问题。

步骤

  1. 通过Spy++或其他工具,获取指定窗口的IntPtr
  2. 调用CaptureWindow方法截图
public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }
    #region 
    enum GetWindowCmd : uint
    {
        GW_HWNDFIRST = 0,
        GW_HWNDLAST = 1,
        GW_HWNDNEXT = 2,
        GW_HWNDPREV = 3,
        GW_OWNER = 4,
        GW_CHILD = 5,
        GW_ENABLEDPOPUP = 6
    }
    #endregion

    class ScreenCapture
    {
        [DllImport("user32.dll")]
        private static extern IntPtr GetWindowDC(IntPtr hwnd);
        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();
        [DllImport("user32.dll")]
        private static extern IntPtr GetWindowRect(IntPtr hWnd, out RECT rect);
        [DllImport("user32.dll")]
        private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, UInt32 nFlags);
        [DllImport("user32.dll")]
        private static extern IntPtr GetDesktopWindow();

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr GetWindow(IntPtr hWnd, GetWindowCmd uCmd);

        [DllImport("gdi32.dll")]
        private 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")]
        private 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坐标
             CopyPixelOperation dwRop   // raster operation code光栅的操作值
         );
        //static extern int BitBlt(IntPtr hdcDest, int xDest, int yDest, int
        //wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, CopyPixelOperation rop);

        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateCompatibleDC(
         IntPtr hdc // handle to DC
         );
        [DllImport("gdi32.dll")]
        private 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")]
        private static extern IntPtr SelectObject(
             IntPtr hdc,           // handle to DC
             IntPtr hgdiobj    // handle to object
         );
        [DllImport("gdi32.dll")]
        private static extern int DeleteDC(
            IntPtr hdc           // handle to DC
         );

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        //[DllImport("User32.dll", CharSet = CharSet.Auto)]
        //public static extern int GetClassName(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);

        public IntPtr GetFistChildHandle(IntPtr parent)
        {
            return GetWindow(parent, GetWindowCmd.GW_CHILD);
        }

        public IntPtr GetNextHandle(IntPtr ptr)
        {
            return GetWindow(ptr, GetWindowCmd.GW_HWNDNEXT);
        }

        public string GetClassName(IntPtr ptr)
        {
            StringBuilder builder = new StringBuilder(20);
            GetClassName(ptr, builder, 20);
            return builder.ToString();
        }

        public IntPtr FindHandleByClassName(IntPtr parent, string className)
        {
            IntPtr childHandle = GetFistChildHandle(parent);
            while (childHandle != IntPtr.Zero)
            {
                string cName = GetClassName(childHandle);
                if (cName.Trim().ToLower() == className.Trim().ToLower())
                {
                    return childHandle;
                }
                childHandle = GetNextHandle(childHandle);
            }
            return IntPtr.Zero;
        }

        /// <summary>
        /// 抓取屏幕(层叠的窗口)
        /// </summary>
        /// <param name="x">左上角的横坐标</param>
        /// <param name="y">左上角的纵坐标</param>
        /// <param name="width">抓取宽度</param>
        /// <param name="height">抓取高度</param>
        /// <returns></returns>
        public Bitmap CaptureScreen(int x, int y, int width, int height)
        {
            Bitmap bmp = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.CopyFromScreen(new Point(x, y), new Point(0, 0), bmp.Size);
                g.Dispose();
            }
            return bmp;
        }

        /// <summary>
        /// 指定窗口截图
        /// </summary>
        /// <param name="handle">窗口句柄. (在windows应用程序中, 从Handle属性获得)</param>
        /// <returns></returns>
        public Bitmap CaptureWindow(IntPtr hWnd)
        {
            IntPtr hscrdc = GetWindowDC(hWnd);
            RECT rect = new RECT();
            return CaptureWindow(hWnd, rect);
        }

        /// <summary>
        /// 指定窗口区域截图
        /// </summary>
        /// <param name="handle">窗口句柄. (在windows应用程序中, 从Handle属性获得)</param>
        /// <param name="rect">窗口中的一个区域</param>
        /// <returns></returns>
        public Bitmap CaptureWindow(IntPtr hWnd, RECT rect)
        {
            // 获取设备上下文环境句柄
            IntPtr hscrdc = GetWindowDC(hWnd);

            // 创建一个与指定设备兼容的内存设备上下文环境(DC)
            IntPtr hmemdc = CreateCompatibleDC(hscrdc);
            IntPtr myMemdc = CreateCompatibleDC(hscrdc);

            // 返回指定窗体的矩形尺寸
            RECT rect1;
            GetWindowRect(hWnd, out rect1);

            // 返回指定设备环境句柄对应的位图区域句柄
            IntPtr hbitmap = CreateCompatibleBitmap(hscrdc, rect1.Right - rect1.Left, rect1.Bottom - rect1.Top);
            IntPtr myBitmap = hbitmap;// CreateCompatibleBitmap(hscrdc, rect.Right - rect.Left, rect.Bottom - rect.Top);

            //把位图选进内存DC 
            // IntPtr OldBitmap = (IntPtr)SelectObject(hmemdc, hbitmap);
            SelectObject(hmemdc, hbitmap);
            SelectObject(myMemdc, myBitmap);

            /////////////////////////////////////////////////////////////////////////////
            //
            // 下面开始所谓的作画过程,此过程可以用的方法很多,看你怎么调用 API 了
            //
            /////////////////////////////////////////////////////////////////////////////

            // 直接打印窗体到画布
            PrintWindow(hWnd, hmemdc, 0);

            // IntPtr hw = GetDesktopWindow();
            // IntPtr hmemdcClone = GetWindowDC(myBitmap);

            BitBlt(myMemdc, 0, 0, rect.Right - rect.Left, rect.Bottom - rect.Top, hmemdc, rect.Left, rect.Top, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
            //SelectObject(myMemdc, myBitmap);

            Bitmap bmp = Bitmap.FromHbitmap(myBitmap);
            DeleteDC(hscrdc);
            DeleteDC(hmemdc);
            DeleteDC(myMemdc);
            return bmp;
        }
    }

文章作者: wireboy
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 wireboy !
  目录