4

C ++で、ウィンドウハンドルを指定して、別のアプリケーションのスクリーンショットを撮るコードを書いています。私が使用している方法は、を使用することBitBltです。私のアプリケーションはスクリーンショットを正常に取得しており、その画像データをbmpファイルに保存する機能があります。

ただし、スクリーンショットにはウィンドウのクロムが含まれています。つまり、境界線とタイトルバーです。私の理解に基づいてGetClientRect、ウィンドウの境界線とタイトルバーを除外することになっています。GetWindowRectこれは、ユーザーのデスクトップ内の座標をGetClientRect返し、アプリケーション自体に関連する座標を返すことを理解しています。

スクリーンショットで、タイトルバーと左側の境界線は表示されていますが、アプリケーションの右側の境界線と下部が切り取られていることに気付きました。したがって、タイトルと境界線を除外する場合は、との何らかの組み合わせを行う必要がありGetWindowRectGetClientRectウィンドウ自体に関する情報を使用してGetClientRect、ウィンドウのタイトルバーの高さによって寸法をオフセットする必要があると考えています。 、 例えば。

これは正確に聞こえますか、それとも以下の私のコードは何か間違っていますか?

#include <Windows.h>
#include "ScreenshotManager.h"

namespace Managers {

    ScreenshotManager::ScreenshotManager(HWND gameHandle) {

        // get a device context for the window
        m_gameContext = GetWindowDC(gameHandle);

        // create a compatible device context for bitblt
        m_bitmapContext = CreateCompatibleDC(m_gameContext);

        // get window client area dimensions
        GetClientRect(gameHandle, &m_gameClientArea);

    }

    bool ScreenshotManager::TakeScreenshot() {

        // create a compatible bitmap for the game screenshots
        m_bitmap = CreateCompatibleBitmap(m_gameContext, m_gameClientArea.right, m_gameClientArea.bottom);

        // select the bitmap into the compatible device context
        SelectObject(m_bitmapContext, m_bitmap);

        // perform bit block transfer
        if (BitBlt(m_bitmapContext, 0, 0, m_gameClientArea.right, m_gameClientArea.bottom, m_gameContext, 0, 0, SRCCOPY) == false)
            return false;

        // get information about the taken screenshot
        GetObject(m_bitmap, sizeof(BITMAP), &m_bitmapInformation);

        return true;

    }

    void ScreenshotManager::SaveScreenshot(LPCWSTR outputPath) {

        BITMAPFILEHEADER   bmfHeader;    
        BITMAPINFOHEADER   bi;

        bi.biSize = sizeof(BITMAPINFOHEADER);
        bi.biWidth = m_bitmapInformation.bmWidth;
        bi.biHeight = m_bitmapInformation.bmHeight;
        bi.biPlanes = 1;    
        bi.biBitCount = 32;    
        bi.biCompression = BI_RGB;    
        bi.biSizeImage = 0;  
        bi.biXPelsPerMeter = 0;    
        bi.biYPelsPerMeter = 0;    
        bi.biClrUsed = 0;    
        bi.biClrImportant = 0;

        DWORD dwBmpSize = ((m_bitmapInformation.bmWidth * bi.biBitCount + 31) / 32) * 4 * m_bitmapInformation.bmHeight;

        // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that 
        // call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc 
        // have greater overhead than HeapAlloc.
        HANDLE hDIB = GlobalAlloc(GHND,dwBmpSize);
        char *lpbitmap = (char *)GlobalLock(hDIB);

        // Gets the "bits" from the bitmap and copies them into a buffer which is pointed to by lpbitmap.
        GetDIBits(m_gameContext, m_bitmap, 0, (UINT)m_bitmapInformation.bmHeight, lpbitmap, (BITMAPINFO *)&bi, DIB_RGB_COLORS);

        // A file is created, this is where we will save the screen capture.
        HANDLE hFile = CreateFile(outputPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);   

        // Add the size of the headers to the size of the bitmap to get the total file size
        DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

        //Offset to where the actual bitmap bits start.
        bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER); 

        //Size of the file
        bmfHeader.bfSize = dwSizeofDIB; 

        //bfType must always be BM for Bitmaps
        bmfHeader.bfType = 0x4D42; //BM   

        DWORD dwBytesWritten = 0;
        WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
        WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
        WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);

        //Unlock and Free the DIB from the heap
        GlobalUnlock(hDIB);    
        GlobalFree(hDIB);

        //Close the handle for the file that was created
        CloseHandle(hFile);

    }

}
4

1 に答える 1

9

GetClientRect()境界線とタイトルバーは含まれません。クライアントエリアの寸法を教えてくれるだけです。

BitBlt()あるデバイスコンテキストから別のデバイスコンテキストにピクセルの長方形領域をコピーします。この例では、ソースDCはウィンドウDCであるため、原点座標はそのウィンドウを基準にしています。

コードが実行しているのは、ウィンドウの原点からクライアントサイズの長方形をコピーすることです。(そのため、右端と下端が失われます。)

AdjustWindowRectEx()コピーする領域の座標を特定するのに役立つ場合があります。

于 2012-06-16T21:45:19.470 に答える