CImageList containing windows system icons

Posted on 2004-10-24
Last Modified: 2013-11-20

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

Question by:csuog
    LVL 2

    Expert Comment

    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.
    LVL 16

    Accepted Solution

    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;
    LVL 16

    Expert Comment

    Was not my answer satisfactory?

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Prepare to Pass the CompTIA A+ 900 Series Exam

    CompTIA aims to adapt its A+ Certification to reflect the most current knowledge and skills needed by today's IT professionals--and this year's 2016 exam is harder than ever. This certification is one of the most highly-respected and sought after in IT.

    In this article, I'll describe -- and show pictures of -- some of the significant additions that have been made available to programmers in the MFC Feature Pack for Visual C++ 2008.  These same feature are in the MFC libraries that come with Visual …
    Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
    This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
    Hi everyone! This is Experts Exchange customer support.  This quick video will show you how to change your primary email address.  If you have any questions, then please Write a Comment below!

    933 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    12 Experts available now in Live!

    Get 1:1 Help Now