2

VS2010 では、フォルダー ブラウザー ツリー ctrl を MFC アプリにドロップできるようにする CMFCShellTreeCtrl が導入されました。

ただし、このクラスではフィルタリング機能が大幅に不足しているようです。つまり、コンテナ オブジェクト (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 のシェル名前空間の一部であるオブジェクトの種類と、それらを有効に使用する方法を理解するための私の理解と創造的なアプローチを改善するための助けをいただければ幸いです。

4

1 に答える 1

2

zipファイル/フォルダーにはSFGAO_STREAM/SFGAO_DROPTARGETとSFGAO_FOLDERが含まれるため、シェルアイテムをストリームとして読み取ることができる場合は、ディレクトリではない可能性があります。もう1つの方法は、SHGetPathFromIDList + PathIsDirectoryを使用することですが、これはファイルシステムパスを持つpidlに対してのみ機能します。

保存された検索のような他の種類の閲覧可能なファイルもあります(ファイルを参照すると、アイテムの列挙を完了するのに永遠にかかる)ので、それらのファイルの処理方法についても検討する必要があります。

于 2013-01-12T00:27:56.550 に答える