Virtual Developer Workshop: Containerized Development with Docker

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


  • Folders...

    Posted by mrwad99 on 04/02/2008 04:18pm

    ...get the correct icon when SHGFI_USEFILEATTRIBUTES is removed from dwFlags in GetIcon(): DWORD dwFlags = SHGFI_SYSICONINDEX;

  • very handy class:>

    Posted by Legacy on 07/09/2003 07:00am

    Originally posted by: Robert

    //I added mycomputer and desktop icons because i dont know how to get them:>
    char sysdir[MAX_PATH];
    CString strIconPath = sysdir;
    strIconPath += "\\Shell32.dll";
    HICON* phiconLarge = new HICON[2];
    HICON* phiconSmall = new HICON[2];
    ExtractIconEx(strIconPath,34, phiconLarge, phiconSmall, 1); //load desktop icon on index 4
    ExtractIconEx(strIconPath,15, &phiconLarge[1], &phiconSmall[1], 1); //load mycomputer icon on index 5

  • this control help me more than what i expected

    Posted by Legacy on 10/03/2002 07:00am

    Originally posted by: roshan

    this control help me more than what i expected
    i like it.

  • Associating System Image List to an Image Combo Box?

    Posted by Legacy on 10/26/2000 07:00am

    Originally posted by: Asiri Warnakulasuriya

    Pls. explain how to associate the system image list to
    an Image Combo Box ctrl. I would like to know the implementation in VB 6.0.

  • Network Neighborhood Icon

    Posted by Legacy on 02/01/2000 08:00am

    Originally posted by: Will

    Hi there,
    Anybody know how to retrieve the index of the Network Neighborhood icon?
    Thanks in advance for your help,

  • Folders, Drives and Network drives

    Posted by Legacy on 01/05/2000 08:00am

    Originally posted by: Teemu L�tti

    In order to retrieve folder icons, replace the line
    with a call to SHGetFileInfo() in
    CSystemImageList::GetIcon() with this code:

    //! Added by TeL: Handle folders
    CString str=sName;
    if (str.Right(1)=="\\")
    // Folder
    if (str.Right(1)==":")
    // Drive
    SHGetFileInfo( str, dwFileAttributes, &sfi, size, dwFlags );

    After this change, you can call GetIcons() with:
    "somedir\\", "c:\\", "f:" etc. to retrieve folder or
    drive icons. Network folders will work also with "\\\\tel"
    and drives mapped to network directories.

    One could also use some additional flag, but I think
    this is more simple. In any way, the file attribute
    is the trick.

  • How to display the list control with small icons?

    Posted by Legacy on 12/27/1999 08:00am

    Originally posted by: Curt Werline


    Good job on the system image list code. One question, how can I display small icons in the list control? The tree control displays them correctly, but I would like to see them in the list control as well.

    When I set the list control view to "Small Icon", the icons are not displayed, only the file names are visible.


  • Folders and drives

    Posted by Legacy on 05/13/1999 07:00am

    Originally posted by: Paul Schmidt

    To get folder and drive icons, change CSystemImageList::GetIcon() so that you include FILE_ATTRIBUTE_DIRECTORY along with FILE_ATTRIBUTE_NORMAL. Then, pass in something like "C:\\temp" (folder) or "D:\\" (drive). Note, the backslashes are doubled for the compiler, and you must include the trailing backslashes for drive letters.

  • Add an image to the system image list?

    Posted by Legacy on 05/10/1999 07:00am

    Originally posted by: Chris


    Is it possible to add an image to the system image list without corrupting the icons. I have a list control that I need both the file/folder icons plus a few of my own. Any ideas?

    - Chris

  • What about folders???

    Posted by Legacy on 03/09/1999 08:00am

    Originally posted by: Andreas Philipson

    How do I get the icon for open/closed folders?
    Is there any way to get the Network Icon too?


  • Loading, Please Wait ...

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date