C++使用BitBlt进行窗口抓图
本文使用C++双缓存进行指定窗口截图。CreateDIBSection创建应用程序可以直接写入的、与设备无关的位图(DIB),它提供内存中位图的指针,外部程序可以直接使用。
需要注意的是,BitBlt方法只能抓图普通窗口的截图,对于使用D3D渲染的窗口(例如Excel、Win10自带视频播放器)则只能获取黑屏。
1、DibCaptureHelper.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | #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; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器