无法使 Windows 覆盖图标在 TListView 中工作

Can't get Windows Overlay icons to work in TListView

使用 Borland C++ Builder 2009,我可以使用我自己的 TImageList.

TListView 对象中显示覆盖图标

但是我还需要它来处理 Windows 图标。显示这些图标不是问题,但我无法让叠加图标工作(目前)。

这是我所做的(不完整,代码是从一个更大的项目中提取出来的,但它应该能正确地说明问题):

初始化期间:

SHFILEINFO info ;
SmallSystemIconsList->Handle = SHGetFileInfo( L"",
                                            0,
                                            &info,
                                            sizeof(info),
                                            SHGFI_ICON |
                                            SHGFI_SMALLICON |
                                            SHGFI_SYSICONINDEX |
                                            SHGFI_OVERLAYINDEX
                                            ) ;
DestroyIcon(info.hIcon) ;`

每次想知道图标的索引:

SHFILEINFO info ;
SHGetFileInfo(             MyFileName.c_str(),
                            FILE_ATTRIBUTE_NORMAL,
                            &info,
                            sizeof(SHFILEINFO) ,
                            SHGFI_ICON |
                            SHGFI_USEFILEATTRIBUTES |
                            SHGFI_OVERLAYINDEX
                            ) ;
DestroyIcon(info.hIcon) ;

// TListItem *ListItem
ListItem->ImageIndex    = (info.iIcon & 0x00FFFFFF) ;
ListItem->OverlayIndex  = (info.iIcon >> 24) - 1;

我注意到在测试期间传递了正确的值。例如,当文件名是 'something.lnk'.

时,ListItem->OverlayIndex 被赋值为 2

但是叠加图标没有显示。我确定我错过了什么。为了让覆盖图标与我自己的 TImageList 对象一起工作,我必须调用 ImageList->Overlay()。我想知道我是否需要对 Windows 列表做同样的事情,但我不确定那时要使用什么值。

SHGetFileInfo() 返回的覆盖索引是基于 1 的,但是 TListItem::OverlayIndex 属性 需要一个基于 0 的索引,然后在更新时将其转换为基于 1使用 Win32 API 的列表项。所以你需要在分配 OverlayIndex:

时减去 1
ListItem->OverlayIndex  = (info.iIcon >> 24) - 1;

使用系统图像列表时,您不需要调用 TImageList::Overlay()

更新:您的子类需要查找 CN_NOTIFY 消息而不是 WM_NOTIFYWM_NOTIFY 传递给 ListView 的 父级 window 并由 VCL 作为 CN_NOTIFY 反射回 ListView。此外,您需要在声明本地 LVITEM 变量时使用 reference,否则您修改的是 copy 而不是 [=消息数据中的 31=]original LVITEM。此外,在分配 item.stateitem.stateMask 时,您需要使用 |= 运算符 向它们附加 您的叠加值,而不是 替换默认处理程序分配的现有值。

void __fastcall TForm1::LVNewWindowProc(Messages::TMessage &Msg)
{
    if (LVOldWindowProc) LVOldWindowProc(Msg);
    if ((Msg.Msg == CN_NOTIFY) &&
        (reinterpret_cast<LPNMHDR>(Msg.LParam)->code == LVN_GETDISPINFOW))
    {
        LV_ITEM &item = reinterpret_cast<LV_DISPINFO*>(Msg.LParam)->item;
        TListItem *ListItem = ListView1->Items->Items[item.iItem];

        item.mask |= LVIF_STATE;
        item.state |= INDEXTOOVERLAYMASK(ListItem->OverlayIndex + 1);
        item.stateMask |= LVIS_OVERLAYMASK;
    }
}