Windows APIを使用したビットマップキャプチャの実装

Windows APIのBitBlt関数を活用して、指定ウィンドウのスクリーンショットを取得する方法を解説します。この手法ではCreateDIBSectionを使用して、アプリケーションが直接書き込めるDIB(デバイス非依存ビットマップ)を作成します。

1、DibCaptureHelper.h

#pragma once

#include <windows.h>
#include <string>

class WindowBitmapCapturer
{
public:
    WindowBitmapCapturer();
    ~WindowBitmapCapturer();

    bool Initialize(const std::string& targetWindow);
    bool Initialize(HWND windowHandle);
    void ReleaseResources();
    bool UpdateWindowInfo();
    bool SwitchTargetWindow(const std::string& newWindow);
    bool SwitchTargetWindow(HWND newHandle);
    bool PerformCapture() const;

    const RECT& GetWindowDimensions() const { return windowDimensions_; }
    const RECT& GetClientDimensions() const { return clientDimensions_; }
    int GetBitmapBufferSize() const { return bitmapBufferSize_; }
    HBITMAP GetBitmapHandle() const { return bitmapHandle_; }
    void* GetBitmapBuffer() const { return pixelBuffer_; }

private:
    HWND targetWindow_;
    HDC screenContext_;
    HDC memoryContext_;
    HBITMAP bitmapHandle_;
    HBITMAP previousBitmap_;
    void* pixelBuffer_;

    RECT windowDimensions_;
    RECT clientDimensions_;
    POINT captureStartPoint_;
    int bitmapBufferSize_;
};

2、DibCaptureHelper.cpp

#include "DibCaptureHelper.h"

WindowBitmapCapturer::WindowBitmapCapturer()
    : targetWindow_(nullptr)
    , screenContext_(nullptr)
    , memoryContext_(nullptr)
    , bitmapHandle_(nullptr)
    , previousBitmap_(nullptr)
    , pixelBuffer_(nullptr)
    , windowDimensions_{}
    , clientDimensions_{}
    , captureStartPoint_{}
    , bitmapBufferSize_(0)
{
}

WindowBitmapCapturer::~WindowBitmapCapturer()
{
    ReleaseResources();
}

bool WindowBitmapCapturer::Initialize(const std::string& targetWindow)
{
    const auto windowHandle = FindWindowA(nullptr, targetWindow.c_str());
    return windowHandle ? Initialize(windowHandle) : false;
}

bool WindowBitmapCapturer::Initialize(HWND windowHandle)
{
    targetWindow_ = windowHandle;

    if (!GetWindowRect(targetWindow_, &windowDimensions_) || 
        !GetClientRect(targetWindow_, &clientDimensions_))
    {
        return false;
    }

    const int width = clientDimensions_.right - clientDimensions_.left;
    const int height = clientDimensions_.bottom - clientDimensions_.top;
    bitmapBufferSize_ = width * height * 4;

    BITMAPINFO bmpInfo{};
    bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmpInfo.bmiHeader.biWidth = width;
    bmpInfo.bmiHeader.biHeight = height;
    bmpInfo.bmiHeader.biPlanes = 1;
    bmpInfo.bmiHeader.biBitCount = 32;
    bmpInfo.bmiHeader.biCompression = BI_RGB;

    screenContext_ = GetWindowDC(targetWindow_);
    memoryContext_ = CreateCompatibleDC(screenContext_);
    bitmapHandle_ = CreateDIBSection(memoryContext_, &bmpInfo, DIB_RGB_COLORS, &pixelBuffer_, nullptr, 0);

    if (!bitmapHandle_)
    {
        ReleaseResources();
        return false;
    }

    previousBitmap_ = (HBITMAP)SelectObject(memoryContext_, bitmapHandle_);
    return true;
}

bool WindowBitmapCapturer::PerformCapture() const
{
    if (!bitmapHandle_ || !memoryContext_ || !screenContext_)
        return false;

    const int width = clientDimensions_.right - clientDimensions_.left;
    const int height = clientDimensions_.bottom - clientDimensions_.top;

    return BitBlt(memoryContext_, 0, 0, width, height,
                 screenContext_, captureStartPoint_.x, captureStartPoint_.y,
                 SRCCOPY) != 0;
}

void WindowBitmapCapturer::ReleaseResources()
{
    if (!bitmapHandle_) return;

    SelectObject(memoryContext_, previousBitmap_);
    DeleteObject(bitmapHandle_);
    DeleteDC(memoryContext_);
    ReleaseDC(targetWindow_, screenContext_);

    targetWindow_ = nullptr;
    screenContext_ = nullptr;
    memoryContext_ = nullptr;
    bitmapHandle_ = nullptr;
    previousBitmap_ = nullptr;
    pixelBuffer_ = nullptr;
}

タグ: WindowsAPI BitBlt スクリーンキャプチャ CreateDIBSection

5月11日 22:51 投稿