• C++使用PrintWindow进行窗口抓图


    本文使用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;
    }
  • 相关阅读:
    js菜单特效分享(1)
    用泛型的IEqualityComparer接口去重复项 .
    jquery一些有用的插件
    JQuery Tree插件——zTree v3.0 beta 发布
    泛型和linq
    js如何隐藏表格的行与列
    34个漂亮的应用程序后台管理界面
    解决Visual Studio setup cannot run in compatibility mode的错误
    html文本框(input)不保存缓存记录
    第九章:第九章:XML文档集成Axd向导
  • 原文地址:https://www.cnblogs.com/xhubobo/p/12565475.html
Copyright © 2020-2023  润新知