Winapi Getwindowtext as String

I was wondering if it were possible to take text input from a text box (CreateWindowEx "EDIT") and store it as a string or even better a vector

I need to have a textbox that the user can enter or paste text and when I click a button it will alphabetize the words and count unique words etc...

so far I have it reading it in as characters (i dont know how to make it a string) and alphabetizes the characters

so if I type in: how now brown cow it will output: bchnnoooorwwww instead of: brown cow how now

my code under the WM_COMMAND case is

int length;
length = GetWindowTextLength(textbox) + 1;
vector<wchar_t> list(length);
GetWindowText(textbox, &list[0], length);
wstring stxt = &list[0];
wstring str(stxt);
sort(str.begin(), str.end());
SetWindowText(sortedOutput, &str[0]);
10

3 Answers

This answer may be of use to you in devising a solution. I don't really know of one that is not hacky, but it can be done casting of the constness of c_string() from std::string.

A std::string's allocation is not guaranteed to be contiguous under the C++98/03 standard, but C++11 forces it to be. In practice, neither I nor Herb Sutter know of an implementation that does not use contiguous storage.

Notice that the &s[0] thing is always guaranteed to work by the C++11 standard, even in the 0-length string case. It would not be guaranteed if you did str.begin() or &*str.begin(), but for &s[0] the standard defines operator[] as:

Returns: *(begin() + pos) if pos < size(), otherwise a reference to an object of type T with value charT(); the referenced value shall not be modified Continuing on, data() is defined as:

Returns: A pointer p such that p + i == &operator for each i in [0,size()]. (notice the square brackets at both ends of the range)

Thus it follows you can do something like this:

int len = GetWindowTextLength(hwnd) + 1;
std::string s;
s.reserve(len);
GetWindowText(hwnd, const_cast<char*>(s.c_str()), len - 1);

Which is pretty ugly. Welcome any more "correct" answers, though.

Regarding when unicode is enabled on your build, you have to use a wstring or equivalent. Testing that out just a moment ago, this works:

std::wstring title;
title.reserve(GetWindowTextLength(m_window_handle) + 1);
GetWindowText(m_window_handle, const_cast<WCHAR *>(title.c_str()), title.capacity());

In general, regarding the windows api its useful to google their all caps typedefs and figure out what they really are.

Regarding splitting strings, std::string isn't particular good at this kind of manipulation. This is where std::stringstream (or wstringstream for unicode) comes in handy. I am fairly certain stringstream is not guaranteed to be contiguous in memory, so you can't really go around writing directly into its buffer.

// Initialize a stringstream so we can extract input using >> operator
std::wstringstream ss;
ss.str(title);

// Make a vector, so we can store our words as we're extracting them
// and so we can use sort later, which works on many stl containers
std::vector<std::wstring> words;
std::wstring word;

// This will evaluate to false and thus end the loop when its done
// reading the string word by word
while(ss >> word)
{
  words.push_back(word);
}

Then proceed with your sorting, but on the new vector words.

12

Your problem is not a winapi problem. While not the only way, you found a solution to transfer a string back and forth to your edit box.

How to turn that string into a list/vector of strings, with words being the elements of that list/vector is in fact an STL problem.

Basically, you are looking for the C++ equivalent of the C# function String.Split().

And there is already a good question and answer for that, here:

Most elegant way to split a string?

So, all you have to do is a sort of round trip:

  1. Get string from TextBox
  2. Convert string to a std::vector<string>, using your split function (see the other question for how to do that).
  3. Sort the vector in the usual way.
  4. Convert the vector back to a string, which is the inverse of your split function (Hint: std::ostringstream).
  5. Set the resulting string as the text of your TextBox.

Depending on your preferences regarding multi character strings and globalization, you might decide to stick to the ASCII versions at first. On windows, you can compile to MBCS or ASCII. The respective string types are then respectively (TCHAR and LPCTSTR or WCHAR and LPCWSTR or CHAR and LPCSTR). All win32 functions come in two flavors, distinguished by a trailing A or W at the end of the function name, respectively.

AFAIK, while there is std::string and std::wstring, there is no standard implementation for std::basic_string<TCHAR>, which would work along with your compile options.

As for the window handling, here some code example (snippets):

In InitInstance(), I created the dialog (IDD_FORMVIEW) with my input edit box, my button and my static output area as a child window of the main application window:

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    hInst = hInstance; // Store instance handle in our global variable

    HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

    HWND hWndChild = CreateDialogW(hInstance, MAKEINTRESOURCE(IDD_FORMVIEW), hWnd, dlgProc);
    if (NULL == hWndChild)
    {
        DWORD lastError = GetLastError();
        wchar_t msg[100];
        swprintf_s(msg, _countof(msg), L"error code: 0x%0X\n", lastError);
        OutputDebugString(msg);

    }
    if (!hWnd)
    {
        return FALSE;
    }
    ShowWindow(hWnd, nCmdShow);
    ShowWindow(hWndChild, SW_SHOW);
    UpdateWindow(hWnd);

    return TRUE;
}

CreateDialogW() takes as the last parameter a pointer to the dialog handler function, which is called dlgProc() in this example.

This is how that dlgProc() function looks like:

// Message handler for our menu which is a child window of the main window, here.
static INT_PTR CALLBACK dlgProc(
    _In_ HWND   hwndDlg,
    _In_ UINT   uMsg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
)
{
    BOOL processed = false;

    switch (uMsg)
    {
    case WM_INITDIALOG:
        break;
    case WM_NOTIFY:
        break;
    case WM_COMMAND:
    {
        auto sourceId = LOWORD(wParam);
        auto code = HIWORD(wParam);
        if (IDC_BUTTON1 == sourceId)
        {
            if (BN_CLICKED == code)
            {
                wchar_t text[1024];
                GetDlgItemText(hwndDlg, IDC_EDIT1, text, _countof(text));
                // TODO: do your string processing here (string -> string)
                SetDlgItemText(hwndDlg, IDC_STATIC, text);
                processed = TRUE;
            }
        }
    }
        break;
    default: 
        break;
    }
    return processed;
}
3

I have just mixed a few lines of code to convert wchar_t to wstring to std::string. Here you go!

string GetWindowStringText(HWND hwnd)
{
    int len = GetWindowTextLength(hwnd) + 1;
    vector<wchar_t> buf(len);
    GetWindowText(hwnd, &buf[0], len);
    wstring wide = &buf[0];
    string s(wide.begin(), wide.end());
    return s;
}

This has a vector so you'll need to include it.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Sarah Jenkins

Sarah Jenkins

Senior Technology Editor & AI Specialist

Sarah Jenkins is a veteran tech journalist with over 12 years of experience covering artificial intelligence, mobile innovations, and digital ethics. Her insights have appeared in leading technology publications worldwide.

Share this article
Twitter Facebook Pinterest