我最近下载了 DevC++,我现在正在用 C++ 编写一个 Windows API 程序,我在其中放置了一个 TextBox
输入控件和一个 OK 按钮以在 MessageBox 中显示文本输入()
。
这是一个小片段:
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);
}
如何将输入保存到 std::string txtStore;
而不是 char txtStore[200];
?
最佳答案
对于保证连续存储字符的实现(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 );
如果您正在学习 Windows API 或编写新软件,您绝对应该更喜欢 UNICODE 版本而不是 ANSI 版本。这会强制您使用 wstring
而不是 string
, wchar_t
而不是 char
,但它可以避免许多不可翻译字符(并非所有 UNICODE 字符都可以用当前代码页表示)、内部 API 转换(API 必须反复将字符串从窄字符转换为宽字符以及其他方式转换)的问题。
如果您定义项目范围的宏,您可以避免一些陷阱 UNICODE
和 _UNICODE
并删除 MBCS
如果它在某处定义。您可以在带有名为“附加定义”或类似名称的字段的选项对话框中执行此操作。如果您不知道如何配置其他宏,请在包含 <windows.h>
之前定义它们header 可以接受。
#define UNICODE
#define _UNICODE
#include <windows.h>
如果你坚持使用string
和 char
, 就在这里。
// 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 );
旧的 C++ 标准不允许修改内部字符串数据。您可以使用在堆栈上定义的一些中间缓冲区,通过 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 );
如果编译器不支持buff.data()
, 使用 &buff[0]
.
错误处理
出现错误 GetWindowTextLengthW
返回 0,因此要检查错误,您需要 SetLastError(0)
在调用它之前检查 GetLastError()
调用后的结果。 GetWindowTextW
错误返回 0 并且必须使用相同的步骤进行检查。这是因为 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 和长度操作解释
附加 + 1
涵盖了 Windows API 的怪癖,其中一些 API 调用考虑了尾随 NUL 字符,而有些则没有。 GetWindowTextLengthW
就是这种情况它返回不带 NUL 字符的文本长度,但最后一个参数在 GetWindowTextW
中需要说明缓冲区大小,包括 NUL 字符的位置。如果我们省略 + 1
缓冲区将少包含一个字符,因为 API 必须放入 NUL 字符。
文档还指出 GetWindowTextLength
可以返回值大几个字符(我认为它主要适用于 GetWindowTextLengthA
变体)。这解释了长度校正,因为只有在 GetWindowTextW
之后我们知道真正的长度。
过度分配字符串空间
大多数保留 string
的字符串实现连续字符还在末尾添加 NUL 字符以简化 c_str()
和 data()
处理,但从字面上理解 C++11 标准,他们不必这样做。因为GetWindowText
始终将 NUL 字符放在末尾,对于不为 NUL 字符永久保留额外空间的实现,它可能会覆盖一些内部数据。
虽然
text.resize( potential_length );
可以工作,将字符串的大小再调整一个字符
text.resize( potential_length + 1 );
将涵盖这些实现。这需要始终调整大小 text
如果我们跨越字符串内联存储大小,后者会更小的长度和不必要的分配。
关于c++ - 是否可以将来自 Win32 EDIT 控件的文本输入存储在 C++ std::string 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57274974/