Win32 C++ ListView LVITEM的 pszText字符串生命周期——为何会出现乱码字符

编程语言 2026-07-08

我的ListView项标签保存在一个 std::vectorstd::wstring 中。关于我在一个工具函数中将来自 std::wstring 的字符串转换为 LVITEMpszText 的生存期问题,导致出现乱码字符,尽管调试器在构造时显示 LVITEM 已经完全正确。

我在我的 MyListView 对象的以下工具方法中进行 LVITEM 的构造,这个方法在添加和修改项时都会被调用。

struct MyListView {
     // ...
     std::vector<std::wstring> labels; // [0] is main, [1+] is additional columns
     // ...
     void addItems(..);
     void modifyItems(..);
private:
     LVITEM prepareMainLVItem();
}

当该工具方法执行以下操作时:

LVITEM MyListView::prepareMainLVItem() {
    LVITEM lvi;

    ZeroMemory(&lvi, sizeof(lvi));
    lvi.pszText = const_cast <wchar_t*>(labels[0].c_str()); // Need to remove const
    //...
    return lvi;

结果却是一片空白(尽管调试器在调用此函数后确认 pszText 是正确的):

标签未显示 1

我也尝试手动把字符串复制到一个 wchar_t buf[256],并把 pszText 设置为它。这样做会得到乱码,尽管调试器再次在末尾显示正确构造的 LVITEM

    LVITEM lvi;
    wchar_t buf[256];

    ZeroMemory(&lvi, sizeof(lvi));
    wcscpy_s(buf, 256, labels[0].c_str());
    lvi.pszText = buf;
    //...
    return lvi;

标签未显示 2

我知道局部变量会在作用域结束,但在这种情况下它是一个调用该方法的类的数据成员。我应该怎么做,才能使用那个数据成员?

我不想为这些标签使用动态内存,对我来说听起来有点儿大材小用。

解决方案

第二种方法显然是错误的,因为局部缓冲区会在作用域结束后失效,导致 LVITEM::pszText 字段成为悬空指针。

不过,只要向量/字符串在将 LVITEM 插入到ListView之前不被修改,第一种方法就应该完全可行。请确保同时填充好 LVITEM::mask 字段,不要让它为零。

LVITEM MyListView::prepareMainLVItem() {
    LVITEM lvi;

    ZeroMemory(&lvi, sizeof(lvi));
    lvi.mask = LVIF_TEXT;
    lvi.pszText = labels[0].data();
    //...

    return lvi;
}

也就是说,既然你已经把字符串存储在内存中,应该考虑在ListView中使用回调模式(callback mode)或虚拟模式(virtual mode),这样就不需要在ListView的内存中重复你的字符串,而是ListView会在需要从你的字符串获取文本时动态通知你。比如:

LVITEM MyListView::prepareMainLVItem() {
    LVITEM lvi;

    ZeroMemory(&lvi, sizeof(lvi));
    lvi.mask = LVIF_TEXT;
    lvi.pszText = LPSTR_TEXTCALLBACK;
    //...
    return lvi;
}

...

case LVN_GETDISPINFO: {
    NMLVDISPINFO* pdi = reinterpret_cast<NMLVDISPINFO*>(lParam);
    if (pdi->item.mask & LVIF_TEXT) {
        wcscpy_s(pdi->item.pszText, pdi->item.cchTextMax, labels[0].c_str());
    }
    break;
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章