BitBlt игнорирует CAPTUREBLT и, кажется, всегда захватывает кэшированную копию цели - PullRequest
8 голосов
/ 24 мая 2010

Я пытаюсь сделать снимки экрана с помощью функции BitBlt. Однако каждый раз, когда я делаю снимок экрана, область, не относящаяся к клиенту, НИКОГДА не меняется, независимо от того, что я делаю. Как будто он получает какую-то кешированную копию. Клиентская область захвачена правильно.

Если я закрою, а затем снова открою окно и сделаю снимок экрана, область, не являющаяся клиентом, будет захвачена как есть. Любые последующие захваты после перемещения / изменения размера окна не влияют на захваченный снимок экрана. Опять же, клиентская область будет правильной.

Кроме того, флаг CAPTUREBLT, похоже, абсолютно ничего не делает. Я не замечаю никаких изменений с этим или без него. Вот мой код захвата:

QPixmap WindowManagerUtils::grabWindow(WId windowId, GrabWindowFlags flags, int x, int y, int w, int h)
{
    RECT r;

    switch (flags)
    {
        case WindowManagerUtils::GrabWindowRect:
            GetWindowRect(windowId, &r);
            break;
        case WindowManagerUtils::GrabClientRect:
            GetClientRect(windowId, &r);
            break;
        case WindowManagerUtils::GrabScreenWindow:
            GetWindowRect(windowId, &r);
            return QPixmap::grabWindow(QApplication::desktop()->winId(), r.left, r.top, r.right - r.left, r.bottom - r.top);
        case WindowManagerUtils::GrabScreenClient:
            GetClientRect(windowId, &r);
            return QPixmap::grabWindow(QApplication::desktop()->winId(), r.left, r.top, r.right - r.left, r.bottom - r.top);
        default:
            return QPixmap();
    }

    if (w < 0)
    {
        w = r.right - r.left;
    }

    if (h < 0)
    {
        h = r.bottom - r.top;
    }

#ifdef Q_WS_WINCE_WM
    if (qt_wince_is_pocket_pc())
    {
        QWidget *widget = QWidget::find(winId);
        if (qobject_cast<QDesktopWidget*>(widget))
        {
            RECT rect = {0,0,0,0};
            AdjustWindowRectEx(&rect, WS_BORDER | WS_CAPTION, FALSE, 0);
            int magicNumber = qt_wince_is_high_dpi() ? 4 : 2;
            y += rect.top - magicNumber;
        }
    }
#endif

    // Before we start creating objects, let's make CERTAIN of the following so we don't have a mess
    Q_ASSERT(flags == WindowManagerUtils::GrabWindowRect || flags == WindowManagerUtils::GrabClientRect);

    // Create and setup bitmap
    HDC display_dc = NULL;
    if (flags == WindowManagerUtils::GrabWindowRect)
    {
        display_dc = GetWindowDC(NULL);
    }
    else if (flags == WindowManagerUtils::GrabClientRect)
    {
        display_dc = GetDC(NULL);
    }

    HDC bitmap_dc = CreateCompatibleDC(display_dc);
    HBITMAP bitmap = CreateCompatibleBitmap(display_dc, w, h);
    HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap);

    // copy data
    HDC window_dc = NULL;
    if (flags == WindowManagerUtils::GrabWindowRect)
    {
        window_dc = GetWindowDC(windowId);
    }
    else if (flags == WindowManagerUtils::GrabClientRect)
    {
        window_dc = GetDC(windowId);
    }

    DWORD ropFlags = SRCCOPY;
#ifndef Q_WS_WINCE
    ropFlags = ropFlags | CAPTUREBLT;
#endif

    BitBlt(bitmap_dc, 0, 0, w, h, window_dc, x, y, ropFlags);

    // clean up all but bitmap
    ReleaseDC(windowId, window_dc);
    SelectObject(bitmap_dc, null_bitmap);
    DeleteDC(bitmap_dc);

    QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap);

    DeleteObject(bitmap);
    ReleaseDC(NULL, display_dc);

    return pixmap;
}

Большая часть этого кода взята из функции Qt QWidget :: grabWindow, так как я хотел внести некоторые изменения, чтобы она была более гибкой. Документация Qt гласит:

Функция grabWindow () захватывает пиксели с экрана, а не из окна, т.е. если есть другое окно частично или полностью над той, которую вы захватить, вы получите пиксели от вышележащее окно тоже.

Однако, я испытываю противоположное ... независимо от флага CAPTUREBLT. Я перепробовал все, что мог придумать ... ничего не работает. Есть идеи?

Ответы [ 2 ]

7 голосов
/ 10 января 2011

Ваша путаница в отношении BitBlt с поведением CAPTUREBLT обусловлена ​​тем, что официальная документация BitBlt неясна и вводит в заблуждение.

В нем говорится, что
"CAPTUREBLT - включает в себя любые окна, расположенные в верхней части окна в результирующем изображении. По умолчанию изображение содержит только ваше окно."

Что на самом деле означает (по крайней мере, для любой операционной системы Windows без Aero) "CAPTUREBLT - включает любые многоуровневые (!) Окна (см. Расширенный стиль окна WS_EX_LAYERED), которые перекрывают ваше окно. Не слоистые окна, которые перекрывают ваше окно, никогда не включаются."

Windows без WS_EX_LAYERED расширенный стиль окна, перекрывающий ваше окно, не включается с флагом CAPTUREBLT или без него (по крайней мере, для любой операционной системы Windows без Aero).

Разработчики QT также неправильно поняли документацию BitBlt / CAPTUREBLT, так что документация QT фактически неверна в отношении поведения QPixmap :: grabWindow на платформе WIN32 без включенного Aero.

ADD:

Если вы хотите захватить ваше окно, как оно есть на экране, вы должны захватить весь рабочий стол с флагом CAPTUREBLT, а затем извлечь прямоугольник с вашим окном. (Разработчики QT должны сделать то же самое). Он будет работать правильно в обоих случаях: с включенным / доступным Aero и без него.

0 голосов
/ 05 ноября 2013

Я снимаю весь экран и получаю одинаковые результаты ...: (

const uint SRCCOPY = 0x00CC0020; //SRCCOPY
    const uint CAPTUREBLT = 0x00CC0020 | 0x40000000; //CAPTUREBLT

    bool dv = BitBlt(hCaptureDC, 0, 0, Bounds.Width, Bounds.Height,
             hDesktopDC, Bounds.Left, Bounds.Top, _with_tooltips ? CAPTUREBLT : SRCCOPY);
...