C++ 使用PrintWindow实现窗口截图功能

所属分类: 软件编程 / C 语言 阅读数: 57
收藏 0 赞 0 分享

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

需要注意的是,PrintWindow方法能够抓取使用D3D渲染的窗口(例如Excel、Win10自带视频播放器),如果抓取普通窗口则会附带窗口阴影,可见窗口阴影是Windows使用D3D渲染出来的。

1、PrintCaptureHelper.h

#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

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

以上就是C++ 使用PrintWindow实现窗口截图功能的详细内容,更多关于c++ 窗口截图的资料请关注脚本之家其它相关文章!

更多精彩内容其他人还在看

在C语言中对utmp文件进行查找和写入操作的函数小结

这篇文章主要介绍了在C语言中对utmp文件进行查找和写入操作的函数小结,包括pututline()函数和getutline()函数以及getutid()函数,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言编程中从密码文件获取数据的函数总结

这篇文章主要介绍了C语言编程中从密码文件获取数据的函数总结,包括getpw()函数和getpwnam()函数以及getpwuid()函数,需要的朋友可以参考下
收藏 0 赞 0 分享

在C语言编程中设置和获取代码组数的方法

这篇文章主要介绍了在C语言编程中设置和获取代码组数的方法,分别为setgroups()函数和getgroups()函数的使用,需要的朋友可以参考下
收藏 0 赞 0 分享

使用C语言操作文件的基本函数整理

这篇文章主要介绍了使用C语言操作文件的基本函数整理,包括创建和打开以及关闭文件的操作方法,需要的朋友可以参考下
收藏 0 赞 0 分享

简要对比C语言中的dup()函数和dup2()函数

这篇文章主要介绍了简要对比C语言中的dup()函数和dup2()函数,是C语言入门学习中的基础知识,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言中对文件最基本的读取和写入函数

这篇文章主要介绍了C语言中对文件最基本的读取和写入函数,是C语言入门学习中的基础知识,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言中lseek()函数和fseek()函数的使用详解

这篇文章主要介绍了C语言中lseek()函数和fseek()函数的使用详解,是C语言入门学习中的基础知识,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言新建临时文件和临时文件名的方法

这篇文章主要介绍了C语言新建临时文件和临时文件名的方法,分别是mkstemp()函数和mktemp()函数的使用,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言的getc()函数和gets()函数的使用对比

这篇文章主要介绍了C语言的getc()函数和gets()函数的使用对比,从数据流中一个是读取字符一个是读取字符串,需要的朋友可以参考下
收藏 0 赞 0 分享

简单对比C语言中的fputs()函数和fputc()函数

这篇文章主要介绍了简单对比C语言中的fputs()函数和fputc()函数,注意其之间的区别,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多