Search code examples
c++mfctreeviewmfc-feature-pack

Filtering file types with CMFCShellTreeCtrl


I'm using a CMFCShellTreeCtrl derived class called CShellTreeCtrl in an CMFCOutlookBar object to display files and I'd like to filter file types and later be able to drag and drop files from it.

I've managed to display files as well as folders, but struggling to understand how to use IEnumIDList to achieve the file type filtering.

int CBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMFCOutlookBar::OnCreate(lpCreateStruct) == -1)
    return -1;

CMFCOutlookBarTabCtrl* pOutlookBar = (CMFCOutlookBarTabCtrl*)GetUnderlyingWindow();

if (pOutlookBar != NULL)
{
    pOutlookBar->SetImageList(IDB_PAGES_HC, 24);
    pOutlookBar->SetToolbarImageList(IDB_PAGES_SMALL_HC, 16);
    pOutlookBar->EnableInPlaceEdit(FALSE);
    RecalcLayout();
}

RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);

// can float, can autohide, can resize, CAN NOT CLOSE
DWORD dwStyle = AFX_CBRS_AUTOHIDE | AFX_CBRS_RESIZE;


CRect rectDummy(0, 0, 0, 0);
const DWORD dwTreeStyle = WS_CHILD | WS_VISIBLE | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_INFOTIP;
m_pDirList = new CShellTreeCtrl;
m_pDirList->Create(dwTreeStyle, rectDummy, this, ID_SHELLDRILL);
m_pDirList->SetFlags(m_pDirList->GetFlags() | SHCONTF_NONFOLDERS);
pOutlookBar->AddControl(m_pDirList, _T("Folders"), 2, FALSE, dwStyle);
}

Solution

  • Got it working with the following code adapted from this similar question

    HRESULT EnumObjects(HTREEITEM hParentItem, LPSHELLFOLDER pParentFolder, LPITEMIDLIST pidlParent)
    {
        ASSERT_VALID(this);
        ASSERT_VALID(afxShellManager);
    
        LPENUMIDLIST pEnum = NULL;
    
        HRESULT hr = pParentFolder->EnumObjects(NULL, m_dwFlags, &pEnum);
        if (FAILED(hr) || pEnum == NULL)
        {
            return hr;
        }
    
        LPITEMIDLIST pidlTemp;
        DWORD dwFetched = 1;
    
        // Enumerate the item's PIDLs:
        while (SUCCEEDED(pEnum->Next(1, &pidlTemp, &dwFetched)) && dwFetched)
        {
            TVITEM tvItem;
            ZeroMemory(&tvItem, sizeof(tvItem));
    
            // Fill in the TV_ITEM structure for this item:
            tvItem.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN;
    
            // AddRef the parent folder so it's pointer stays valid:
            pParentFolder->AddRef();
    
            // Put the private information in the lParam:
            LPAFX_SHELLITEMINFO pItem = (LPAFX_SHELLITEMINFO)GlobalAlloc(GPTR, sizeof(AFX_SHELLITEMINFO));
            ENSURE(pItem != NULL);
    
            pItem->pidlRel = pidlTemp;
            pItem->pidlFQ = afxShellManager->ConcatenateItem(pidlParent, pidlTemp);
    
            pItem->pParentFolder = pParentFolder;
            tvItem.lParam = (LPARAM)pItem;
    
            CString strItem = OnGetItemText(pItem);
            tvItem.pszText = strItem.GetBuffer(strItem.GetLength());
            tvItem.iImage = OnGetItemIcon(pItem, FALSE);
            tvItem.iSelectedImage = OnGetItemIcon(pItem, TRUE);
    
            // Determine if the item has children:
            DWORD dwAttribs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_DISPLAYATTRMASK | SFGAO_CANRENAME | SFGAO_FILESYSANCESTOR;
    
            pParentFolder->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlTemp, &dwAttribs);
            tvItem.cChildren = (dwAttribs & (SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR));
    
            // Determine if the item is shared:
            if (dwAttribs & SFGAO_SHARE)
            {
                tvItem.mask |= TVIF_STATE;
                tvItem.stateMask |= TVIS_OVERLAYMASK;
                tvItem.state |= INDEXTOOVERLAYMASK(1); //1 is the index for the shared overlay image
            }
    
            // Fill in the TV_INSERTSTRUCT structure for this item:
            TVINSERTSTRUCT tvInsert;
    
            tvInsert.item = tvItem;
            tvInsert.hInsertAfter = TVI_LAST;
            tvInsert.hParent = hParentItem;
    
            string str = strItem;
    
            if (tvItem.cChildren & SFGAO_HASSUBFOLDER)
            {
                InsertItem(&tvInsert);
            }
            else
            {
                if ((str.substr(str.find_last_of(".") + 1) == "pdf"))
                {
                    InsertItem(&tvInsert);
                }
            }
            dwFetched = 0;
        }
    
        pEnum->Release();
        return S_OK;
    }