如何检测给定的PIDL实际上是.zip文件还是类似文件?

时间:2013-01-11 21:21:01

标签: c++ mfc visual-studio-2012 windows-shell

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命名空间的一部分,以及如何有效地使用它们将不胜感激!

1 个答案:

答案 0 :(得分:2)

zip文件/文件夹将具有SFGAO_STREAM / SFGAO_DROPTARGET以及SFGAO_FOLDER,因此如果您可以将shell项作为流读取,那么它可能不是目录。另一种说法是使用SHGetPathFromIDList + PathIsDirectory,但这仅适用于具有文件系统路径的pidl。

还有其他类型的可浏览文件,比如保存的搜索(如果您浏览文件就像永远完成枚举项目一样),所以您可能想要考虑如何处理这些文件。