Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getting a specific window name in c++

Tags:

c++

windows

I use this code to get the window name:

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

However, it gets only the foreground window.

  1. I need to get all window names

  2. Or, actually, I need to get one specific window name which belongs to the "notepad.exe" process.

Thanks for your help :)

like image 348
Orhan Kurtulan Avatar asked Dec 25 '12 10:12

Orhan Kurtulan


2 Answers

Call EnumWindows. You supply a callback function that is called once for each top-level window. You can then check the properties of each window with your specific criterion. You can call GetWindowText and then check that against the value that you are looking for.

like image 41
David Heffernan Avatar answered Oct 02 '22 10:10

David Heffernan


I don't think there's really any easier way by using the raw winapi, but here goes:

  1. Use the Toolhelp32 API to get a list of process IDs whose executable names match "notepad.exe".
  2. Enumerate the windows to find any whose PID matches one in the list.
  3. Grab the title of that window and do what you will with it.

Here's the code I came up with:

#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);
    // Do use a proper RAII type for this so it's robust against exceptions and code changes.
    auto cleanupSnap = [snap] { CloseHandle(snap); };

    PROCESSENTRY32W entry;
    entry.dwSize = sizeof entry;

    if (!Process32FirstW(snap, &entry)) {
        cleanupSnap();
        return 0;
    }

    do {
        if (isNotepad(entry)) {
            pids.emplace_back(entry.th32ProcessID);
        }
    } while (Process32NextW(snap, &entry));
    cleanupSnap();

    EnumWindows(enumWindowsProc, reinterpret_cast<LPARAM>(&pids));
}

Going through in order:

First note the wide versions of functions and strings. TCHAR is not good to use and it would be a shame if one of the titles happened to have UTF-16 in it.

isNotepad just checks the executable name member of the PROCESSENTRY32W structure to see whether it equals "notepad.exe". This assumes Notepad uses this process name, and that nothing that isn't Notepad uses the process name. To eliminate false positives, you'd have to do more checking, but you can never be too sure.

In enumWindowsProc, take note that lParam is actually a pointer to a vector of PIDs (to save ourselves from having to use a global). This constitutes the cast at the beginning of the function. Next, we get the PID of the window we found. Then, we loop through the list of PIDs passed in and check whether it matches any. If it does, I chose to grab the title and output the PID and the window title. Note that using a standard string as a buffer is only guaranteed to work in C++11, and must not have the extra null character (not part of the length) overwritten. Lastly, we return TRUE so that it keeps enumerating until it has gone through every top-level window.

Onto main, the first thing you see is our initially empty list of PIDs. We take a snapshot of the processes and go through them. We use the helper function, isNotepad to check whether the process is "notepad.exe", and if so, store its PID. Lastly, we call EnumWindows to enumerate the windows, and pass in the list of PIDs, disguised as the required LPARAM.

It's a bit tricky if you haven't done this sort of thing, but I hope it makes sense. If you want the child windows, the correct thing to do would be to add a EnumChildWindowsProc and call EnumChildWindows with that in the spot where I output information about the found window. If I'm correct, you don't need to recursively call EnumChildWindows to get grandchildren etc., as they will be included in the first call.

like image 184
chris Avatar answered Oct 02 '22 10:10

chris