参考了其他博主的代码修改而成,直接上源代码吧:
#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 + ' '); // 输出结果 //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 ", "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; }
希望能帮助到你。