1. 程式人生 > 程式設計 >C++使用BitBlt進行視窗抓圖的方法

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 },clientRect_{ 0,bitbltStartPoint_{ 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_,clientRectWidth,clientRectHeight,scrDc_,bitbltStartPoint_.x,bitbltStartPoint_.y,SRCCOPY);
return ret != 0;
}

以上就是C++使用BitBlt進行視窗抓圖的方法的詳細內容,更多關於c++ 視窗抓圖的資料請關注我們其它相關文章!