本実装では、C++とWindows APIを使用して特定のウィンドウのスクリーンショットを取得します。CreateDIBSection関数により、アプリケーションが直接書き込めるデバイス非依存ビットマップ(DIB)を作成し、メモリ内のビットマップデータへのポインタを提供します。
PrintWindow関数はD3Dでレンダリングされるウィンドウ(ExcelやWindows 10のビデオプレイヤーなど)のキャプチャが可能です。通常のウィンドウをキャプチャする場合は、WindowsがD3Dで描画するウィンドウシャドウも含まれて取得されます。
1、WindowCaptureUtility.h
#pragma once
#include <windows.h>
#include <string>
class WindowCaptureUtility
{
public:
WindowCaptureUtility();
~WindowCaptureUtility();
bool Initialize(const std::string& targetWindowName);
bool Initialize(HWND windowHandle);
void ReleaseResources();
bool UpdateWindowInfo();
bool SwitchTargetWindow(const std::string& newWindowName);
bool SwitchTargetWindow(HWND newWindowHandle);
bool PerformCapture() const;
const RECT& GetWindowDimensions() const { return windowDimensions_; }
const RECT& GetClientDimensions() const { return clientDimensions_; }
int GetBitmapMemorySize() const { return bitmapMemorySize_; }
HBITMAP GetBitmapHandle() const { return bitmapHandle_; }
void* GetBitmapBuffer() const { return pixelBuffer_; }
private:
HWND targetWindow_;
HDC screenDC_;
HDC memoryDC_;
HBITMAP bitmapHandle_;
HBITMAP previousBitmap_;
void* pixelBuffer_;
RECT windowDimensions_;
RECT clientDimensions_;
int bitmapMemorySize_;
};
2、WindowCaptureUtility.cpp
#include "WindowCaptureUtility.h"
WindowCaptureUtility::WindowCaptureUtility()
: targetWindow_(nullptr)
, screenDC_(nullptr)
, memoryDC_(nullptr)
, bitmapHandle_(nullptr)
, previousBitmap_(nullptr)
, pixelBuffer_(nullptr)
, windowDimensions_{ 0, 0, 0, 0 }
, clientDimensions_{ 0, 0, 0, 0 }
, bitmapMemorySize_(0)
{
}
WindowCaptureUtility::~WindowCaptureUtility()
{
ReleaseResources();
}
bool WindowCaptureUtility::Initialize(const std::string& targetWindowName)
{
HWND windowHandle = ::FindWindowA(nullptr, targetWindowName.c_str());
if (windowHandle == nullptr)
return false;
return Initialize(windowHandle);
}
bool WindowCaptureUtility::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;
bitmapMemorySize_ = 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;
screenDC_ = ::GetWindowDC(targetWindow_);
memoryDC_ = ::CreateCompatibleDC(screenDC_);
bitmapHandle_ = ::CreateDIBSection(screenDC_, &bmpInfo, DIB_RGB_COLORS, &pixelBuffer_, nullptr, 0);
if (bitmapHandle_ == nullptr)
{
::DeleteDC(memoryDC_);
::ReleaseDC(targetWindow_, screenDC_);
return false;
}
previousBitmap_ = (HBITMAP)::SelectObject(memoryDC_, bitmapHandle_);
return true;
}
void WindowCaptureUtility::ReleaseResources()
{
if (bitmapHandle_ == nullptr)
return;
::SelectObject(memoryDC_, previousBitmap_);
::DeleteObject(bitmapHandle_);
::DeleteDC(memoryDC_);
::ReleaseDC(targetWindow_, screenDC_);
targetWindow_ = nullptr;
screenDC_ = nullptr;
memoryDC_ = nullptr;
bitmapHandle_ = nullptr;
previousBitmap_ = nullptr;
}
bool WindowCaptureUtility::UpdateWindowInfo()
{
HWND currentWindow = targetWindow_;
ReleaseResources();
return Initialize(currentWindow);
}
bool WindowCaptureUtility::SwitchTargetWindow(const std::string& newWindowName)
{
ReleaseResources();
return Initialize(newWindowName);
}
bool WindowCaptureUtility::SwitchTargetWindow(HWND newWindowHandle)
{
ReleaseResources();
return Initialize(newWindowHandle);
}
bool WindowCaptureUtility::PerformCapture() const
{
if (bitmapHandle_ == nullptr || memoryDC_ == nullptr || screenDC_ == nullptr)
return false;
BOOL result = ::PrintWindow(targetWindow_, memoryDC_, PW_CLIENTONLY | PW_RENDERFULLCONTENT);
return result != FALSE;
}