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

原文链接: https://www.cnblogs.com/xhubobo/p/12561887.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    C++使用BitBlt进行窗口抓图

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/337262

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月1日 下午11:04
下一篇 2023年3月1日 下午11:04

相关推荐