简体   繁体   English

是否可以将来自Win32 EDIT控件的文本输入存储在C ++ std :: string中?

[英]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() . 我最近下载了DevC ++,现在正在用C ++编写Windows API程序,在其中放置了一个TextBox输入控件和一个OK按钮,以在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; 如何将输入保存到std::string txtStore; instead of char txtStore[200]; 而不是char txtStore[200]; ?

For implementations guaranteeing that characters are stored continuously (C++11 and up) you can get text directly into std::wstring . 对于保证字符连续存储(C ++ 11及更高版本)的实现,您可以将文本直接放入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. 如果您正在学习Windows API或编写新软件,则绝对应该选择UNICODE构建而不是ANSI构建。 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). 这迫使您使用wstring代替string ,用wchar_t代替char ,但是它使您避免了不可翻译字符的问题(并非所有UNICODE字符都可以由当前代码页表示),内部API转换(API必须反复从窄到宽字符以及其他方式)。

Yo can save yourself from some traps if you define project wide macros UNICODE and _UNICODE and remove MBCS if it is defined somewhere. 如果您定义了项目范围的宏UNICODE_UNICODE并且可以删除MBCS如果在某些地方定义了),则_UNICODE陷入陷阱。 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. 如果您不知道如何配置其他宏,可以在包含<windows.h>标头之前定义它们。

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

If you insist on using string and char , here it is. 如果您坚持使用stringchar ,那就是。

// 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. 较旧的C ++标准不允许修改内部字符串数据。 You could use some intermediate buffer defined on stack, obtained with new wchar_t[] or as I prefer with std::vector . 您可以使用在堆栈上定义的一些中间缓冲区,该缓冲区是通过new wchar_t[]或我更喜欢的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] . 如果编译器不支持buff.data() ,请使用&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. 发生错误时, GetWindowTextLengthW返回0,因此要检查错误,需要在调用它之前设置SetLastError(0) ,并在调用后检查GetLastError()结果。 GetWindowTextW on error returns 0 and checking must be done with same steps. 发生错误时, GetWindowTextW返回0,并且必须使用相同的步骤进行检查。 This is because 0 is valid text length. 这是因为0是有效的文本长度。

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 +1和长度操作说明

Additional + 1 covers quirks of the Windows API where some API calls take into account trailing NUL characters, and some don't. 其他+ 1涵盖了Windows API的怪癖,其中一些API调用考虑了尾随NUL字符,而有些则没有。 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. GetWindowTextLengthW就是这种情况,它返回不带NUL字符的文本长度,但是GetWindowTextW最后一个参数需要声明缓冲区大小,包括NUL字符的位置。 If we omit + 1 buffer would contain one character less because API have to put NUL character. 如果我们省略+ 1缓冲区,则它少包含一个字符,因为API必须放置NUL字符。

Documentation states also that GetWindowTextLength can return value few character larger (I think it applies mostly to GetWindowTextLengthA variant). 文档还指出, GetWindowTextLength返回值可以大几个字符(我认为它主要适用于GetWindowTextLengthA变体)。 This explains length correction, because only after GetWindowTextW we know true length. 这解释了长度校正,因为只有在GetWindowTextW之后,我们才知道真正的长度。


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. 大多数保持string字符连续的字符串实现都在末尾添加了NUL字符,以简化c_str()data()处理,但是从字面上采用C ++ 11标准,他们不必这样做。 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. 因为GetWindowText总是将NUL字符放在末尾,所以对于那些不能为NUL字符永久保留额外空间的实现,它可能会覆盖一些内部数据。

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. 如果我们越过字符串内联存储大小,则必须始终将text大小调整为较小的长度并进行不必要的分配,这是有代价的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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