Can't get Windows Overlay icons to work in TListView

自闭症网瘾萝莉.ら 提交于 2019-12-12 05:49:49

问题


Using Borland C++ Builder 2009 I can display overlay icons in a TListView object, using my own TImageList.

However I also need this to work with the Windows icons. Showing those icons is not a problem, but I can't get Overlay icons to work (yet).

Here's what I do (not complete and code lifted out of a bigger project, but it should illustrate the question properly) :

During Init:

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

Everytime I want to know the index of an icon:

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;

I notice that the proper values are being passed during testing. For instance ListItem->OverlayIndex is assigned value 2 when the Filename is 'something.lnk'.

But the overlay icon is not showing. I'm sure I'm missing something. To get overlay icons to work with my own TImageList objects I had to call ImageList->Overlay(). I wonder if I need to do the same with the Windows list, but I'm not sure what values to use then.


回答1:


The overlay index returned by SHGetFileInfo() is 1-based, but the TListItem::OverlayIndex property expects a 0-based index, which it then converts to 1-based when updating the list item using the Win32 API. So you need to subtract 1 when assigning the OverlayIndex:

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

You DO NOT need to call TImageList::Overlay() when using a system image list.

Update: your subclass needs to look for the CN_NOTIFY message instead of WM_NOTIFY. WM_NOTIFY is delivered to the ListView's parent window and reflected back to the ListView as CN_NOTIFY by the VCL. Also, you need to use a reference when declaring your local LVITEM variable, otherwise you are modifying a copy instead of the original LVITEM that is in the message data. Also, when assigning item.state and item.stateMask, you need to use the |= operator to append your overlay values to them instead of replacing the existing values that were assigned by the default handler.

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;
    }
}


来源:https://stackoverflow.com/questions/30110297/cant-get-windows-overlay-icons-to-work-in-tlistview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!