是否可以将来自 Win32 EDIT 控件的文本输入存储在C++ std::string 中?
Is it possible to store text input from a Win32 EDIT control in a C++ std::string?
我最近下载了 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>
这是可以接受的。
#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()
结果。 错误返回 0 时GetWindowTextW
,必须使用相同的步骤进行检查。这是因为 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++中的稳定内存中
- std::原子加载和存储都需要吗
- C++:将控制台输出存储在宏中更好吗
- 使用QProcess执行命令,并将结果存储在QStringList中
- 访问存储在向量C++中的结构的多态成员
- 如何从存储在std::映射中的std::集中删除元素
- 存储模板类型以强制转换回派生<T>
- 类型总是使用其大小存储在内存中吗
- 当字符串存储在变量中时,如何将字符串转换为wchar_t
- 使用无符号字符数组有效存储内存
- 如何在cpp.中使用协议缓冲区存储大缓冲区/数组(char/int)
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 带结构的二维矢量:如何存储元素
- 添加存储在向量中的大整数的函数出现问题
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 在std::vector上存储带有模板的类实例
- 谷歌测试中的期望值存储在哪里
- 为什么C中的通用链表中存储的数据已损坏
- 在c++中获取两个大int,并将它们存储在数组中
- 在reactor中存储eventHandlers的最佳方式是什么