CImageList containing windows system icons


I'm writing an app that involves the selection and manipulation of files using a CTreeCtrl.  I would very much like to have icons next to each item in the tree e.g. icons for folders and icons for the associated files eg. Icons that depict a text document etc - as in windows explorer.

Can anyone tell me how to do this?

Many Thanks

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

First, draw the icons on a single bitmap, one by one next to each other. Make each icon same size, eg 16x16 pixels. Have the image saved as bmp. Add the image to the application resources. Then somewhere duing initialization (for example your treeviews OnInitialUpdate()) create the imagelist and give ot to the treectrl

like this:

m_pIconImageList = new CImageList;
m_pIconImageList->Create( IDB_ICONS  , 16 , 1 , RGB(255,0,255) );
m_tree.SetImageList( m_pIconImageList, TVSIL_NORMAL );

where IDB_ICONS is the resource id of you icon bitmap, and RGB(255,0,255) is the transparent color - in this case pink.

Then when inserting items in the tree control do:

m_tree.InsertItem( "SomeNode" , 0 , 1 );

The 0 is the unselected image, and the 1 is the selected image for the node.

A great way to draw good icons is to use a vector based graphics program. I used openoffice's draw. Then when done, I zoom in close to the icon (mabe around 300x300 pixels, not important as long as it is quite big) and take a screenshot. The icon is then resized to 16x16 in a graphics program, I use irfanview. The resizing gives you nice small smooth looking icons which are difficult to draw by hand.
You need also to do some shell programming in order to get the proper icons.

Here's an excerpt from a class the does populate a checkboxed tree with folders and proper icons (starting from 'Desktop' item)

      LPITEMIDLIST pidlTemp = (LPITEMIDLIST) pidl;

      // Calculate size of list.
      UINT cb = pidl->mkid.cb + sizeof(pidl->mkid.cb);

      LPITEMIDLIST pidlRet = (LPITEMIDLIST)g_pMalloc->Alloc(cb);
      if (pidlRet)
            CopyMemory(pidlRet, pidl, cb);
      return pidlRet;

// CTargetTree message handlers

void CTargetTree::Populate(HTREEITEM hItem /*= NULL*/)
      LPITEMIDLIST      pidlDesktop;
      HRESULT                  hr;
      STRRET                  strDispName;
      TCHAR                  szDisplayName[100];

      //LPSHELLVIEW            pShellView;
      // // Get a pointer to the Desktop's IShellFolder interface. //

      hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidlDesktop);
      hr = m_pSHDesktopFolder->GetDisplayNameOf(pidlDesktop, SHGDN_INFOLDER, &strDispName);
      hr = StrRetToBuf(&strDispName, pidlDesktop, szDisplayName, sizeof(szDisplayName));

      SHFILEINFO      sfi;
      HIMAGELIST      hDesktop = (HIMAGELIST)SHGetFileInfo((LPCTSTR)pidlDesktop, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);

            CImageList      *pIL = CImageList::FromHandle(hDesktop);

            SetImageList(pIL, TVSIL_NORMAL);
            hItem = InsertItem(szDisplayName, sfi.iIcon, sfi.iIcon);

      CImageList      *pIl2 = GetImageList(TVSIL_STATE);
      IMAGEINFO      imgInfo;
      ZeroMemory(&imgInfo, sizeof(imgInfo));
      pIl2->GetImageInfo(0, &imgInfo);
      pIl2->Add(LoadIcon(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_CHECK_GRAY)));

      PopulateSubItem(m_pSHDesktopFolder, hItem);


      Expand(hItem, TVE_EXPAND);

void CTargetTree::PopulateSubItem(LPSHELLFOLDER pSHFolder, HTREEITEM hParent, int iDepth)
      LPITEMIDLIST      pIdl;
      LPENUMIDLIST      pEnumFolders;
      //SHFILEINFO            sfi;
      //HIMAGELIST            hDesktop;
      HRESULT                  hr;
      CImageList            *pIL;
      STRRET                  strDispName;
      TCHAR                  szDisplayName[MAX_PATH],szFullName[MAX_PATH];
      HTREEITEM            hItem;
      SFGAOF                  rgf = SFGAO_HASSUBFOLDER;
      _FolderData            *pFolderData;

      hr = pSHFolder->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN, &pEnumFolders);


      hr = pEnumFolders->Next(1, &pIdl, NULL);

      while(SUCCEEDED(hr) && (hr != S_FALSE))
            rgf = -1;
            hr = pSHFolder->GetAttributesOf(1, (LPCITEMIDLIST*)&pIdl, &rgf);

            //special case for Control Panel -> skip
            if(rgf  == 0xa0000004)
                  hr = pEnumFolders->Next(1, &pIdl, NULL);

            //if we have a folder
            if((rgf & SFGAO_FOLDER) && !(rgf & SFGAO_LINK))
                  hr = pSHFolder->GetDisplayNameOf(pIdl, SHGDN_INFOLDER, &strDispName);
                  hr = StrRetToBuf(&strDispName, pIdl, szDisplayName, sizeof(szDisplayName));

                  hr = pSHFolder->GetDisplayNameOf(pIdl, SHGDN_NORMAL | SHGDN_FORPARSING, &strDispName);
                  hr = StrRetToBuf(&strDispName, pIdl, szFullName, sizeof(szFullName));
