我使用这个代码来获取窗口名称:
#include <Windows.h> #include <stdio.h> int main() { TCHAR title[500]; int i=0; while(i<10) { GetWindowText(GetForegroundWindow(), title, 500); printf("%s\n",title); i++; system("pause"); } }
但是,它只获取前景窗口。
我需要得到所有的窗口名称
或者,实际上,我需要得到一个属于“notepad.exe”进程的特定窗口名称。
谢谢你的帮助 :)
我不认为使用原始winapi真的有更简单的方法,但是这里有:
这里是我提出的代码:
#include <iostream> #include <string> #include <vector> #include <windows.h> #include <tlhelp32.h> bool isNotepad(const PROCESSENTRY32W &entry) { return std::wstring(entry.szExeFile) == L"notepad.exe"; } BOOL CALLBACK enumWindowsProc(HWND hwnd, LPARAM lParam) { const auto &pids = *reinterpret_cast<std::vector<DWORD>*>(lParam); DWORD winId; GetWindowThreadProcessId(hwnd, &winId); for (DWORD pid : pids) { if (winId == pid) { std::wstring title(GetWindowTextLength(hwnd) + 1, L'\0'); GetWindowTextW(hwnd, &title[0], title.size()); //note: C++11 only std::cout << "Found window:\n"; std::cout << "Process ID: " << pid << '\n'; std::wcout << "Title: " << title << "\n\n"; } } return TRUE; } int main() { std::vector<DWORD> pids; HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32W entry; entry.dwSize = sizeof entry; if (!Process32FirstW(snap, &entry)) { return 0; } do { if (isNotepad(entry)) { pids.emplace_back(entry.th32ProcessID); } } while (Process32NextW(snap, &entry)); EnumWindows(enumWindowsProc, reinterpret_cast<LPARAM>(&pids)); }
按顺序浏览:
首先注意功能和字符串的广泛版本。 TCHAR
不好用,如果其中一个标题碰巧有UTF-16,那就太遗憾了。
isNotepad
只是检查PROCESSENTRY32W
结构的可执行名称成员,以查看它是否等于“notepad.exe”。 这假定记事本使用这个进程名称,并且没有记事本没有使用进程名称。 为了消除误报,你必须做更多的检查,但你永远不能太确定。
在enumWindowsProc
,需要注意的是lParam
实际上是一个指向PID矢量的指针(为了避免使用全局)。 这构成了功能开始时的角色。 接下来,我们得到我们找到的窗口的PID。 然后,我们遍历传入的PID列表,并检查它是否匹配任何。 如果是这样,我选择抓住标题并输出PID和窗口标题。 请注意,使用标准字符串作为缓冲区只能保证在C ++ 11中工作,并且不得有覆盖的额外空字符(不是长度的一部分)。 最后,我们返回TRUE
以便继续枚举,直到它经历了每个顶层窗口。
main
,你首先看到的是我们最初的PID列表。 我们对流程进行快照并通过它们。 我们使用辅助函数isNotepad
检查进程是否为“notepad.exe”,如果是,则存储其PID。 最后,我们调用EnumWindows
枚举窗口,并传入PID列表,伪装成所需的LPARAM
。
如果你还没有做这样的事,这有点棘手,但我希望这是有道理的。 如果你想要子窗口,正确的做法是添加一个EnumChildWindowsProc
并在那里输出关于找到的窗口的信息的位置调用EnumChildWindows
。 如果我是正确的,你不需要递归地调用EnumChildWindows
来获取孙子们等等,因为它们将被包含在第一个调用中。
调用EnumWindows
。 您为每个顶级窗口提供一次调用的回调函数。 然后,您可以使用您的特定标准检查每个窗口的属性。 你可以调用GetWindowText
然后检查你正在寻找的值。
你问,
“我需要得到一个属于”notepad.exe“进程的特定窗口名称”
那么,C ++是这个任务的错误语言。 脚本编写更自然简单。 例如,下面是一个Windows批处理文件,报告所有记事本窗口的标题:
@echo off for /f "usebackq delims=, tokens=1,9" %%t in (`tasklist /v /fo csv`) do ( if %%t=="notepad.exe" echo %%u )
使用示例:
[d:\ dev的\杂项\所以\ notepad_window_name] > 标题 “无标题 - 记事本” [d:\ dev的\杂项\所以\ notepad_window_name] > _
另外,除了语言选择之外,还要考虑到你的C ++代码通过使用TCHAR
类型进行广告,它可以被编译为Unicode和ANSI,但是由于使用了printf
它不能被编译为Unicode。 这意味着这个愚蠢的TCHAR
误导你引入了一个bug。 简单地不要使用T
东西,如TCHAR
:它只是一种混淆代码和引入错误的方法。
以下代码示例说明如何创建一个仅限Unicode的程序。
与批处理文件相比,这只能检索一个记事本窗口的标题:
#include <iostream> // std::wcout, std::endl #include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS #include <string> // std::wstring using namespace std; #define UNICODE #include <windows.h> int main() { HWND const window = FindWindow( L"Notepad", nullptr ); if( window == 0 ) { wcerr << "!Didn't find any Notepad window." << endl; } else { int const nAttempts = 3; for( int i = 1; i <= nAttempts; ++i ) { int const bufferSize = 1 + GetWindowTextLength( window ); wstring title( bufferSize, L'\0' ); int const nChars = GetWindowText( window, &title[0], bufferSize ); if( nChars == 0 || nChars < GetWindowTextLength( window ) ) { Sleep( 20 ); continue; } title.resize( nChars ); wcout << "'" << title << "'" << endl; return EXIT_SUCCESS; } wcerr << "!Found a Notepad window but unable to obtain the title." << endl; } return EXIT_FAILURE; }
所以,C ++是错误的语言选择, TCHAR
是完全错误的数据类型选择。
如果由于某种原因你确实需要C ++代码,而且你需要所有的记事本窗口标题,那么这个批处理文件将不会执行,而上面的C ++代码将不会执行。 在这种情况下,请使用David Hefferman建议的Windows EnumWindows
API函数。 为了避免混淆,微妙的错误和误导读者的代码,使用基于wchar_t
的字符串,而不是TCHAR
,如上面的代码所示。