【问题标题】:Winapi ListView_GetItemText wrong output formatWinapi ListView_GetItemText 输出格式错误
【发布时间】:2015-11-09 14:10:24
【问题描述】:

我这样使用ListView_GetItemText

int count = ListView_GetItemCount(procmon_lv); //Get Items count
wchar_t buffer[2048]; //Init buffer
ListView_GetItemText(procmon_lv, count-1, 0, buffer, 2048); //Call function
LPWSTR itemtxt = buffer; //Create LPWSTR var

stringstream s;
s << itemtxt;
MessageBoxA(NULL, s.str().c_str(), NULL, NULL);

Sleep(7000); //Sleep because this piece of code is inside a While loop

MessageBox 函数显示如下:

我需要的是获取该行的整个文本,但似乎我得到的是一个十六进制字符串...

【问题讨论】:

  • 如果你想保留一个字符串,不要使用不兼容的字符编码来混合它。提示:std::stringstream 不能从 const wchar_t* 转换为 ASCII(或 ANSI)字符串。你得到的输出是缓冲区的地址。
  • 您知道列表视图窗口处于不同的进程吗?这会在某个时候烧伤你。为什么不使用 API 而不是破解 procmon 来获取数据?
  • @DavidHeffernan 你是什么API? Procmon 的命令行?这是相当有限的。你是对的,我正在尝试做某种“hack”,因为将 ListView 导出到支持文件,然后将支持文件转换为 XML 并不是我需要的解决方案。我已经获得了 ListView 的 HWND,我可以与项目交互(添加、删除、排序...),我只需要读取行...
  • 所有信息都可以通过Windows API获取。以这种方式进行黑客攻击是令人讨厌的。我认为您需要跨流程边界编组子项目的数据。而且它可能不适用于所有版本的 Windows。查看 Process Hacker 的代码。
  • @DavidHeffernan 我还没有找到有关如何获取 Procmon 数据的信息。这就是为什么我要做那个“讨厌的”黑客,作为最后的资源。你知道在哪里可以找到它吗?谢谢。

标签: c++ listview winapi char items


【解决方案1】:

std::stringstreamwchar_t* 指针视为通用指针,因此存储指针的值,而不是它指向的字符。

如果要使用MessageBoxA,则需要将wchar_t数据转换为ANSI。

int count = ListView_GetItemCount(procmon_lv); //Get Items count
wchar_t buffer[2048] = {0}; //Init buffer
char buffer_ansi[2048 * 2] = {0};
ListView_GetItemText(procmon_lv, count-1, 0, buffer, 2048); //Call function
WideCharToMultiByte(CP_ACP, 0, buffer, -1, buffer_ansi, sizeof(buffer_ansi), NULL, NULL);

stringstream s;
s << buffer_ansi;
MessageBoxA(NULL, s.str().c_str(), NULL, 0);

更新:你不应该使用NULL 作为MessageBoxA 的第四个参数,它不是一个指针。


更新 2:不是将字符串转换为 ANSI,而是使用 std::wstringstream 而不是 std::stringstream,并调用 MessageBoxW() 而不是 MessageBoxA()

int count = ListView_GetItemCount(procmon_lv); //Get Items count
wchar_t buffer[2048] = {0}; //Init buffer
ListView_GetItemText(procmon_lv, count-1, 0, buffer, 2048); //Call function

std::wstringstream s;
s << buffer;
MessageBoxW(NULL, s.str().c_str(), NULL, 0);

注意:您有注释“初始化缓冲区”,所以初始化缓冲区


更新 3:或者,根本不要使用 std::wstringstream

int count = ListView_GetItemCount(procmon_lv); //Get Items count
wchar_t buffer[2048] = {0}; //Init buffer
ListView_GetItemText(procmon_lv, count-1, 0, buffer, 2048); //Call function

MessageBoxW(NULL, buffer, NULL, 0);

【讨论】:

  • 这几乎是倒退。由于 ListView 包含 Unicode 字符串,并且 Windows API 始终使用 Unicode,转换为 ANSI 字符串以便您可以调用 MessageBoxA(而不是 MessageBoxW)可能会解决直接问题。但这是错误的解决方案。只需使用wstringstream
  • 如果我使用常规函数MessageBox,编译器会抛出错误:无法从 const char * 转换为 LPCSTR。那是因为我在 ANSI 环境下,应该改用MessageBoxA,所以不需要转换为 ANSI。应用WideCharToMultiByte 后,我的消息中出现空白。感谢您的帮助。
  • @ProtectedVoid:没有像 "ANSI 环境" 这样的东西(除非您正在为 Windows 95 开发)。如果您已将编译器设置为使用 MBCS 字符编码,则只需调用 MessageBoxW。当然,没人能猜到,你的 ListView 使用什么字符编码。您正在传递一个wchar_t 缓冲区,因此我们必须假设您知道自己在做什么。
  • 完全不需要使用stringstream。将 C 风格的字符串插入其中,只需在其上调用 str().c_str(),以获取相同的 C 风格的字符串是不必要的。只需将 C 风格的字符串传递给 WINdows API。从 UTF-16 转换为 MBCS 编码的第一个代码 sn-p 假定 Unicode 代码单元的等价物在 MBCS 编码中正好是 2 个字节。虽然对于 Visual Studio 来说确实如此,但通常情况并非如此。您可以使用WideCharToMultiByte 报告所需的缓冲区大小。
  • @IInspectable 真的吗?似乎 gcc 在这两种情况下都初始化了整个数组。 goo.gl/Icta5s
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-08
  • 2020-03-17
  • 2015-06-28
  • 1970-01-01
相关资源
最近更新 更多