0

I'm trying to take a screenshot of another window specified by a valid hwnd. The procedure works, however the window flickers when the screenshot is taken.

The first function uses PrintScreen, the second BitBlt. Each is called from a routine that takes a screenshot every 10 seconds.

Is there a way to avoid a flicker when using the PrintScreen or BitBlt functions?

Any help would be appreciated.

        public Bitmap GetScreenshot(IntPtr ihandle)
    {
        IntPtr hwnd = ihandle;//handle here

        RECT rc;
        FocusWindow(ihandle);
        GetWindowRect(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 Bitmap CaptureWindowImage(IntPtr hWnd)  //, System.Drawing.Rectangle wndRect)
    {
        IntPtr hWndDc = GetDC(hWnd);
        IntPtr hMemDc = CreateCompatibleDC(hWndDc);
        RECT rc;
        GetWindowRect(hWnd, out rc);

        IntPtr hBitmap = CreateCompatibleBitmap(hWndDc, rc.Width, rc.Height);
        SelectObject(hMemDc, hBitmap);

        BitBlt(hMemDc, 0, 0, rc.Width, rc.Height, hWndDc, 0, 0, TernaryRasterOperations.SRCCOPY);
        Bitmap bitmap = Bitmap.FromHbitmap(hBitmap);

        DeleteObject(hBitmap);
        ReleaseDC(hWnd, hWndDc);
        ReleaseDC(IntPtr.Zero, hMemDc);
        DeleteDC(hMemDc);
        return bitmap;
    }
Scott Mooney
  • 167
  • 1
  • 1
  • 4
  • you should just use `Graphics.CopyFromScreen`. I see a few GDI memory leaks in your code. That's not causing the flicker, but there are zero reasons to use unmanaged code for this solution, especially if you use it wrong. – Andy Mar 15 '21 at 01:03
  • BTW, `Graphics.CopyFromScreen()` already uses BitBlt internally. -- As an alternative, you can also call [PrintWindow](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-printwindow); example [here](https://stackoverflow.com/a/65317047/7444103) (slightly different language). It has the advantage that is not a screenshot, so you can print a Window to a destination DC even if its partially or completely obscured by another. – Jimi Mar 15 '21 at 01:21
  • Are `GetScreenshot` and `CaptureWindowImage` two methods? When I used `CaptureWindowImage`, I didn't find any flickering problems. Did I miss some steps? Which window does the flickering problem appear on? Maybe you can post the complete code for us to reproduce. – Strive Sun Mar 15 '21 at 02:43

0 Answers0