在c ++中获取特定的窗口名称

我使用这个代码来获取窗口名称:

#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"); } } 

但是,它只获取前景窗口。

  1. 我需要得到所有的窗口名称

  2. 或者,实际上,我需要得到一个属于“notepad.exe”进程的特定窗口名称。

谢谢你的帮助 :)

我不认为使用原始winapi真的有更简单的方法,但是这里有:

  1. 使用Toolhelp32 API获取可执行文件名称与“notepad.exe”匹配的进程ID列表。
  2. 枚举窗口来查找任何一个PID匹配列表中的一个。
  3. 抓住那个窗口的标题,做你想做的事情。

这里是我提出的代码:

 #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]
 > _

如何编写现代的Unicode C ++ Windows程序。

另外,除了语言选择之外,还要考虑到你的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 ++代码,而且你需要所有的记事本窗口标题,那么这个批处理文件将不会执行,而上面的C ++代码将不会执行。 在这种情况下,请使用David Hefferman建议的Windows EnumWindows API函数。 为了避免混淆,微妙的错误和误导读者的代码,使用基于wchar_t的字符串,而不是TCHAR ,如上面的代码所示。