C++使用BitBlt函数进行窗口抓图的示例代码

xhubobo 2024-12-19 10:27:18编程技术
107

本文使用C++双缓存进行指定窗口截图。CreateDIBSection创建应用程序可以直接写入的、与设备无关的位图(DIB),它提供内存中位图的指针,外部程序可以直接使用。

需要注意的是,BitBlt方法只能抓图普通窗口的截图,对于使用D3D渲染的窗口(例如Excel、Win10自带视频播放器)则只能获取黑屏。

C++.jpg

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

总结

通过对C++使用BitBlt函数进行窗口抓图的详细解析,我们了解了整个抓图过程的步骤和关键点。BitBlt函数可以将一个设备上下文的内容复制到另一个设备上下文中,从而实现屏幕或窗口的抓图。本文提供的示例代码展示了如何在C++中使用BitBlt函数进行窗口抓图,并处理了一些常见的错误和异常情况。通过本文的学习,开发者可以掌握在C++中使用BitBlt函数进行窗口抓图的方法,提高图像处理的效率和质量。希望本文的内容能为读者在实际项目中提供有价值的参考和帮助。无论是处理用户界面的截图,还是实现自动化测试工具,本文的示例代码和方法都能为开发者提供有效的解决方案。

C++ bitblt
THE END
蜜芽
故事不长,也不难讲,四字概括,毫无意义。

相关推荐

C++函数模板(Template)基础知识讲解
在C++编程中,函数模板(Template)提供了一种强大的工具,使得程序员能够编写出通用的函数代码,从而避免了重复定义相同逻辑的函数。函数模板不仅提高了代码的复用性,还增强了...
2024-12-20 编程技术
106

C++ Vector 容器常见用法详解:从基础到高级
在现代编程中,容器是不可或缺的一部分,它们使得数据的存储、管理和操作变得更加高效和便捷。C++中的Vector容器作为标准模板库(STL)的一部分,因其动态数组的特性而广受欢...
2024-12-20 编程技术
104

C++11中std::bind使用方法详解
C++11引入了许多新特性,其中std::bind是一个非常有用的工具,它可以将函数对象与其参数绑定在一起,形成一个新的可调用对象。这在回调函数、事件处理和函数组合等场景中非常...
2024-12-18 编程技术
113

microsoft visual c++可以卸载吗?microsoft visual c++卸载方法详解
Microsoft Visual C++(以下简称 “VC++”)是一组重要的软件开发工具和运行库。然而,有时候我们可能会考虑卸载 VC++,可能是因为磁盘空间不足、软件冲突或者其他原因。那么,...
2024-10-09 电脑知识
203

VS Code上搭建C/C++开发环境图文详解
Visual Studio Code (VS Code) 是一款轻量级但功能强大的源代码编辑器,它支持多种编程语言,并通过扩展提供了丰富的开发工具。本文将详细讲解如何在 VS Code 上搭建一个高效...
2024-07-11 编程技术
143

C++首度超越C语言,荣登TIOBE编程语言排行榜亚军宝座
2024年6月,全球编程语言社区迎来了一个历史性时刻。根据TIOBE编程社区指数的最新数据,C++语言在受欢迎程度上首次超越了C语言,以10.03%的占比位居排行榜第二,而C语言则以9...
2024-06-11 新闻资讯
97