Capturing a window with WPF

后端 未结 2 1947
萌比男神i
萌比男神i 2021-02-10 19:02

With Windows Presentation Foundation, if I have an HWND, how can I capture it\'s window as an image that I can manipulate and display?

相关标签:
2条回答
  • 2021-02-10 19:16

    You can:

    1. CreateBitmap() to create a hBitmap
    2. Call GetDC() on the hWnd
    3. BitBlt() the contents to the hBitmap
    4. ReleaseDC()
    5. Call Imaging.CreateBitmapSourceFromHBitmap() to create a managed BitmapSource
    6. DeleteObject() on the hBitmap
    7. Use the BitmapSource as desired

    Steps 1-4 and 6 use the Win32 API (GDI to be precise), Steps 5 and 7 are done using WPF

    0 讨论(0)
  • 2021-02-10 19:43

    While above answer is great, this would have saved a ton of time too:

    Using section:

    using System;
    using System.Windows;
    using System.Windows.Interop;
    using System.Runtime.InteropServices;
    using System.Windows.Media.Imaging;
    

    Code:

    /// <summary>
    /// Captures screenshot using WINAPI.
    /// </summary>
    static public class CaptureScreenshot
    {
        /// <summary>
        /// Capture the screenshot.
        /// <param name="area">Area of screenshot.</param>
        /// <returns>Bitmap source that can be used e.g. as background.</returns>
        /// </summary>
        public static BitmapSource Capture(Rect area)
        {
            IntPtr screenDC = GetDC(IntPtr.Zero);
            IntPtr memDC = CreateCompatibleDC(screenDC);
            IntPtr hBitmap = CreateCompatibleBitmap(screenDC, (int)SystemParameters.VirtualScreenWidth, (int)SystemParameters.VirtualScreenHeight);
            SelectObject(memDC, hBitmap); // Select bitmap from compatible bitmap to memDC
    
            // TODO: BitBlt may fail horribly
            BitBlt(memDC, 0, 0, (int)area.Width, (int)area.Height, screenDC, (int)area.X, (int)area.Y, TernaryRasterOperations.SRCCOPY);
            BitmapSource bsource = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
    
            DeleteObject(hBitmap);
            ReleaseDC(IntPtr.Zero, screenDC);
            ReleaseDC(IntPtr.Zero, memDC);
            return bsource;
        }
    
        #region WINAPI DLL Imports
    
        [DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
        static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
    
        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
    
        [DllImport("gdi32.dll", SetLastError = true)]
        private static extern IntPtr CreateCompatibleDC(IntPtr hdc);
    
        [DllImport("gdi32.dll")]
        private static extern bool DeleteObject(IntPtr hObject);
    
        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateBitmap(int nWidth, int nHeight, uint cPlanes, uint cBitsPerPel, IntPtr lpvBits);
    
        [DllImport("user32.dll")]
        private static extern IntPtr GetDC(IntPtr hWnd);
    
        [DllImport("user32.dll")]
        private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
    
        private enum TernaryRasterOperations : uint
        {
            /// <summary>dest = source</summary>
            SRCCOPY = 0x00CC0020,
            /// <summary>dest = source OR dest</summary>
            SRCPAINT = 0x00EE0086,
            /// <summary>dest = source AND dest</summary>
            SRCAND = 0x008800C6,
            /// <summary>dest = source XOR dest</summary>
            SRCINVERT = 0x00660046,
            /// <summary>dest = source AND (NOT dest)</summary>
            SRCERASE = 0x00440328,
            /// <summary>dest = (NOT source)</summary>
            NOTSRCCOPY = 0x00330008,
            /// <summary>dest = (NOT src) AND (NOT dest)</summary>
            NOTSRCERASE = 0x001100A6,
            /// <summary>dest = (source AND pattern)</summary>
            MERGECOPY = 0x00C000CA,
            /// <summary>dest = (NOT source) OR dest</summary>
            MERGEPAINT = 0x00BB0226,
            /// <summary>dest = pattern</summary>
            PATCOPY = 0x00F00021,
            /// <summary>dest = DPSnoo</summary>
            PATPAINT = 0x00FB0A09,
            /// <summary>dest = pattern XOR dest</summary>
            PATINVERT = 0x005A0049,
            /// <summary>dest = (NOT dest)</summary>
            DSTINVERT = 0x00550009,
            /// <summary>dest = BLACK</summary>
            BLACKNESS = 0x00000042,
            /// <summary>dest = WHITE</summary>
            WHITENESS = 0x00FF0062
        }
    
        [DllImport("gdi32.dll")]
        private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
    
        #endregion
    }
    

    Notice that this takes screenshot of given area in the screen and not of window. It works for my purposes, you probably have to modify it for yours :)

    0 讨论(0)
提交回复
热议问题