//                  if((rgf & 0xf080014c) != 0xf080014c)
//                        hDesktop = (HIMAGELIST)SHGetFileInfo((LPCTSTR)pIdl, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_ICON);
//                  else
//                        hDesktop = (HIMAGELIST)SHGetFileInfo(szFullName, 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);

                  LPEXTRACTICON      pIcon;
                  hr = pSHFolder->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST*)&pIdl, IID_IExtractIcon, NULL, (void**)&pIcon);
                        TCHAR      szIconLoc[300];
                        int            iIndex;
                        UINT      uFlags;
                        HICON      hSmall,hLarge;

                        hr = pIcon->GetIconLocation(GIL_FORSHELL, szIconLoc, 300, &iIndex, &uFlags);
                        hr = pIcon->Extract(szIconLoc, iIndex, &hLarge, &hSmall, 16);

                        pIL = GetImageList(TVSIL_NORMAL);
                              pIL = new CImageList;
                              pIL->Create(16, 16, ILC_COLOR32, 0, 4);
                        int      iIdx = pIL->GetImageCount()-1;
                        SetImageList(pIL, TVSIL_NORMAL);
                        hItem = InsertItem(szDisplayName, iIdx, iIdx, hParent);
                        //check children
                        int      iCheck = GetCheck(hParent);
                        if(iCheck == eChecked)
                              SetCheck(hItem, iCheck);

                        //if the item is on excluded, will be unchecked (MUST be done after the above check ;)
                        //if the item is on scan folders, will be checked
                        CheckItemOnPopulate(hItem, szFullName);

                  pIL = CImageList::FromHandle(hDesktop);
                  SetImageList(pIL, TVSIL_NORMAL);
                  hItem = InsertItem(szDisplayName, sfi.iIcon, sfi.iIcon, hParent);
                  SetItemData(hItem, NULL);
                  //SHGetPathFromIDList(pIdl, szDisplayName);

                  pFolderData = new _FolderData;
                  pFolderData->pIdl = MakeCopy(pIdl);
                  pFolderData->pSHF = pSHFolder;
                  SetItemData(hItem, (DWORD_PTR)pFolderData);

                  //if it has subfolders
                  if((m_iDepth <= iDepth) && (rgf & SFGAO_HASSUBFOLDER))
                        LPSHELLFOLDER      pSHSubFolder;
                        hr = pSHFolder->BindToObject(pIdl, NULL, IID_IShellFolder, (void**)&pSHSubFolder);
                              if(m_iDepth < iDepth)
                                    PopulateSubItem(pSHSubFolder, hItem);

                              //for my computer (and others) do extra stuff
                              DoExtraStuff(szFullName, hItem);
            hr = pEnumFolders->Next(1, &pIdl, NULL);


void CTargetTree::OnTvnItemexpanding(NMHDR *pNMHDR, LRESULT *pResult)
      LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
      HTREEITEM      hItem = pNMTreeView->itemNew.hItem;
      if(pNMTreeView->action == TVE_EXPAND)
                  CWaitCursor      cw;            
                  HTREEITEM      hChild = GetChildItem(hItem);

                              _FolderData      *pFD = (_FolderData*)GetItemData(hChild);

                                          LPSHELLFOLDER      pSHSubFolder;
                                          HRESULT hr = pFD->pSHF->BindToObject(pFD->pIdl, NULL, IID_IShellFolder, (void**)&pSHSubFolder);
                                                PopulateSubItem(pSHSubFolder, hChild, 1);
                        hChild = GetNextSiblingItem(hChild);

      *pResult = 0;

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Was not my answer satisfactory?
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.