6

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!!!

marco56
  • 165
  • 1
  • 2
  • 11
  • 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 – Richard Critten Mar 03 '17 at 22:29
  • Pass a pointer to your data in the second argument of EnumWindows – David Heffernan Mar 03 '17 at 22:29
  • `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. – IInspectable Mar 03 '17 at 22:40
  • Related: [How can I get EnumWindows to list all windows?](https://stackoverflow.com/q/10246444/3357935) – Stevoisiak Aug 07 '18 at 15:51
  • 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. –  Aug 29 '18 at 15:42
  • 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 –  Aug 29 '18 at 15:46

2 Answers2

13

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.
IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • Could be improved by allocating `windowTitle` dynamically instead of restricting it to 1023 chars. – zett42 Mar 03 '17 at 23:04
  • 3
    @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 Mar 03 '17 at 23:12
  • @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. – IInspectable Mar 03 '17 at 23:30
  • @zett42 How would you allocate `windowTitle` dynamically? – Stevoisiak Aug 02 '18 at 19:23
  • @StevenVascellaro For instance: `std::wstring title( length, L'\0' );` – zett42 Aug 02 '18 at 23:11
  • 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_... – kayleeFrye_onDeck Apr 26 '19 at 14:56
  • 1
    @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 Apr 26 '19 at 20:07
7

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;

}
gil123
  • 512
  • 6
  • 12