WinAPI GetWindowText 作为字符串

Posted

技术标签:

【中文标题】WinAPI GetWindowText 作为字符串【英文标题】:WinAPI GetWindowText as string 【发布时间】:2017-08-25 03:39:42 【问题描述】:

我想知道是否可以从文本框 (CreateWindowEx "EDIT") 获取文本输入并将其存储为字符串,甚至更好地存储为向量

我需要一个用户可以输入或粘贴文本的文本框,当我点击一个按钮时,它会按字母顺序排列单词并计算唯一单词等...

到目前为止,我已经将它作为字符读取(我不知道如何将其设为字符串)并将字符按字母顺序排列

所以如果我输入:现在怎么样棕色母牛 它将输出:bchnnoooorwwww 而不是:棕色母牛现在怎么样

我在 WM_COMMAND 情况下的代码是

int length;
length = GetWindowTextLength(textbox) + 1;
vector<wchar_t> list(length);
GetWindowText(textbox, &list[0], length);
wstring stxt = &list[0];
wstring str(stxt);
sort(str.begin(), str.end());
SetWindowText(sortedOutput, &str[0]);

【问题讨论】:

当你说你想要它在一个向量中并且你不知道如何使它成为一个字符串你是什么意思?你把它放在一个向量中,然后在你的例子中把它放在一个字符串中。 为什么需要中间的stxtstr 变量?只需在std::sort 调用中使用list。此外,将变量命名为 list 也不是一个好主意,因为 C++ 中有一个 std::list 我认为他的问题与与编辑框的交互无关。他想要对单词进行排序,而不是对字符进行排序。所以他想要一个std::vector&lt;std::wstring&gt; 并对其进行排序。所以他寻找一个函数 string -&gt; string[] 的等价物,在 Haskell 中称为 words 我想从文本框中获取文本,并在单击按钮时对单个单词进行排序,而不是对每个字母进行排序。所以就像让一个元素包含一个完整的单词而不是一个字母。对不起,如果我没有说清楚,对不起,如果我的代码全部结束了......我一直在看数百个例子,只是试图把它放在一起弗兰肯斯坦。我是赢得 API 的新手 @Dweeb 我从来没有在控制台之外使用 c++ 工作过,所以我很难将我的工作代码和一个带有按钮的文本框连接起来 -- 它不应该无论您尝试处理的字符串来自何处,无论是文件、键盘、文本框、套接字、硬编码到程序中等。只要您有字符串,问题就在于处理该字符串。也许编写一个接受字符串的函数并且只完成创建数组的工作,而不是将所有内容都填充到您的WM_COMMAND 处理程序中,这可能会更好地向您解释这一点。 【参考方案1】:

这个答案可能对您设计解决方案有用。我真的不知道有一个不是 hacky,但可以从 std::string 转换 c_string() 的常量。

https://***.com/a/1986974/128581

在 C++98/03 标准下,不保证 std::string 的分配是连续的,但 C++11 强制它是连续的。在实践中,我和 Herb Sutter 都不知道不使用连续存储的实现。

请注意,C++11 标准始终保证 &s[0] 可以正常工作,即使在长度为 0 的字符串情况下也是如此。如果您执行 str.begin() 或 &*str.begin() 将无法保证,但对于 &s[0],标准将 operator[] 定义为:

返回:*(begin() + pos) 如果 pos

返回:一个指针 p 使得 p + i == &operator 对于 [0,size()] 中的每个 i。 (注意范围两端的方括号)

因此,您可以执行以下操作:

int len = GetWindowTextLength(hwnd) + 1;
std::string s;
s.reserve(len);
GetWindowText(hwnd, const_cast<char*>(s.c_str()), len - 1);

这很丑陋。不过,欢迎提供更多“正确”答案。

关于在您的构建中启用 unicode 时,您必须使用 wstring 或等效项。刚才测试了一下,这行得通:

std::wstring title;
title.reserve(GetWindowTextLength(m_window_handle) + 1);
GetWindowText(m_window_handle, const_cast<WCHAR *>(title.c_str()), title.capacity());

一般来说,关于 windows api,谷歌它们的全部大写 typedef 并找出它们的真正含义是很有用的。

关于拆分字符串,std::string 并不是特别擅长这种操作。这就是 std::stringstream(或 unicode 的 wstringstream)派上用场的地方。我相当肯定 stringstream 不能保证在内存中是连续的,所以你不能真的直接写到它的缓冲区中。

// Initialize a stringstream so we can extract input using >> operator
std::wstringstream ss;
ss.str(title);

// Make a vector, so we can store our words as we're extracting them
// and so we can use sort later, which works on many stl containers
std::vector<std::wstring> words;
std::wstring word;

// This will evaluate to false and thus end the loop when its done
// reading the string word by word
while(ss >> word)

  words.push_back(word);

然后继续你的排序,但在新的向量词上。

【讨论】:

今晚早些时候我看到了这个或类似的东西,const_cast 给了我一个“与“LPWSTR”类型的参数不兼容你会推荐一种不同的方法吗?我只需要一个文本框和按钮,我有实际代码作为控制台 c++ 项目对唯一单词进行排序和计数。我只是不知道如何将它们连接在一起 啊,从记忆中,我猜是因为编码问题。我的代码适用于旧式非 unicode 启用版本(可能不是 vs 2015/2-17 的默认设置)。 LPWSTR 是指向宽字符串的指针。 std 库中的等价物是 wstring。尝试 std::wstring 而不是字符串。此外,控制台项目和 windows gui 项目之间的唯一区别是一些项目设置(_CONSOLE 定义变为 _WINDOWS,链接器系统>子系统被更改)以及使用特定签名而不是 main() 切换到 WinMain/wWinMain。 用 unicode 版本的测试解决方案更新了我的答案。 确实编译没有错误!排序(title.begin(),title.end()); SetWindowText(sortedOutput, &title[0]);输出我输入的内容。即不按字母顺序排列。虽然越来越近了!啊,可能是因为它不是 vector 而 c.str 不是 vector 的函数...嗯 哦,不明白你对字符串做了什么。您要按单词排序吗?每个退休的忍者评论使用 wstringstream。 >> 运算符默认会标记化(按空格分割字符串)。同样的事情适用于 C++ 中的很多事情,比如使用 ifstream 读取文件等。我会再次更新。【参考方案2】:

