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