2013-01-11 19 views
1

VS2010引入了CMFCShellTreeCtrl,它允許將文件夾瀏覽器樹ctrl拖放到我們的MFC應用程序中。如何檢測給定的PIDL是否實際上是.zip文件或類似文件?

但是,這個類似乎嚴重缺乏過濾功能。即它將構建容器對象(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,它可能在將來還未得到支持 - 或者其他類型的存儲不是真正的文件夾。

我不想消除諸如「網絡」和「計算機」之類的東西成爲有效的節點。只是那些有問題的,如「下載\ Foobar.zip」

我很抱歉這個問題散漫。任何幫助提高我的理解和創造性的方法,以瞭解什麼樣的對象是微軟的shell命名空間的一部分,以及如何有用地使用它們將不勝感激!

+0

我想,只需檢查項目是否爲文件? –

+0

「計算機」和「網絡」測試失敗。我不想排除重要的非文件系統節點。只是那些歸檔容器或類似的東西。 – Mordachai

+0

uhm,我的意思是,如果它是一個真實的文件(並且符合您不應該包含的文件的標準),則排除它 –

回答

2

一個zip文件/文件夾會有SFGAO_STREAM/SFGAO_DROPTARGET和SFGAO_FOLDER,所以如果你可以讀取shell項目作爲流,那麼它可能不是一個目錄。另一種說法是使用SHGetPathFromIDList + PathIsDirectory,但這隻適用於具有文件系統路徑的pidl。

還有其他類型的可瀏覽文件,如保存的搜索(如果您瀏覽文件需要永久完成枚舉項目),所以您可能還想考慮如何處理這些文件。

+0

這兩種技術都適用於我的目的,在Windows 7下(希望XP..8)。 – Mordachai

相關問題