Search code examples
c++windowswindow

How can I show a window with the a name given as parameter in Windows in C++


I would like to make my software usable for Linux and Windows (Linux already works). Now I still need some functions so I can run the software on Windows, too.

I am currently trying to use the EnumWindows() function to get the window names and then show the window in the foreground (which matches the parameter).

static BOOL CALLBACK setWindowFocus(HWND hWnd, LPARAM lparam) {
    int length = GetWindowTextLength(hWnd);
    char* buffer = new char[length + 1];
    GetWindowText(hWnd, buffer, length + 1);
    std::string windowTitle(buffer);

    // List visible windows with a non-empty title
    if (IsWindowVisible(hWnd) && length != 0) {
        // Check if it is the right Windowshandle
        if ( windowTitle.compare(programname) == 0 ) <-- programname is a static variable
        {
            // Set application to the foreground
            SetForegroundWindow(hWnd);
        }
    }
    return TRUE;
}

Additionally, I used this to create the variable:

std::string programname;

And this to call it:

static void setWindowFocus(std::string programname)
{
    std::cout << "Setting focus to window." << std::endl;
    tempsavedProgramname=programname;
    EnumWindows(setWindowFocus, NULL);
}

That is working, as long as it is in main(). But, I would like to have it in an extra class with some other functions (I would like to remove the static variable too, if possible).

Is there a way I can use the EnumWindows() function with an anonymous function, or something?

Can I use something like this to pass a string to the function:

EnumWindows(setWindowFocus, reinterpret_cast<LPARAM>(stringvariable));

Or, are there other ways which I can try to reach my goal?

Includes which I used for the code:

Windows.h
winuser.h
string
iostream

I hope that I did not forgot one.


Solution

  • Yes, you can use the LPARAM to pass a string variable into your callback, eg:

    static BOOL CALLBACK setWindowFocus(HWND hWnd, LPARAM lparam) {
        std::string &programname = *reinterpret_cast<std::string*>(lparam);
    
        int length = GetWindowTextLength(hWnd);
        char* buffer = new char[length + 1];
        GetWindowText(hWnd, buffer, length + 1);
        std::string windowTitle(buffer);
        delete[] buffer; // <-- ADD THIS!
    
        /* I would use this instead:
        int length = GetWindowTextLength(hWnd);
        std::string windowTitle(length+1, '\0');
        windowTitle.resize(GetWindowText(hWnd, &windowTitle[0], length + 1));
        */
    
        // List visible windows with a non-empty title
        if (IsWindowVisible(hWnd) && (length != 0)) {
            // Check if it is the right Windowshandle
            if (windowTitle == programname)
            {
                // Set application to the foreground
                SetForegroundWindow(hWnd);
                return FALSE;
            }
        }
        return TRUE;
    }
    
    static void setWindowFocus(std::string programname)
    {
        std::cout << "Setting focus to window." << std::endl;
        EnumWindows(setWindowFocus, reinterpret_cast<LPARAM>(&programname));
    }
    

    And yes, you can use a C++11 lambda for the callback, rather than a static class method, but only if you use a non-capturing lambda, which is implicitly convertible to a function pointer (capturing lambdas are not). Fortunately, the LPARAM makes that a possibility, eg:

    static void setWindowFocus(std::string programname)
    {
        std::cout << "Setting focus to window." << std::endl;
        EnumWindows(
            [](HWND hWnd, LPARAM lparam) -> BOOL {
                std::string &programname = *reinterpret_cast<std::string*>(lparam);
                // ...
            },
            reinterpret_cast<LPARAM>(&programname)
        );
    }
    

    Now, that being said, there is a much simpler solution - since you already know the exact window text you are looking for, you can use FindWindow() instead of EnumWindows(), eg:

    static void setWindowFocus(std::string programname)
    {
        std::cout << "Setting focus to window." << std::endl;
        HWND hWnd = FindWindowA(NULL, programname.c_str());
        if (hWnd != NULL) {
            // Set application to the foreground
            SetForegroundWindow(hWnd);
        }
    }