You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用ListView_SortItemsEx后ListView_FindItem始终返回-1的原因排查

问题根源与修复方案

核心问题分析

你的代码存在三个关键错误,直接导致排序后ListView_FindItem查找失败:

  1. 排序回调参数完全误用
    ListView_SortItemsEx的回调函数参数lParam1和lParam2是每个项设置的lParam值,不是项的索引。但你插入所有项时都把lParam设为0,回调里错误地将这个值当作索引调用ListView_GetItemText,导致排序逻辑彻底混乱,控件内部数据结构被破坏,后续查找自然无法正常工作。

  2. 列索引创建错误
    ListView的列索引从0开始,但你创建列时直接使用iCol=1,导致列0不存在。主项文本(子项0)没有对应的显示列,控件对文本的存储和管理出现异常,进一步影响查找功能。

  3. 排序回调返回值逻辑错误
    strcmp的返回值规则是:

  • 返回<0:str1小于str2
  • 返回0:两字符串相等
  • 返回>0:str1大于str2
    你当前的返回值映射完全错误,会导致排序结果不符合预期,甚至加剧控件内部状态混乱。

修复步骤与代码示例

1. 修正项的lParam存储

插入项时,将项的索引存入lParam,这样排序回调可以通过lParam获取到正确的项索引,进而读取文本。

2. 修正列创建逻辑

从索引0开始创建列,确保主项文本(子项0)有对应的显示列。

3. 修正排序回调函数

正确使用lParam作为项索引,同时修复strcmp返回值的映射逻辑。

4. 确保查找逻辑正确

ListView_FindItem使用LVFI_STRING时默认查找子项0的文本,确保该文本已正确设置。

修复后的完整代码:

#include "windows.h"
#include "commctrl.h"
#include "vector"
#include "string"
#pragma comment(lib, "Comctl32.lib")

HINSTANCE hinst;
HWND hwndMain;
HWND hwndList;

LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);

int CreateColumn(HWND hwndLV, int iCol, CHAR* Text, int iWidth)
{
    LVCOLUMN lvc;

    lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
    lvc.fmt = LVCFMT_LEFT;
    lvc.cx = iWidth;
    lvc.pszText = Text;
    lvc.iSubItem = iCol;
    return ListView_InsertColumn(hwndLV, iCol, &lvc);
}

int CreateItem(HWND hwndList, CHAR* text, int index)
{
    LVITEM lvi = { 0 };
    int res;

    lvi.mask = LVIF_TEXT | LVIF_PARAM;
    lvi.iItem = index;
    lvi.pszText = text;
    lvi.lParam = index; // 将项的索引存入lParam,用于排序回调
    res = ListView_InsertItem(hwndList, &lvi);

    return res;
}

void fillListView()
{
    for (int i = 0; i < 10; ++i)
    {
        CreateItem(hwndList, (CHAR*)std::to_string(i).c_str(), i);
    }
}

// 修正后的排序回调函数
int CALLBACK CompareListViewFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
    // lParam1和lParam2是项的索引
    int itemIndex1 = static_cast<int>(lParam1);
    int itemIndex2 = static_cast<int>(lParam2);

    std::vector<CHAR> str1(MAX_PATH);
    std::vector<CHAR> str2(MAX_PATH);

    ListView_GetItemText(hwndList, itemIndex1, 0, &str1.front(), MAX_PATH);
    ListView_GetItemText(hwndList, itemIndex2, 0, &str2.front(), MAX_PATH);

    // 直接返回strcmp的结果,符合排序回调的返回值要求
    return strcmp(&str1.front(), &str2.front());
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpszCmdLine, int nCmdShow)
{
    MSG msg;
    BOOL bRet;
    WNDCLASS wc;
    UNREFERENCED_PARAMETER(lpszCmdLine);

    // 注册主窗口类
    if (!hPrevInstance)
    {
        wc.style = 0;
        wc.lpfnWndProc = (WNDPROC)WndProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInstance;
        wc.hIcon = LoadIcon((HINSTANCE)NULL,
            IDI_APPLICATION);
        wc.hCursor = LoadCursor((HINSTANCE)NULL,
            IDC_ARROW);
        wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wc.lpszMenuName = NULL;
        wc.lpszClassName = "MainWndClass";

        if (!RegisterClass(&wc))
            return FALSE;
    }

    hinst = hInstance;  

    hwndMain = CreateWindow("MainWndClass", "Sample",
        WS_OVERLAPPEDWINDOW, 500, 30, 700, 700, (HWND)NULL,
        (HMENU)NULL, hinst, (LPVOID)NULL);

    hwndList = CreateWindow(WC_LISTVIEW, "", WS_VISIBLE | WS_BORDER | WS_CHILD | LVS_REPORT |
        LVS_NOCOLUMNHEADER, 5, 5, 470, 630, hwndMain, (HMENU)44444, 0, 0);

    HWND btn = CreateWindow("Button", "Select element 2", WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, 500, 5, 150, 30, hwndMain, (HMENU)44445, 0, 0);

    HWND btn2 = CreateWindow("Button", "Sorting", WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, 500, 55, 150, 30, hwndMain, (HMENU)44446, 0, 0);

    ListView_SetExtendedListViewStyleEx(hwndList, 0, LVS_EX_FULLROWSELECT | LVS_EX_FLATSB);

    // 从索引0开始创建列
    CreateColumn(hwndList, 0, "", 450);

    fillListView();


    if (!hwndMain)
        return FALSE;

    ShowWindow(hwndMain, nCmdShow);
    UpdateWindow(hwndMain);

    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {

    case WM_COMMAND:
    {
        int wmId = LOWORD(wParam);
        switch (wmId)
        {
        case 44445:
        {
            LVFINDINFO lvfiInfo;
            lvfiInfo.flags = LVFI_STRING;
            lvfiInfo.psz = "2";
            int iIndex = ListView_FindItem(hwndList, -1, &lvfiInfo);
            if (iIndex != -1)
            {
                ListView_SetItemState(hwndList, iIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
                SetFocus(hwndList);
            }
            else
            {
                MessageBox(hWnd, "Not found", "ERROR", MB_ICONINFORMATION);
            }

            break;
        }
        case 44446:
        {
            ListView_SortItemsEx(hwndList, CompareListViewFunc, 0);

            break;
        }
        }
        break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

额外修正点说明

  • 移除了LVIF_IMAGE标志,因为没有使用图像列表,避免不必要的参数设置。
  • 将窗口类的lpszMenuName改为NULL,原代码中的"MainMenu"未定义,会导致编译警告。
  • 移除了ListView创建时的LVS_SORTDESCENDING风格,避免初始排序干扰测试。

内容的提问来源于stack exchange,提问作者jrfdsa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 04:27:03