Frage

Hintergrundinfo: Ich habe diese MFC-Anwendung I codiert und für eine lange Zeit verwenden, die so ziemlich automatisch Screenshots auf der Festplatte speichert, wenn der Benutzer den Print Screen Hits / Alt + Druck-Taste. Ich habe bis jetzt alles mit Bezug zu Aero aufzuschieben, dass ich für ein paar Wochen Windows 7 RC gewesen verwenden.

Das Problem: Ich bin mit dem Standard GetDC / BitBlt Methode den Fensterinhalt zu erfassen. Ich habe keine Probleme mit dieser Methode, während regelmäßiges Zupacken Vollbild zu tun (egal, wie viele Fenster geöffnet etc.). Das Problem entsteht, wenn ich versuche, das Vordergrundfenster (Alt + Druck) zu erfassen. Hier sind zwei Beispiele:

Beispiel 1 http://indiecodelabs.com/extern/example1.jpg

Beispiel 2 http://indiecodelabs.com/extern/example2.jpg

Wie Sie sehen, ich bin immer Müll, wo die Grenzen liegen. Das ist mehr spürbar nach oben hin, wo wir einige Überschneidungen der Symbolleiste in beiden Screenshots sehen können.

Ich habe jetzt stundenlang über die schon googeln und alles, was ich finden kann Artikel sagen, dass die BitBtl / GetDC Verfahren unter DWM werden nicht funktionieren, kann aber nicht einen einzigen zu erklären, was wir (die Entwickler) sollten finden Sie in der Lage sein, die gleiche Funktionalität in unsere Anwendungen zu halten, wenn auf DWM ausgeführt wird.

Jede Hilfe, Zeiger, werden Vorschläge sehr geschätzt.

War es hilfreich?

Lösung

Es ist eine ausgezeichnete Frage, die ich nicht unfortuneatly genaue Antwort wissen zu. Meine erste Idee war es, den gesamten Desktop zu packen und interessanten Teil aus ihn heraus geschnitten.

Ich habe in QT 4.5 Quellen gegraben, um zu sehen, wie sie es tun, und fand so etwas wie diese. Wenn Sie GetClientRect zu GetWindowRect wechseln und QT Standardcode Streifen sollten Sie bekommen, was Sie wollen. Es sieht aus wie ein Hack aber :)


QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h )
{
    RECT r;
    GetClientRect(winId, &r);  
    if (w < 0) w = r.right - r.left;
    if (h < 0) h = r.bottom - r.top;  
    // Create and setup bitmap
    HDC display_dc = GetDC(0);
    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 = GetDC(winId);
    BitBlt(bitmap_dc, 0, 0, w, h, window_dc, x, y, SRCCOPY);

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

    QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap);

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

    return pixmap;
}

Andere Tipps

BOOL CaptureWindow(const CString& filename)
{
    HWND hWnd = NULL;
    hWnd = ::GetForegroundWindow();   
    if(!hWnd)
    {
        return FALSE;
    }
    CRect rect;
    GetWindowRect(hWnd, &rect);
    rect.NormalizeRect();
    return DoCapture(CPoint(rect.left, rect.top), CSize(rect.Width(), rect.Height()), filename);
}

BOOL DoCapture(const POINT& coords, const SIZE& areaSize, const CString& filename)
{
    CDC dc;
    HDC hdc = GetDC(NULL);  // <-- We use this instead of GetWindowDC. 
                            // This is the only thing I had to change other than 
                            // getting the window coordinates in CaptureWindow()
    dc.Attach(hdc);

    // Create a memory DC into which the bitmap will be captured
    CDC memDC;
    memDC.CreateCompatibleDC(&dc);

    // If there is already a bitmap, delete it as we are going to replace it
    CBitmap bmp;
    bmp.DeleteObject();

    ICONINFO info;
    GetIconInfo((HICON)::GetCursor(), &info);   

    CURSORINFO cursor;
    cursor.cbSize = sizeof(CURSORINFO);
    GetCursorInfo(&cursor);

    bmp.CreateCompatibleBitmap(&dc, areaSize.cx, areaSize.cy);
    CBitmap * oldbm = memDC.SelectObject(&bmp);

    // Before we copy the image in, we blank the bitmap to
    // the background fill color
    memDC.FillSolidRect(&CRect(0,0,areaSize.cx, areaSize.cy), RGB(255,255,255));

    // Copy the window image from the window DC into the memory DC
    memDC.BitBlt(0, 0, areaSize.cx, areaSize.cy, &dc, coords.x, coords.y, SRCCOPY|CAPTUREBLT);

    // This part captures the mouse cursor and paints it on the image.
    if(programSettings.bWantCursor) 
    {    
        int osVersion = OSCheck::GetMajorOSVersion(); // For some reason cursor icons in 
                                                      // versions older than Vista are not
                                                      // top-aligned. So we compensate. 
        int offsetX = (osVersion >= 6) ? 0 : 10;
        int offsetY = (osVersion >= 6) ? 0 : 10;        

        CPoint cursorOffset(cursor.ptScreenPos.x - coords.x - offsetX, cursor.ptScreenPos.y - coords.y - offsetY);

        // Now draw the image of the cursor that we captured during
        // the mouse move. DrawIcon will draw a cursor as well.
        memDC.DrawIcon(cursorOffset, (HICON)cursor.hCursor);
    }
    memDC.SelectObject(oldbm);  

    Bitmap outputBitMap(bmp, NULL);

    // Optionally copy the image to the clipboard.
    if(programSettings.bWantClipboard)
    {
        if(OpenClipboard(NULL))
        {
            EmptyClipboard();
            SetClipboardData(CF_BITMAP, bmp);
            CloseClipboard();
        }
    }

    BOOL success = DumpImage(&outputBitMap, filename);

    DeleteObject(bmp.Detach());
    DeleteDC(dc.Detach());
    DeleteDC(memDC.Detach());
    return success;
}

Als Referenz: DumpImage verwendet ziemlich das Gdi :: Bitmap-Methode speichern. Es wurde verzichtet, weil es einige app-spezifischen Code hat, die nicht relevant für das Beispiel. Auch ein zusätzlicher Bonus ist, dass, wenn Sie sich fragen, wie Sie den Cursor in Ihrem Screengrab enthalten dann der Code auch da ist. Ich hoffe es hilft. Auch wert, im Gegensatz zu dem traditionellen Ansatz zu erwähnen, wird dies auch eine Windows-überzog Sie oben auf das aufgenommene Fenster haben könntest. Auch, wenn Sie diesen Code für die Vollbildaufnahmen verwenden, seien Sie gewarnt, dass es nicht Videospiel-Fenster erfassen. Ich frage mich wirklich, wie das zu tun, richtig, ohne zu DirectX zurückgreifen zu müssen. Dies betrifft nur Windows Vista / 7, wenn in Aero-Modus ausgeführt wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top