首页 > 系统相关 >C++调用opencv和windows api完成桌面窗口截图——以梦幻西游为例

C++调用opencv和windows api完成桌面窗口截图——以梦幻西游为例

时间:2023-12-12 15:15:19浏览次数:36  
标签:窗口 为例 windows hwnd C++ height width WindowShot rect

目录

程序简介

项目编写的C++程序,根据输入的字符串,遍历所有桌面窗口标题,查找包含该标题的窗口,对该桌面窗口进行截图,以梦幻西游为例

输入:桌面窗口包含的字符串 比如输入“梦幻”,程序就会截取桌面“梦幻西游”的窗口

输出:该桌面窗口的截图,数据类型为opencv的Mat矩阵

show

程序/数据集下载

点击进入下载地址

本文章只发布于博客园爆米算法CSDN,被抄袭后可能排版错乱或下载失效,作者:爆米LiuChen

代码环境、文件结构

VS2019 注意链接器需要加入dwmapi.lib,用来调用windows的API的

opencv4.5.5

show1

show2

show3

代码分析

FindWindow.h声明了查找和定位窗口的函数,定义解析请看下文

#pragma once
#include <dwmapi.h>
#include <windows.h> 
#include <vector> 
#include <string>  
#include <iostream>

struct WindowData;

BOOL CALLBACK WindowEnumerationCallback(HWND hwnd, LPARAM lParam);

HWND getWindowHWND(std::string titleSection);

RECT getWindowLoc(HWND hwnd);

FindWindow.cpp中核心函数getWindowHWND可以根据输入的窗口标题字符串,定位到含有该字符串的窗口,返回窗口句柄HWND,然后将句柄输入getWindowLoc函数,得到窗口的位置,这里调用了windows api DwmGetWindowAttribute,如果用传统的方法GetWindowRect会得到错误的结果,因为传统方法没考虑到桌面缩放且自windows vista后的系统桌面窗口加入了“毛玻璃边缘”效果,得到的窗口位置会有偏移

#include "FindWindow.h"

struct WindowData {
    HWND handle;//窗口句柄
    char title[256];//窗口标题
};

std::vector<WindowData> windowDatas;

// 声明回调函数  
BOOL CALLBACK WindowEnumerationCallback(HWND hwnd, LPARAM lParam) {
    // 通过IsWindow函数检查窗口是否有效  
    if (IsWindow(hwnd)) {
        // 通过IsWindowEnabled函数检查窗口是否启用  
        if (IsWindowEnabled(hwnd)) {
            // 通过IsWindowVisible函数检查窗口是否可见  
            if (IsWindowVisible(hwnd)) {
                // 获取窗口的文本,并打印  
                char windowText[256];
                GetWindowTextA(hwnd, windowText, sizeof(windowText));
                WindowData windowData;
                windowData.handle = hwnd;
                memcpy(windowData.title, windowText, 256);
                windowDatas.push_back(windowData);
            }
        }
    }
    // 继续枚举其他窗口  
    return TRUE;
}

//返回包含titleSection的桌面窗口句柄
HWND getWindowHWND(std::string titleSection)
{
    HWND handle = NULL;
    //每次都要清空容器
    windowDatas.clear();
    // 使用EnumWindows函数枚举所有窗口,并传递给回调函数处理  
    EnumWindows(WindowEnumerationCallback, NULL);
    //一个个找包含指定字符串的
    for (auto it = windowDatas.begin(); it != windowDatas.end(); it++)
    {
        char title[256];
        memcpy(title, it->title, 256);
        std::string windowTitle(title);
        if (windowTitle.find(titleSection) != std::string::npos)
        {
            handle = it->handle;
        }
    }
    return handle;
}


//根据窗口句柄和桌面缩放获得窗口尺寸和位置
RECT getWindowLoc(HWND hwnd)
{
    RECT frame;
    DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &frame, sizeof(RECT));
    //std::cout << "窗口位置:(" << frame.left << ", " << frame.top << ")" << std::endl;
    //std::cout << "窗口大小:(" << frame.right-frame.left << ", " << frame.bottom-frame.top << ")" << std::endl;
    return frame;
}

WindowShot.h声明了根据坐标和尺寸的截图函数,定义解析请看下文

#pragma once
#include "FindWindow.h"
#include <opencv2/opencv.hpp>

