System Image List

A system image list contains each file, folder, shortcut, etc. which is
very handy for creating a custom explore type application. I saw Matt
Esterly’s code for using an image list, and noted the comment at the bottom
about detaching it from the CImageList; if this isn’t done the CImageList
destructor frees up the system image list causing the user to lose all of
their desktop icons. Note that this only happens under ’95 (haven’t tried
’98) – NT 4 is much more careful and won’t let you free its list. There is
also the further problem that the CImageList class checks it’s permanent
object list for the handle, and if that handle has already been attached to
another instance of CImageList it Asserts. This means that if you want to
use the image list in more than two places at once you’ll have a problem.

I had this problem in my app and so wrote a wrapper class CSystemImageList
to save me having to remember to detach the lists. Basically, the first time
an instance of the class is created it creates two singleton image lists (one
for large and one for small icons) which are stored as static members. Every
subsequent instance then uses these items, and a simple reference count is
used to keep track of their use. When the last CSystemImageList is destroyed
the reference count is zeroed and the singleton objects are detached from the
system image list, and then deleted from the heap. This means that you can use
the image lists at will without having to worry about multiple instances, asserts
or detaching lists.

Another important difference to Matt’s version is that by using the
SHGFI_USEFILEATTRIBUTES flag for SHGetFileInfo the function doesn’t need to
open a real file to either get the icon index or the image lists themselves.
This is useful, say, if you want to find the image of an object on the
internet, which doesn’t actually exist on your local disk.

In order to use the image lists, construct a CSystemImageList and then call

CImageList * CSystemImageList::GetImageList( BOOL bSmall = TRUE ) const;

which returns a pointer to the required image list (large or small) which can
then be passed to, say, CTreeCtrl::SetImageList. Bear in mind that the object
must exist for the entire time that the image list is to be used, so it’s usually
best to make it a member of the window class. A helper function


int CSystemImageList::GetIcon( const CString& sName,
BOOL bOpen = FALSE, BOOL bSmall = TRUE ) const;

provides a way of getting the particular image index for a filename. The index
returned can be from the small or large image list, and in the open or normal
state, depending on the parameters passed.

In the demo I’ve provided is a dialog-based MFC app with a tree control and a
list control, each of which is populated with a few items. See below for the
code extracts.

The demo code was generated and tested using VC++ v5.0, and has been tested under v6.0.

// SysImageListDlg.h - the dialog class

class CSysImageListDlg : public CDialog
{
// Implementation
protected:
	CSystemImageList    m_ImgList;
          :
          :
};

// SysImageListDlg.cpp - OnInitDialog
// Initialise the tree and list controls to use the image

// m_Tree is a CTreeCtrl created from the resources with ClassWizard.
// m_List is a CListCtrl.
m_Tree.SetImageList( m_ImgList.GetImageList(), TVSIL_NORMAL );

// Pass false to GetImageList to get the Large icons
m_List.SetImageList( m_ImgList.GetImageList( FALSE ), LVSIL_NORMAL );

CString sFile;

sFile = "somefile.html";
// Now create an item in each control, setting the icon indices.
// First the tree control - set the index of the icon both closed and open
m_Tree.InsertItem( sFile, m_ImgList.GetIcon( sFile ), m_ImgList.GetIcon( sFile, TRUE ) );

// and the list control - remembering to get the index for the large icon
m_List.InsertItem( 1, sFile, m_ImgList.GetIcon( sFile, FALSE, TRUE ) );


Download demo project – 20KB

Download source – 1.8KB

More by Author

Must Read