Getting a list of all open windows in c++ and storing them

16,394

Solution 1

The second parameter (lParam) to EnumWindows is documented as:

An application-defined value to be passed to the callback function.

Just pass your container to the API call:

int main() {
    std::vector<std::wstring> titles;
    EnumWindows(speichereFenster, reinterpret_cast<LPARAM>(&titles));
    // At this point, titles if fully populated and could be displayed, e.g.:
    for ( const auto& title : titles )
        std::wcout << L"Title: " << title << std::endl;
    cin.get();
    return 0;
}

And use it in your callback:

BOOL CALLBACK speichereFenster(HWND hwnd, LPARAM lParam){
    const DWORD TITLE_SIZE = 1024;
    WCHAR windowTitle[TITLE_SIZE];

    GetWindowTextW(hwnd, windowTitle, TITLE_SIZE);

    int length = ::GetWindowTextLength(hwnd);
    wstring title(&windowTitle[0]);
    if (!IsWindowVisible(hwnd) || length == 0 || title == L"Program Manager") {
        return TRUE;
    }

    // Retrieve the pointer passed into this callback, and re-'type' it.
    // The only way for a C API to pass arbitrary data is by means of a void*.
    std::vector<std::wstring>& titles =
                              *reinterpret_cast<std::vector<std::wstring>*>(lParam);
    titles.push_back(title);

    return TRUE;
}

Notes:

  • The code presented uses a std::wstring in place of std::string. This is necessary so that the entire character set can be represented.
  • As written, the code isn't correct. There are (invisible) code paths, that have no well-defined meaning. The Windows API is strictly exposed as a C interface. As such, it doesn't understand C++ exceptions. Particularly with callbacks it is vital to never let C++ exceptions travel across unknown stack frames. To fix the code apply the following changes:
    • [C++11 only] Mark the callback noexcept.
    • Wrap the entire callback inside a try-catch block, and handle any exceptions appropriately.
    • [C++11 only] With C++11 you can pass C++ exceptions across unknown stack frames, by passing a std::exception_ptr, and calling std::rethrow_exception at the call site.

Solution 2

Simple code to get all visible windows with non empty title

for (HWND hwnd = GetTopWindow(NULL); hwnd != NULL; hwnd = GetNextWindow(hwnd, GW_HWNDNEXT))
{   

    if (!IsWindowVisible(hwnd))
        continue;

    int length = GetWindowTextLength(hwnd);
    if (length == 0)
        continue;

    char* title = new char[length+1];
    GetWindowText(hwnd, title, length+1);

    if (title == "Program Manager")
        continue;

    std::cout << "HWND: " << hwnd << " Title: " << title << std::endl;

}
Share:
16,394
marco56
Author by

marco56

Updated on June 04, 2022

Comments

  • marco56
    marco56 almost 2 years

    I'm currently trying to get a list of all opened windows and storing them inside a vector. I've been looking at the code so much that the solution could be very easy but I don't seem to get it done without a global variable (which I want to avoid).

    Here is the code:

    #include "stdafx.h"
    #include "json.h"
    #include <algorithm>  
    
    using namespace std;
    vector<string> vec;
    
    
    BOOL CALLBACK speichereFenster(HWND hwnd, LPARAM substring){
        const DWORD TITLE_SIZE = 1024;
        TCHAR windowTitle[TITLE_SIZE];
    
        GetWindowText(hwnd, windowTitle, TITLE_SIZE);
        int length = ::GetWindowTextLength(hwnd);
    
        wstring temp(&windowTitle[0]);
        string title(temp.begin(), temp.end());
    
    
    
        if (!IsWindowVisible(hwnd) || length == 0 || title == "Program Manager") {
            return TRUE;
        }
    
        vec.push_back(title);
    
        return TRUE;
    }
    
    int main() {
        EnumWindows(speichereFenster, NULL);
        cin.get();
        return 0;
    }
    

    I want to store all titles in the vector but I don't know how as I can't pass the vector into the function...

    Thanks!!!

    • Richard Critten
      Richard Critten about 7 years
      Pass the address of the vector through lParam (2nd parameter) and cast it back inside the callback. You will need to use the reinterpret_cast hammer
    • David Heffernan
      David Heffernan about 7 years
      Pass a pointer to your data in the second argument of EnumWindows
    • IInspectable
      IInspectable about 7 years
      wstring temp(&windowTitle[0]); string title(temp.begin(), temp.end()); - Despite your assumption, this is no character encoding conversion. It's a data trashing device. And needless, too. Just use wide character strings throughout your Windows application.
    • Stevoisiak
      Stevoisiak over 5 years
    • Admin
      Admin over 5 years
      I'm going to disagree with saying that using a C-style method in C++ is a sin. Many people falsy claim that reinterpret_cast is the proper way to cast in C++, this is factually incorrect. C programming styles are well defined under the C++ specification and the best practice is to use the method with less typing. ASCII in C++ is not a sin, in fact I utilize retro computer mimicry techniques modeled after biomimicry in order to create easier to understand next-generation systems. My Unicode handling is done through other faster mechanisms.
    • Admin
      Admin over 5 years
      Your logical fallacy stems from undeserved trust in the C++ std library developer's code. At this point, I've replaced most of their code, and I've managed to optimize almost everything to run faster with less ROM and compile rapidly. I went from about a minute to compile the SDK core, down to 5 seconds after replacing their junk code. I even have optional dynamic memory running on an infinite cache; we're talking a major spanking. #DeleteBoost
  • zett42
    zett42 about 7 years
    Could be improved by allocating windowTitle dynamically instead of restricting it to 1023 chars.
  • IInspectable
    IInspectable about 7 years
    @zett42: There are one bazillion ways this code could be improved. I concentrated on answering the question: "How do I pass data to my callback and back?"
  • IInspectable
    IInspectable about 7 years
    @MarcoVogt: The 'conversion' from wchar_t to char is not a conversion. It's a destructive operation, and it won't preserve the initial data. One quarter of the code units are unaffected, another quarter are re-interpreted, in an undesirable way, and the remaining half just gets thrown out. If you are working with the Windows API, use wide character string everywhere (UTF-16). If you need to interface with the outside world (files, network sockets, serving web pages), convert to an appropriate character encoding, e.g. UTF-8.
  • Stevoisiak
    Stevoisiak over 5 years
    @zett42 How would you allocate windowTitle dynamically?
  • zett42
    zett42 over 5 years
    @StevenVascellaro For instance: std::wstring title( length, L'\0' );
  • kayleeFrye_onDeck
    kayleeFrye_onDeck almost 5 years
    Just a reminder, if you see a way to improve an answer that doesn't reduce the current answer's clarity then submit an edit. However, I have to wonder what the heck you're going to need with 1000+ chars for the window's title...
  • IInspectable
    IInspectable almost 5 years
    @kay: I believe the motivation behind that comment was, that, as written, the code usually overallocates memory. It's a tradeoff, though. Allocating 2048 bytes on the stack is cheap, usually even free, whereas heap allocations are among the most expensive operations we commonly perform. On the other hand, while there is usually abundant heap memory available, stack memory is limited to 1MB by default (when using Visual Studio). That said, there is one vital improvement to be made, to make the code correct.
  • IInspectable
    IInspectable about 2 years
    if (title == "Program Manager") never evaluates to true.