一个查找窗口和子窗口的MFC类

参考了其他博主的代码修改而成,直接上源代码吧:

#pragma once
#include "MfcStrFile.h"

//标题中包含szWindTitle的窗口
bool FindWindowTitle(const char* szWindTitle, HWND& wDstHWnd, const char* szWindClass = nullptr);
bool FindSubWindowTitle(const char* szWindTitle, HWND& wHWndParent, HWND& wDstHWnd, const char* szWindClass = nullptr);

class CMonitorWindow
{
public:
    CMonitorWindow(){}
    bool MonitorWindowClose(HWND& wHWnd, DWORD dwMilliseconds = INFINITE);

private:
    static void CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime );
    static UINT WaitWorker(LPVOID lParam);

private:
    static HANDLE g_hEvent;
    static DWORD g_nWaitRes;
};

然后是cpp文件:

#include "FindWindowTitle.h"
#include "tlhelp32.h"
#include <vector>
#include "Log.h"

#pragma region 依赖

typedef struct EnumHWndsArg
{
    std::vector<HWND> *vecHWnds;
    DWORD dwProcessId;
}EnumHWndsArg, *LPEnumHWndsArg;

// 判断窗口是否属于目标进程
BOOL CALLBACK lpEnumFunc(HWND hwnd, LPARAM lParam)
{
    EnumHWndsArg *pArg = (LPEnumHWndsArg)lParam;
    DWORD  processId;

    // 检索窗口线程标识符
    GetWindowThreadProcessId(
        hwnd,            // 窗口句柄
        &processId        // 接收 PID 的指针
        );

    // 如果这个 HWND 属于这个 PID ,则加入到 vecHWnds 数组末尾
    if (processId == pArg->dwProcessId){pArg->vecHWnds->push_back(hwnd);}

    return TRUE;
}

// 根据 PID 获取 HWND
void GetHWndsByProcessID(DWORD processID, std::vector<HWND> &vecHWnds)
{
    EnumHWndsArg wi;
    wi.dwProcessId = processID;
    wi.vecHWnds = &vecHWnds;

    // 枚举所有顶级窗口
    EnumWindows(
        lpEnumFunc,        // 回调函数指针
        (LPARAM)&wi        // 传递给回调函数的值
        );
}

#pragma endregion


bool FindWindowTitle(const char* szWindTitle, HWND& wDstHWnd, const char* szWindClass /*= nullptr*/)
{
    HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    PROCESSENTRY32 process = {sizeof(PROCESSENTRY32)};
    
    // 遍历进程
    while (Process32Next(hProcessSnap,&process))
    {
        std::string processName = process.szExeFile;        // 进程名
        std::vector<HWND> vecHWnds;                    // 进程下的窗体句柄数组
        GetHWndsByProcessID(process.th32ProcessID,vecHWnds);
        
        // 获取 HWND 窗口标题、窗口类名
        TCHAR szBuf_title[MAX_PATH];
        TCHAR szBuf_class[MAX_PATH];
        size_t nWindCount = vecHWnds.size();
        for (size_t i = 0; i < nWindCount; ++i)
        {
            const HWND &h = vecHWnds[i];
            GetWindowText(
            h,                    // 窗口句柄
            szBuf_title,        // 接收窗口标题的缓冲区指针
            MAX_PATH            // 缓冲区字节大小
            );
            GetClassName(
            h,                    // 窗口句柄
            szBuf_class,        // 接收窗口类名的缓冲区指针
            MAX_PATH            // 缓冲区字节大小
            );

            std::string stBuftitle(szBuf_title);
            std::string stWindTitle(szWindTitle);

            if (szWindClass == nullptr)
            {
                //只考虑标题
                if (stBuftitle.find(szWindTitle) != std::string::npos)
                {
                    wDstHWnd = h;
                    return true;
                }
            }
            else
            {
                //同时考虑标题和类名
                if (stBuftitle.find(szWindTitle) != std::string::npos && strcmp(szBuf_class, szWindClass) == 0)
                {
                    wDstHWnd = h;
                    return true;
                }
            }

            //TRACE(szBuf_title + ' ');
            //TRACE(szBuf_class + '\n');
            
            // 输出结果    
            //cout << "szBuf_title = " << szBuf_title << endl;
            //cout << "szBuf_class = " << szBuf_class << endl;
            //cout << "--------------------------------------------" << endl;
        }
    }
    
    return false;
}

