Захват без перекрытия

У меня есть элемент управления .NET, который выводит видео через неуправляемый код.

Я хотел бы захватить клиентскую область управления (кадр видео).

Метод Control.DrawToBitmap не работает, выводит фон элемента - серый цвет.

Затем я попытался использовать BitBlt GDI:

    [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);
    }

Он работает, но проблема в том, что он захватывает все — даже те элементы управления, которые находятся над захваченным элементом управления.

Я хочу захватить область клиента управления, даже если она перекрывается. Как этого добиться?


person Centro    schedule 28.05.2011    source источник
comment
вы используете D3DImage или что-то еще?   -  person Yaur    schedule 29.05.2011
comment
Попробуйте использовать SRCCOPY | CAPTUREBLT   -  person Chris O    schedule 29.05.2011
comment
@Chris O Это тоже не работает, перекрытие все еще фиксируется вместе с элементом управления.   -  person Centro    schedule 29.05.2011


Ответы (1)


это должно работать, но прошло некоторое время с тех пор, как я написал код для этого с помощью winforms... если это не так, я смогу его воссоздать.

Скорее, чем

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);

также обратите внимание, что если это дает вам серый фон, это может означать, что неуправляемый код отображается не в вашем окне, а в другом окне, созданном поверх него. Вы можете узнать, так ли это, с помощью spy++.

person Yaur    schedule 28.05.2011
comment
На самом деле я не вижу никакой разницы между использованием GDI P/Invokes напрямую и их версией .NET, которая просто обертывает эти GDI P/Invokes. Неплохо было проверить через Spy++, но к сожалению нет дополнительного окна, т.е. видео рендерится прямо в .NET контрол. Также довольно странно, что иногда видео захватывается, иногда серый фон, как будто не происходит инвалидации окна при рендеринге видео. Также я пытался использовать API PrintWindow, он ведет себя так же (в основном серый фон, иногда видео), но решает проблему перекрытия. - person Centro; 29.05.2011
comment
это, вероятно, правильно, это не делает окно недействительным, когда оно рисует видео. Но когда WndProc PictureBox получает сообщение о рисовании, он перерисовывает его с правильным содержимым, которое, насколько это возможно, является серым фоном. Подкласс PictureBox и добавьте свою собственную обработку для WM_PAINT и/или WM_NCPAINT, которая может заставить его всегда возвращать видео. - person Yaur; 29.05.2011