简体   繁体   中英

Is it possible to store text input from a Win32 EDIT control in a C++ std::string?

I have recently downloaded DevC++ and I am now programming a Windows API program in C++, where I have put a TextBox input control and an OK button to show the text input in a MessageBox() .

Here's a small snippet:

HWND TextBox;
char txtStore[200];

/*WM_CREATE*/
TextBox = CreateWindow("edit", "",
    WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL,
    0 ,30 ,500 ,20 ,
    hwnd, (HMENU) 0, NULL, NULL
    ); /* Text Input field */

CreateWindow("button", "Go",
    WS_VISIBLE | WS_CHILD,
    500 ,30 ,100 ,20 ,
    hwnd, (HMENU) 2, NULL, NULL
    ); /* Button 8/

/*WM_COMMAND*/

if(LOWORD(wParam)==2){
    GetWindowText(TextBox,&txtStore[0],200);
    MessageBox(0,txtStore,"Title",0);
}

How do I save the input into std::string txtStore; instead of char txtStore[200]; ?

For implementations guaranteeing that characters are stored continuously (C++11 and up) you can get text directly into std::wstring .

// UNICODE build - prefered
int potential_length = GetWindowTextLengthW( hwnd )
std::wstring text;
// Theoretically, some implementations can keep internal buffer not NUL terminated
// Allocate one character more just to be safe
text.resize( potential_length + 1 );
int final_length = GetWindowTextW( hwnd, &text[0], potential_length + 1 );
text.resize( final_length );

If you are learning Windows API or writing new software, you definitely should prefer UNICODE builds over ANSI builds. This forces you to use wstring instead of string , wchar_t instead of char , but it saves you from many problems with untranslatable characters (not all UNICODE characters can be represented by current code page), internal API conversions (API has to repeatedly convert strings from narrow to wide characters and other way round).

Yo can save yourself from some traps if you define project wide macros UNICODE and _UNICODE and remove MBCS if it is defined somewhere. You can do this probably in options dialog with field named "additional defines" or something like this. If you don't know how to configure additional macros, defining them just before including <windows.h> header can be acceptable.

#define UNICODE
#define _UNICODE
#include <windows.h>

If you insist on using string and char , here it is.

// ANSI build - obsolete, use only if you have to
// You will lose characters untranslatable into current code page
int potential_length = GetWindowTextLengthA( hwnd );
std::string text;
// Theoretically, some implementations can keep internal buffer not NUL terminated
// Allocate one character more just to be safe
text.resize( potential_length + 1 );
int final_length = GetWindowTextA( hwnd, &text[0], potential_length + 1 );
text.resize( final_length );

Older C++ standards disallow modifying internal string data. You could use some intermediate buffer defined on stack, obtained with new wchar_t[] or as I prefer with std::vector .

// UNICODE build - preferred
int potential_length = GetWindowTextLengthW( hwnd );
std::vector<wchar_t> buff;
buff.resize( potential_length + 1 );
int final_length = GetWindowTextW( hwnd, buff.data(), potential_length + 1 );
std::wstring text( buff.data(), final_length );
// ANSI build - obsolete, use only if you have to
// You will lose characters untranslatable into current code page
int potential_length = GetWindowTextLengthA( hwnd );
std::vector<char> buff;
buff.resize( potential_length + 1 );
int final_length = GetWindowTextA( hwnd, buff.data(), potential_length + 1 );
std::string text( buff.data(), final_length );

If compiler doesn't support buff.data() , use &buff[0] .


Error handling

On error GetWindowTextLengthW returns 0, so to check error you would need to SetLastError(0) before calling it and check GetLastError() result after call. GetWindowTextW on error returns 0 and checking must be done with same steps. This is because 0 is valid text length.

SetLastError( 0 );
int potential_length = GetWindowTextLengthW( hwnd );
if ( potential_length == 0 )
{
    DWORD error = GetLastError();
    if ( error != 0 )
    {
        // Handle error here. Throw exception, log message, display dialog etc.
        // Most probably hwnd handle is invalid.
        return;
    }
}
std::wstring text;
// Theoretically, some implementations can keep internal buffer not NUL terminated
// Allocate one character more just to be safe
text.resize( potential_length + 1 );
SetLastError( 0 );
int final_length = GetWindowTextW( hwnd, &text[0], potential_length + 1 );
if ( final_length == 0 )
{
    DWORD error = GetLastError();
    if ( error != 0 )
    {
        // Handle error here. Throw exception, log message, display dialog etc.
        // Most probably hwnd handle is invalid or belongs to another process.
        return;
    }
}
text.resize( final_length );

+ 1 and length manipulation explanation

Additional + 1 covers quirks of the Windows API where some API calls take into account trailing NUL characters, and some don't. This is the case with GetWindowTextLengthW which returns length of text without NUL character, but last parameter in GetWindowTextW needs to state buffer size including place for NUL character. If we omit + 1 buffer would contain one character less because API have to put NUL character.

Documentation states also that GetWindowTextLength can return value few character larger (I think it applies mostly to GetWindowTextLengthA variant). This explains length correction, because only after GetWindowTextW we know true length.


Over-allocating string space

Most string implementations which keep string characters continuously also add NUL character at end to simplify c_str() and data() handling, but taking C++11 standard literally, they don't have to. Because GetWindowText always puts NUL character at end, for implementations that do not keep additional space for NUL character permanently it could overwrite some internal data.

Although

text.resize( potential_length );

could work, resizing string one character more

text.resize( potential_length + 1 );

will cover these implementations. This has a cost of always resizing text latter to smaller length and unnecessary allocation if we cross string inline storage size.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM