C++使用PrintWindow进行窗口抓图
本文使用C++双缓存进行指定窗口截图。CreateDIBSection创建应用程序可以直接写入的、与设备无关的位图(DIB),它提供内存中位图的指针,外部程序可以直接使用。
需要注意的是,PrintWindow方法能够抓取使用D3D渲染的窗口(例如Excel、Win10自带视频播放器),如果抓取普通窗口则会附带窗口阴影,可见窗口阴影是Windows使用D3D渲染出来的。
1、PrintCaptureHelper.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 | #pragma once #include <windows.h> #include <string> using std::string; class PrintCaptureHelper { public : PrintCaptureHelper(); virtual ~PrintCaptureHelper(); 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_; int bmpDataSize_; }; |
2、PrintCaptureHelper.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 | #include "stdafx.h" #include "PrintCaptureHelper.h" PrintCaptureHelper::PrintCaptureHelper() : hwnd_( nullptr ) , scrDc_( nullptr ) , memDc_( nullptr ) , bitmap_( nullptr ) , oldBitmap_( nullptr ) , bitsPtr_( nullptr ) , windowRect_{ 0, 0, 0, 0 } , clientRect_{ 0, 0, 0, 0 } , bmpDataSize_(0) { } PrintCaptureHelper::~PrintCaptureHelper() { Cleanup(); } bool PrintCaptureHelper::Init( const string& windowName) { const auto handle = ::FindWindowA( nullptr , windowName.c_str()); if (handle == nullptr ) { return false ; } return Init(handle); } bool PrintCaptureHelper::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; //位图信息 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_); memDc_ = ::CreateCompatibleDC(scrDc_); bitmap_ = ::CreateDIBSection(scrDc_, &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 PrintCaptureHelper::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 ; } bool PrintCaptureHelper::RefreshWindow() { const auto hwnd = hwnd_; Cleanup(); return Init(hwnd); } bool PrintCaptureHelper::ChangeWindowHandle( const string& windowName) { Cleanup(); return Init(windowName); } bool PrintCaptureHelper::ChangeWindowHandle( HWND hwnd) { Cleanup(); return Init(hwnd); } bool PrintCaptureHelper::Capture() const { if (bitmap_ == nullptr || memDc_ == nullptr || scrDc_ == nullptr ) { return false ; } const auto ret = ::PrintWindow(hwnd_, memDc_, PW_CLIENTONLY | PW_RENDERFULLCONTENT); return ret != 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库