您的问题不是 winapi 问题。虽然不是唯一的方法,但您找到了一种将字符串来回传输到您的编辑框的解决方案。

如何将该字符串转换为字符串的列表/向量,单词作为该列表/向量的元素实际上是一个 STL 问题。

基本上,您正在寻找 C# 函数 String.Split() 的 C++ 等效项。

这里已经有一个很好的问题和答案:

Most elegant way to split a string?

所以,你所要做的就是往返:

    从文本框中获取字符串 使用您的 split 函数将字符串转换为 std::vector&lt;string&gt;(有关如何执行此操作,请参阅其他问题)。 以通常的方式对向量进行排序。 将向量转换回字符串,这与拆分函数相反(提示:std::ostringstream)。 将生成的字符串设置为 TextBox 的文本。

根据您对多字符串和全球化的偏好,您可能首先决定坚持使用 ASCII 版本。在 Windows 上,您可以编译为 MBCS 或 ASCII。相应的字符串类型则分别为(TCHARLPCTSTRWCHARLPCWSTRCHARLPCSTR)。所有 win32 函数都有两种风格,分别以函数名称末尾的 AW 来区分。

AFAIK,虽然有std::stringstd::wstring,但没有std::basic_string&lt;TCHAR&gt; 的标准实现,可以与您的编译选项一起使用。

至于窗口处理,这里有一些代码示例(sn-ps):

InitInstance() 中,我使用输入编辑框、按钮和静态输出区域创建了对话框(IDD_FORMVIEW)作为主应用程序窗口的子窗口:

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

    hInst = hInstance; // Store instance handle in our global variable

    HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

    HWND hWndChild = CreateDialogW(hInstance, MAKEINTRESOURCE(IDD_FORMVIEW), hWnd, dlgProc);
    if (NULL == hWndChild)
    
        DWORD lastError = GetLastError();
        wchar_t msg[100];
        swprintf_s(msg, _countof(msg), L"error code: 0x%0X\n", lastError);
        OutputDebugString(msg);

    
    if (!hWnd)
    
        return FALSE;
    
    ShowWindow(hWnd, nCmdShow);
    ShowWindow(hWndChild, SW_SHOW);
    UpdateWindow(hWnd);

    return TRUE;

CreateDialogW() 将指向对话处理函数的指针作为最后一个参数,在本例中称为dlgProc()

dlgProc() 函数如下所示:

// Message handler for our menu which is a child window of the main window, here.
static INT_PTR CALLBACK dlgProc(
    _In_ HWND   hwndDlg,
    _In_ UINT   uMsg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
)

    BOOL processed = false;

    switch (uMsg)
    
    case WM_INITDIALOG:
        break;
    case WM_NOTIFY:
        break;
    case WM_COMMAND:
    
        auto sourceId = LOWORD(wParam);
        auto code = HIWORD(wParam);
        if (IDC_BUTTON1 == sourceId)
        
            if (BN_CLICKED == code)
            
                wchar_t text[1024];
                GetDlgItemText(hwndDlg, IDC_EDIT1, text, _countof(text));
                // TODO: do your string processing here (string -> string)
                SetDlgItemText(hwndDlg, IDC_STATIC, text);
                processed = TRUE;
            
        
    
        break;
    default: 
        break;
    
    return processed;

【讨论】:

我会调查一下,谢谢!我只写过 c++ 控制台应用程序,我只需要弄清楚如何使用文本框和按钮使其工作 @Dweeb 关注点分离。您的代码显示了两件事。字符串的排序(按字符而不是单词)和 Win32 UI 处理。您的 UI 处理基本正确(您找到了正确的功能)。所以我得出结论,这不是你的问题。您可以在探索 Win32 函数的工作原理时简化代码,方法是不转换而是获取字符串,将其转储到调试输出 (OutputDebugString()),然后设置一个虚拟内容作为结果。这样,您就可以独立解决这两个问题。 感谢您提供所有这些信息,我将花一天时间阅读 win32 教程,以便更好地掌握这一切【参考方案3】:

我刚刚混合了几行代码来将wchar_t 转换为wstringstd::string。给你!

string GetWindowStringText(HWND hwnd)

    int len = GetWindowTextLength(hwnd) + 1;
    vector<wchar_t> buf(len);
    GetWindowText(hwnd, &buf[0], len);
    wstring wide = &buf[0];
    string s(wide.begin(), wide.end());
    return s;

这有一个vector,所以你需要包含它。

【讨论】:

OP 的代码已经使用vector。只有std::string 是新的。因此,您可能需要推荐包含 &lt;string&gt;

以上是关于WinAPI GetWindowText 作为字符串的主要内容,如果未能解决你的问题,请参考以下文章

C++ WinAPI:处理长文件路径/名称

vc6.0如何使用getwindowtext函数获取edit控件中的文本内容

GetWindowText 为另一个进程返回空字符串

对于 C#,在调用 Win32 函数(如 GetWindowText)时使用“字符串”而不是“字符串生成器”是不是有不利之处?

GetWindowText() 抛出错误并且未被 try/catch 捕获

c# 在知道数据窗口的句柄的时候如何获得数据窗口的数据