struct WindowRect
{
    int x;
    int y;
    int width;
    int height;
};

class WindowShot
{
public:
    WindowShot();
    double static getZoom();
    cv::Mat getWindowMat(std::string titleSection);
    uchar* getWindowUchar(std::string titleSection);
    WindowRect windowRect;
    cv::Mat getDesktopMat();
    ~WindowShot();

private:
    int width;
    int height;
    double zoom;
    uchar* windowUchar;
    RECT rect;
    HDC screenDC;
    HDC compatibleDC;
    HBITMAP hBitmap;
    LPVOID shotData;
    HWND hwnd;
};

WindowShot.cpp定义了核心函数getWindowMat,该函数会调用FindWindow模块来查找窗口的句柄和位置,然后对整个屏幕具体的位置进行截图,当然同时也定义了getDesktopMat函数用来截图整个桌面,不同的是这个函数用到了个人桌面缩放率

#include "WindowShot.h"

//初始化变量
WindowShot::WindowShot()
{
    zoom = getZoom();//缩放率 比如1.25
}


//根据窗口标题是否包含该字符串,获得窗口截图
cv::Mat WindowShot::getWindowMat(std::string titleSection)
{
    hwnd = getWindowHWND(titleSection);
    //如果窗口小化 就将其展示 
    if (IsIconic(hwnd)) {
        ShowWindow(hwnd, SW_RESTORE);
    }
    SetForegroundWindow(hwnd); // 将窗口置顶  
    rect = getWindowLoc(hwnd); // 窗口位置
    width = rect.right - rect.left;
    height = rect.bottom - rect.top;
    windowRect.x = rect.left;
    windowRect.y = rect.top;
    windowRect.width = width;
    windowRect.height = height;
    shotData = new char[width * height * 4];
    screenDC = GetDC(NULL);// 获取屏幕 DC
    compatibleDC = CreateCompatibleDC(screenDC);//兼容新DC
    // 创建位图
    hBitmap = CreateCompatibleBitmap(screenDC, width, height);
    SelectObject(compatibleDC, hBitmap);
    // 得到位图的数据
    BitBlt(compatibleDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY);
    GetBitmapBits(hBitmap, width * height * 4, shotData);
    // 创建图像
    cv::Mat windowMat(height, width, CV_8UC4, shotData);
    return windowMat;
}

//根据窗口标题是否包含该字符串,获得窗口截图 将截图转为uchar* 供python使用
uchar* WindowShot::getWindowUchar(std::string titleSection)
{
    cv::Mat windowMat = this->getWindowMat(titleSection);
    int size = width * height * 4;
    free(windowUchar);
    windowUchar = (uchar*)malloc(sizeof(uchar) * size);
    memcpy(windowUchar, windowMat.data, size);
    return windowUchar;
}

cv::Mat WindowShot::getDesktopMat()
{
    width = GetSystemMetrics(SM_CXSCREEN) * zoom;
    height = GetSystemMetrics(SM_CYSCREEN) * zoom;
    rect.left = 0;
    rect.top = 0;
    rect.right = width;
    rect.bottom = height;
    width = rect.right - rect.left;
    height = rect.bottom - rect.top;
    shotData = new char[width * height * 4];
    screenDC = GetDC(NULL);// 获取屏幕 DC
    compatibleDC = CreateCompatibleDC(screenDC);//兼容新DC
    // 创建位图
    hBitmap = CreateCompatibleBitmap(screenDC, width, height);
    SelectObject(compatibleDC, hBitmap);
    // 得到位图的数据
    BitBlt(compatibleDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY);
    GetBitmapBits(hBitmap, width * height * 4, shotData);
    // 创建图像
    cv::Mat desktopMat(height, width, CV_8UC4, shotData);
    return desktopMat;
}

/* 获取屏幕缩放值 */
double WindowShot::getZoom()
{
    // 获取窗口当前显示的监视器
    HWND hWnd = GetDesktopWindow();
    HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);

    // 获取监视器逻辑宽度
    MONITORINFOEX monitorInfo;
    monitorInfo.cbSize = sizeof(monitorInfo);
    GetMonitorInfo(hMonitor, &monitorInfo);
    int cxLogical = (monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left);

    // 获取监视器物理宽度
    DEVMODE dm;
    dm.dmSize = sizeof(dm);
    dm.dmDriverExtra = 0;
    EnumDisplaySettings(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &dm);
    int cxPhysical = dm.dmPelsWidth;

    return cxPhysical * 1.0 / cxLogical;
}

