问题
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