2010-05-24 2 views
8

Sto provando a catturare schermate usando la funzione BitBlt. Tuttavia, ogni volta che catturo uno screenshot, l'area non client non cambia MAI indipendentemente da ciò che faccio. È come se ne stessero copiane una copia nella cache. L'area del client viene acquisita correttamente.BitBlt ignora CAPTUREBLT e sembra catturare sempre una copia cache del target

Se chiudo e quindi riapre la finestra e faccio uno screenshot, l'area non client verrà acquisita così com'è. Qualsiasi cattura successiva dopo lo spostamento/ridimensionamento della finestra non ha alcun effetto sullo screenshot catturato. Di nuovo, l'area cliente sarà corretta.

Inoltre, la bandiera CAPTUREBLT sembra non fare assolutamente nulla. Non noto alcun cambiamento con o senza di esso. Qui è il mio codice di cattura:

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

La maggior parte di questo codice viene da funzione QWidget :: grabWindow di Qt, come ho voluto fare alcune modifiche in modo che sarebbe stato più flessibile. la documentazione di Qt afferma che:

La funzione grabWindow() afferra pixel dallo schermo, non dalla finestra, vale a dire se c'è un altro finestra parzialmente o totalmente su quello che si afferrare, si ottiene pixel da anche la finestra sovrastante .

Tuttavia, provo l'esatto contrario ... indipendentemente dal flag CAPTUREBLT. Ho provato tutto quello che riesco a pensare ... niente funziona. Qualche idea?

risposta

7

tua confusione su BitBlt con CAPTUREBLT comportamento deriva dal fatto che il funzionario BitBlt documentazione è chiaro e fuorviante.

afferma che
"CAPTUREBLT - Include tutte le finestre che sono a strati sulla parte superiore della finestra nell'immagine risultante Per impostazione predefinita, l'immagine contiene solo la finestra.".

Cosa significa in realtà (almeno per qualsiasi sistema operativo Windows senza Aero abilitata) "CAPTUREBLT - comprende qualsiasi strati finestre (vedi WS_EX_LAYERED esteso stile finestra) che si sovrappongono finestra finestre non-strati che si sovrappongono (!). la tua finestra non è mai inclusa. "

Windows senza WS_EX_LAYERED esteso stile di finestra che si sovrappongono la finestra non è incluso con o senza CAPTUREBLT bandiera (almeno per qualsiasi sistema operativo Windows senza Aero abilitata).

Gli sviluppatori QT hanno frainteso anche la documentazione BitBlt/CAPTUREBLT, quindi la documentazione QT è effettivamente errata sul comportamento di QPixmap :: grabWindow sulla piattaforma WIN32 senza Aero abilitato.

ADD:

Se si desidera catturare la vostra finestra in quanto è sullo schermo è necessario catturare l'intero desktop con bandiera CAPTUREBLT e quindi estrarre il rettangolo con la vostra finestra. (Gli sviluppatori QT dovrebbero fare la stessa cosa). Funzionerà correttamente in entrambi i casi: con e senza Aero abilitato/disponibile.

0

catturo tutto schermo e ottiene gli stessi risultati ... :(

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