C++使用BitBlt進行窗口抓圖


本文使用C++雙緩存進行指定窗口截圖。CreateDIBSection創建應用程序可以直接寫入的、與設備無關的位圖(DIB),它提供內存中位圖的指針,外部程序可以直接使用。

需要注意的是,BitBlt方法只能抓圖普通窗口的截圖,對於使用D3D渲染的窗口(例如Excel、Win10自帶視頻播放器)則只能獲取黑屏。

1、DibCaptureHelper.h

#pragma once

#include <windows.h>
#include <string>
using std::string;

class DibCaptureHelper
{
public:
	DibCaptureHelper();
	virtual ~DibCaptureHelper();

	bool Init(const string& windowName);
	bool Init(HWND hwnd);
	void Cleanup();
	bool RefreshWindow();
	bool ChangeWindowHandle(const string& windowName);
	bool ChangeWindowHandle(HWND hwnd);
	bool Capture() const;

	const RECT& GetWindowRect() const { return windowRect_; }
	const RECT& GetClientRect() const { return clientRect_; }
	int GetBitmapDataSize() const { return bmpDataSize_; }
	HBITMAP GetBitmap() const { return bitmap_; }
	void* GetBitmapAddress() const { return bitsPtr_; }

private:
	HWND hwnd_;
	HDC scrDc_;
	HDC memDc_;
	HBITMAP bitmap_;
	HBITMAP oldBitmap_;
	void* bitsPtr_;

	RECT windowRect_;
	RECT clientRect_;
	POINT bitbltStartPoint_;
	int bmpDataSize_;
};

2、DibCaptureHelper.cpp

#include "stdafx.h"
#include "DibCaptureHelper.h"


DibCaptureHelper::DibCaptureHelper()
	: hwnd_(nullptr)
	, scrDc_(nullptr)
	, memDc_(nullptr)
	, bitmap_(nullptr)
	, oldBitmap_(nullptr)
	, bitsPtr_(nullptr)
	, windowRect_{ 0, 0, 0, 0 }
	, clientRect_{ 0, 0, 0, 0 }
	, bitbltStartPoint_{ 0,0 }
	, bmpDataSize_(0)
{
}


DibCaptureHelper::~DibCaptureHelper()
{
	Cleanup();
}

bool DibCaptureHelper::Init(const string& windowName)
{
	const auto handle = ::FindWindowA(nullptr, windowName.c_str());
	if (handle == nullptr)
	{
		return false;
	}

	return Init(handle);
}

bool DibCaptureHelper::Init(HWND hwnd)
{
	hwnd_ = hwnd;

	//獲取窗口大小
	if (!::GetWindowRect(hwnd_, &windowRect_) || !::GetClientRect(hwnd_, &clientRect_))
	{
		return false;
	}

	const auto clientRectWidth = clientRect_.right - clientRect_.left;
	const auto clientRectHeight = clientRect_.bottom - clientRect_.top;
	bmpDataSize_ = clientRectWidth * clientRectHeight * 4;

	bitbltStartPoint_.x = 0;
	bitbltStartPoint_.y = 0;

	//位圖信息
	BITMAPINFO bitmapInfo;
	bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo);
	bitmapInfo.bmiHeader.biWidth = clientRectWidth;
	bitmapInfo.bmiHeader.biHeight = clientRectHeight;
	bitmapInfo.bmiHeader.biPlanes = 1;
	bitmapInfo.bmiHeader.biBitCount = 32;
	bitmapInfo.bmiHeader.biSizeImage = clientRectWidth * clientRectHeight;
	bitmapInfo.bmiHeader.biCompression = BI_RGB;

	scrDc_ = ::GetWindowDC(hwnd_); //獲取窗口DC
	memDc_ = ::CreateCompatibleDC(scrDc_); //緩沖內存DC
	bitmap_ = ::CreateDIBSection(memDc_, &bitmapInfo, DIB_RGB_COLORS, &bitsPtr_, nullptr, 0);
	if (bitmap_ == nullptr)
	{
		::DeleteDC(memDc_);
		::ReleaseDC(hwnd_, scrDc_);
		return false;
	}

	oldBitmap_ = static_cast<HBITMAP>(::SelectObject(memDc_, bitmap_));
	return true;
}

void DibCaptureHelper::Cleanup()
{
	if (bitmap_ == nullptr)
	{
		return;
	}

	//刪除用過的對象
	::SelectObject(memDc_, oldBitmap_);
	::DeleteObject(bitmap_);
	::DeleteDC(memDc_);
	::ReleaseDC(hwnd_, scrDc_);

	hwnd_ = nullptr;
	scrDc_ = nullptr;
	memDc_ = nullptr;
	bitmap_ = nullptr;
	oldBitmap_ = nullptr;
	bitsPtr_ = nullptr;
}

bool DibCaptureHelper::RefreshWindow()
{
	const auto hwnd = hwnd_;
	Cleanup();
	return Init(hwnd);
}

bool DibCaptureHelper::ChangeWindowHandle(const string& windowName)
{
	Cleanup();
	return Init(windowName);
}

bool DibCaptureHelper::ChangeWindowHandle(HWND hwnd)
{
	Cleanup();
	return Init(hwnd);
}

bool DibCaptureHelper::Capture() const
{
	if (bitmap_ == nullptr || memDc_ == nullptr || scrDc_ == nullptr)
	{
		return false;
	}

	const auto clientRectWidth = clientRect_.right - clientRect_.left;
	const auto clientRectHeight = clientRect_.bottom - clientRect_.top;

	const auto ret = ::BitBlt(
		memDc_, 0, 0, clientRectWidth, clientRectHeight,
		scrDc_, bitbltStartPoint_.x, bitbltStartPoint_.y,
		SRCCOPY);
	return ret != 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM