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

标签 c++ winapi

我最近下载了 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>

如果你坚持使用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 );

旧的 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/

相关文章:

c++ - int 到自定义结构 c++ 的转换

python - 使用 python setup.py 编译和安装 C++ 程序

C++ 干净指针算法

c++ - 使用 Memcpy 扩大指针数组的大小

C++/Windows API - 无法找到 CreateWindow

winapi - GDI 函数 BitBlt 和 StretchBlt 在 Win32 中是否硬件加速?

C# 使用 CredWrite 访问 C$

c++ - 哪个命名空间包含这个友元函数的声明?

c++ - MessageBox 超时或从另一个线程关闭 MessageBox

c++ - 显示弹出通知窗口