VS2010 引入了 CMFCShellTreeCtrl,它允许将文件夹浏览器树 ctrl 拖放到我们的 MFC 应用程序中。
但是,这个类似乎严重缺乏过滤能力。即它将构建容器对象列表(IShellFolder)。但似乎没有办法指定 .zip 容器不应显示在文件夹树中。
它确实提供了一个可以粗略地用于此目的的虚拟:
HRESULT CMFCShellTreeCtrl::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; InsertItem(&tvInsert); dwFetched = 0; } pEnum->Release(); return S_OK; }
我感到困惑的是缺乏区分正在枚举的对象类型的能力(或者首先控制枚举以过滤掉诸如这些非文件系统对象的更好方法)。
可以查看被枚举项目的文本,如果它以“.zip”结尾,则只需将其排除。但是,这对我来说似乎很不稳定。毕竟,可以将任意文件夹命名为 XYZ.zip(它仍然是一个文件夹,而不是 zip 存档)。类似地,未来可能还支持除 .zip 以外的其他存档类型 - 或者其他容器类型,但它们实际上并不是文件夹。
我不想消除像“网络”和“计算机”这样的有效节点。只是那些有问题的,例如“Downloads\Foobar.zip”
我为这个漫无边际的问题道歉。任何有助于提高我的理解和创造性方法以了解哪些类型的对象是 Microsoft 的 shell 命名空间的一部分,以及如何有效地使用它们,我们将不胜感激!