2

I have a .NET control which outputs a video via unmanaged code.

I'd like to capture the control client area (a video frame).

The method Control.DrawToBitmap does not work, it outputs the control background - gray color.

Then I tried to use the GDI's BitBlt:

    [DllImport("gdi32.dll")]
    private static extern bool BitBlt(
    IntPtr hdcDest, // handle to destination DC
    int nXDest, // x-coord of destination upper-left corner
    int nYDest, // y-coord of destination upper-left corner
    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
    int nYSrc, // y-coordinate of source upper-left corner
    int dwRop // raster operation code
    );

    private const int SRCCOPY = 0xCC0020;

    private void btnSave_Click(object sender, EventArgs e)
    {
        Graphics graphic = captureBox.CreateGraphics();
        Bitmap memImage = new Bitmap(captureBox.Width, captureBox.Height, graphic);
        Graphics memGraphic = Graphics.FromImage(memImage);
        IntPtr dc1 = graphic.GetHdc();
        IntPtr dc2 = memGraphic.GetHdc();

        BitBlt(dc2, 0, 0, this.captureBox.ClientRectangle.Width,
        this.captureBox.ClientRectangle.Height, dc1, 0, 0, SRCCOPY);

        graphic.ReleaseHdc(dc1);
        memGraphic.ReleaseHdc(dc2);

        memImage.Save("capture.bmp", ImageFormat.Bmp);
    }

It works, but the problem is that it captures all - even controls that are over the captured control.

I want to capture the control client area even when it is overlapped. How can it be achieved?

Centro
  • 3,892
  • 2
  • 25
  • 31

1 Answers1

1

this should work but its been a while since I've written code to do this with winforms... if it doesn't I may be able to recreate it.

Rather than

Graphics graphic = captureBox.CreateGraphics();
IntPtr dc1 = graphic.GetHdc();

do

[DllImport("gdi32.dll")]
private static extern IntPtr GetDC(IntPtr hWnd)
[DllImport("gdi32.dll")]
private static extern int ReleaseDc(IntPtr hWnd, IntPtr hDc)
// ...

IntPtr dc1 = GetDc(captureBox.Handle);
// ...
ReleaseDc(captureBox.Handle,dc1);

also note that if this gives you the grey background it may mean that the unmanaged code isn't rendering into your window, but another window that was created on top of it. You can find out if this is the case with spy++.

Yaur
  • 7,333
  • 1
  • 25
  • 36
  • Actually I don't see any difference between using GDI P/Invokes directly and their .NET version that just wraps those GDI P/Invokes. It was a nice idea to check via Spy++, but unfortunately there is no additional window, i.e. the video is rendered directly into the .NET control. Also it is strange enough that sometimes the video is captured, sometimes the grey background is, as though no window invalidation happens when the video is rendered. Also I tried to use the PrintWindow API, it behaves the same way (mostly the grey background, sometimes the video), but it resolves the overlap problem. – Centro May 28 '11 at 23:01
  • that is probably right it isn't invalidating the window when it draws the video. But when the PictureBox's WndProc gets a paint message it will redraw it with the "proper" content which is, as far as its concerned, the grey background. Subclass PictureBox and add your own handling for WM_PAINT and/or WM_NCPAINT which may make it always return the video. – Yaur May 28 '11 at 23:26