bool FindSubWindowTitle(const char* szWindTitle, HWND& wHWndParent, HWND& wDstHWnd, const char* szWindClass /*= nullptr*/)
{
    if (wHWndParent == nullptr)
    {
        return false;
    }

    HWND childWindow = GetWindow(wHWndParent, GW_CHILD);

    TCHAR szBuf_title[MAX_PATH];
    TCHAR szBuf_class[MAX_PATH];

    int nWindowCount = 1;

    while (childWindow)
    {
        const HWND &h = childWindow;
        GetWindowText(
            h,                    // 窗口句柄
            szBuf_title,        // 接收窗口标题的缓冲区指针
            MAX_PATH            // 缓冲区字节大小
            );
        GetClassName(
            h,                    // 窗口句柄
            szBuf_class,        // 接收窗口类名的缓冲区指针
            MAX_PATH            // 缓冲区字节大小
            );

        std::string stBuftitle(szBuf_title);
        std::string stWindTitle(szWindTitle);
        CLOG::Out(_T("%d %s"), nWindowCount, szBuf_title);
        CLOG::Out(_T("%d %s"), nWindowCount++, szBuf_class);

        if (szWindClass == nullptr)
        {
            //只考虑标题
            if (stBuftitle.find(szWindTitle) != std::string::npos)
            {
                wDstHWnd = h;
                return true;
            }
        }
        else
        {
            //同时考虑标题和类名
            if (stBuftitle.find(szWindTitle) != std::string::npos && strcmp(szBuf_class, szWindClass) == 0)
            {
                wDstHWnd = h;
                return true;
            }
        }

        childWindow = GetNextWindow(childWindow, GW_HWNDNEXT);
    }

    return false;
}

HANDLE CMonitorWindow::g_hEvent;
DWORD CMonitorWindow::g_nWaitRes;

//传递参数
typedef struct _lPara
{
    HWND pDoc;
    DWORD dTimeout;
}lPara;

//定时器
void CALLBACK CMonitorWindow::TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime )
{
    TRACE("TimerProc");
    SetEvent(g_hEvent);
}

UINT  CMonitorWindow::WaitWorker(LPVOID  lParam)
{
    DWORD dTimeout = 6000;
    HWND hWnd = nullptr;

    if (lParam)
    {
        lPara* lp = (lPara*)lParam;
        dTimeout = lp->dTimeout;
        hWnd = lp->pDoc;
    }

    //启动定时器1,定时时间是1秒,注意SetTimer在线程中设置无效
    //SetTimer(hWind, 1, 1000, (TIMERPROC)TimerProc);//用回调函数处理,此时对话框的消息处理函数不再处理。

    for(;;)
    {
        TRACE("%s, %d\n", "monitoring...", hWnd);
        if (!::IsWindow(hWnd) || !::IsWindowVisible(hWnd))
        {
            TRACE("window closed!");
            SetEvent(g_hEvent);
            break;
        }

        Sleep(1000);

        if (WAIT_TIMEOUT == g_nWaitRes)
        {
            break;
        }
    }

    //KillTimer(nullptr, 1);

    return 0;
}

bool CMonitorWindow::MonitorWindowClose(HWND& wHWnd, DWORD dwMilliseconds /*= INFINITE*/)
{
    if (wHWnd == nullptr)
    {
        return true;
    }

    //默认等待失败
    g_nWaitRes = WAIT_FAILED;

    lPara lp;
    lp.pDoc = wHWnd;
    lp.dTimeout = dwMilliseconds;

    //创建等待事件
    g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    AfxBeginThread(WaitWorker, (LPVOID)&lp);//启动新的线程

    g_nWaitRes = WaitForSingleObject(g_hEvent, dwMilliseconds);

    switch (g_nWaitRes)
    {
    case WAIT_OBJECT_0:
        TRACE("wait success!");
        break;

    case WAIT_TIMEOUT:
        TRACE("wait timeout!");
        break;

    case WAIT_FAILED:
        TRACE("wait failed!");
        //函数调用失败,比如传递了一个无效的句柄
        break;
    }

    ResetEvent(g_hEvent);

    return g_nWaitRes == WAIT_OBJECT_0;
}

希望能帮助到你。

posted @ 2020-07-03 14:30  秋月的私语  阅读(730)  评论(0编辑  收藏  举报