WindowShot::~WindowShot()
{
    DeleteObject(hBitmap);
    DeleteDC(compatibleDC);
}

结果展示

运行一下main.cpp,得到梦幻西游的窗口截图(文章开头已给出),对比下整个桌面截图

desktop


标签:窗口,为例,windows,hwnd,C++,height,width,WindowShot,rect
From: https://www.cnblogs.com/boom-meal/p/17896946.html

相关文章

  • C++ 用 std::get<> 访问元组
     C++ 用std::get<>访问元组 #include<iostream>#include<tuple>intmain(){//Creatingatuplestd::tuple<int,double,std::string>myTuple(42,3.14,"Hello");//Accessingelementsusingstd::get<>......
  • C++(using namespace std;)
    usingnamespacestd;是C++中的一条指令,用于指示编译器使用标准命名空间std中的所有标识符。这意味着在代码中可以直接使用标准库中的各种类、函数和对象,而无需在每个标识符前面添加std::前缀。以下是关于这条指令的一些解释:using关键字:using是一个关键字,用于创建别......
  • C++连点器
     功能这个连点器可以提升你的CPS值,它可以让你的每一次点击变成好多次,左键右键均可。 要求它调用了"windos.h"函数库(Windows系统自带函数库)以及"bits/stdc++.h"函数库(C++拓展函数),若无法使用"bits.stdc++.h"函数库的,可以将其替换为"iostream.h"函数库和"cstdio.h"......
  • C++(std::vector)
    这段代码定义了一个std::vector对象,该对象的元素类型为float。std::vector是C++标准库中的动态数组容器,可以存储多个元素,并且大小可以动态调整。std::vector<float>具体解释如下:std::vector:这是C++标准库中的一个模板类,用于实现动态数组。std::vector是一个模板类,......
  • Windows:定时关机任务
    点击Win键+R打开运行,输入下面的代码:shutdown-s-t9000其中9000是时间,单位为秒,这段代码的意思是,注册一个9000秒(两个半小时)后关机的任务,运行成功后会有如下显示:如果你需要取消关机任务,请输入:shutdown-a如果成功,会显示下面的图片......
  • C++( get()方法、->、*)
    在C++中,指针是一种强大的工具,用于处理内存和访问数据。以下是一些与指针相关的基本概念和操作符:解引用运算符*:用于访问指针指向的内存地址处的值。例如,如果有一个指针int*ptr,则*ptr将返回指针所指向地址的整数值。intx=10;int*ptr=&x;std::cout<<*ptr;/......
  • 在当前的Linux上并安装字体(这里以安装中文字体为例)
    一、如果你想手动上传并安装中文字体,可以按照以下步骤进行:1.下载中文字体文件。你可以在网上找到许多免费的中文字体,例如文泉驿正黑字体。请确保你下载的字体文件是合法和可信的。 我本地提前准备好了,都是TrueType类型中文字体,具体如下(仿宋、宋体、黑体等): 2.将字体文件......
  • windowserver2012服务器部署.net core3.1环境
    一、安装.netcore3.1要先具备这些系统补丁,如果没有则需要安装,这些KB必须按以下顺序安装:(clearcompressionflag.exe、KB2919442、KB2919355、KB2932046、KB2959977、KB2937592、KB2938439、KB2934018)安装过程中需要多次重启生效。最后安装vc_redist.x64.exe)二、.netcore3.......
  • 《Function Programming in C++》
    说明《FunctionalProgramminginC++》书中代码练习测试以及一些笔记,部分代码需要用到C++20可以使用在线编译器编译代码地址:https://coliru.stacked-crooked.com/或者自己编译gcc-11.2及以上版本安装1介绍1.1什么是函数式编程用常用的函数范式模板代替一些循环等,比如std......
  • Unreal C++自定义Actor设置StaticMesh和Material
    1.新建第三人称c++游戏(其它模板开局也可以的)2.新建继承自Actor的c++类3.添加静态网格体成员SM_MyActor,并在构造函数中进行相应的初始化UCLASS()classMYPROJECT9S_APIAMyActor:publicAActor{GENERATED_BODY()protected:/**Pleaseaddavariabledescripti......