Hi,

I have been searching on google to find a way to get a bitmap of a hidden window. I thought I found it, but when tried it, it is only giving me a good image (not a black one), when my window is in front/active, when hidden it give me a black bitmap.

Here is my code:

public const int SRCCOPY = 13369376;
        public const int WM_CLICK = 0x00F5;


        [DllImport("user32.dll", SetLastError = true)]
        internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", EntryPoint = "GetDC")]
        internal extern static IntPtr GetDC(IntPtr hWnd);

        [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleDC")]
        internal extern static IntPtr CreateCompatibleDC(IntPtr hdc);

        [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleBitmap")]
        internal extern static IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);

        [DllImport("gdi32.dll", EntryPoint = "DeleteDC")]
        internal extern static IntPtr DeleteDC(IntPtr hDc);

        [DllImport("user32.dll", EntryPoint = "ReleaseDC")]
        internal extern static IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);

        [DllImport("gdi32.dll", EntryPoint = "BitBlt")]
        internal extern static bool BitBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, int RasterOp);

        [DllImport("gdi32.dll", EntryPoint = "SelectObject")]
        internal extern static IntPtr SelectObject(IntPtr hdc, IntPtr bmp);

        [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
        internal extern static IntPtr DeleteObject(IntPtr hDc);

        [DllImport("user32.dll")]
        public static extern int SendMessage(
              int hWnd,      // handle to destination window
              uint Msg,       // message
              long wParam,  // first message parameter
              long lParam   // second message parameter
              );

        static IntPtr hWnd = FindWindow(null, "My programs title");

        public static Bitmap createBitmap()
        {

            Bitmap bmp = null;

            IntPtr hdcFrom = GetDC(hWnd);

            IntPtr hdcTo = CreateCompatibleDC(hdcFrom);

            //X and Y coordinates of window
            int Width = 529;
            int Height = 436;

            IntPtr hBitmap = CreateCompatibleBitmap(hdcFrom, Width, Height);

            if (hBitmap != IntPtr.Zero)
            {
                // adjust and copy
                IntPtr hLocalBitmap = SelectObject(hdcTo, hBitmap);
                BitBlt(hdcTo, 0, 0, Width, Height,
                    hdcFrom, 0, 0, SRCCOPY);
                SelectObject(hdcTo, hLocalBitmap);
                //We delete the memory device context.
                DeleteDC(hdcTo);
                //We release the screen device context.
                ReleaseDC(hWnd, hdcFrom);
                //Image is created by Image bitmap handle and assigned to Bitmap variable.
                bmp = System.Drawing.Image.FromHbitmap(hBitmap);
                //Delete the compatible bitmap object. 
                DeleteObject(hBitmap);

                bmp.Save("here comes my link where it needs to be saved", ImageFormat.Bmp);

            }

            return bmp;

        }

As stated above, it doesn't work when my window is hidden. Everything works except when my window is hidden. Does anyone have an idea how I can create a bitmap (not a black one) when my window is hidden?

Any help is greatly appreciated.

Dani AI

Generated

What you are seeing is expected: a hidden/minimized top-level window typically has no pixels to copy, so GetDC/BitBlt returns a black bitmap. Even when the window is merely occluded, GDI will not include layered/DWM content unless you ask for it. Use APIs that ask the target to draw into your DC instead of scraping pixels from the screen, and size the capture correctly.

  • Prefer PrintWindow. It asks the target to render itself and works even when off-screen. On modern Windows, add the flag that renders full content (works on 8.1+): PW_RENDERFULLCONTENT (0x00000002). If you pass 0, you get the whole window; PW_CLIENTONLY (0x00000001) limits to client area. Note: PrintWindow routes through WM_PRINT/WM_PRINTCLIENT, so results depend on how the app handles those messages. PrintWindow docs.

  • If the target supports it, WM_PRINT can be used directly. Be sure NOT to include PRF_CHECKVISIBLE when capturing a hidden window, and include both client and nonclient if you want the full frame. WM_PRINT docs, WM_PRINTCLIENT.

Example (C#, abbreviated) showing WM_PRINT usage:

[DllImport("user32.dll")] 
static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

const int WM_PRINT = 0x0317;
const int PRF_NONCLIENT = 0x00000002, PRF_CLIENT = 0x00000004;
const int PRF_ERASEBKGND = 0x00000008, PRF_CHILDREN = 0x00000010;

// after creating a compatible DC + bitmap and selecting it:
int flags = PRF_CLIENT | PRF_NONCLIENT | PRF_CHILDREN | PRF_ERASEBKGND;
SendMessage(hWnd, WM_PRINT, memHdc, (IntPtr)flags);
  • For overlapped but visible windows, BitBlt can work if you OR in CAPTUREBLT (0x40000000) to include layered/DWM surfaces; this still will not help when the window is hidden/minimized. BitBlt docs.

  • Size the bitmap from GetWindowRect for full frame, or use DwmGetWindowAttribute(DWMWA_EXTENDED_FRAME_BOUNDS) to capture without the drop shadow, then crop accordingly. DwmGetWindowAttribute.

Gaurang Patel’s PrintWindow tip is the right direction; if you still get black with GPU-heavy apps, try PW_RENDERFULLCONTENT, or temporarily restore the window off-screen before capture.

Recommended Answers

All 3 Replies

>when hidden it give me a black bitmap.

Have a look at blog.

use PrintWindow API. Its works fine.

public System.Drawing.Bitmap CaptureWindow(IntPtr hWnd)
        {
            System.Drawing.Rectangle rctForm = System.Drawing.Rectangle.Empty;

            using (System.Drawing.Graphics grfx = System.Drawing.Graphics.FromHdc(GetWindowDC(hWnd)))
            {
                rctForm = System.Drawing.Rectangle.Round(grfx.VisibleClipBounds);
            }

            System.Drawing.Bitmap pImage = new System.Drawing.Bitmap(rctForm.Width, rctForm.Height);
            System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(pImage);

            IntPtr hDC = graphics.GetHdc();
            //paint control onto graphics using provided options        
            try
            {
                PrintWindow(hWnd, hDC, (uint)0);
            }
            finally
            {
                graphics.ReleaseHdc(hDC);
            }
            return pImage;


        }

The code posted by Gaurang Patel did the trick, awesome!.
The only thing that's missing is a couple of DLLIMPORTs:

[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);

[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.