SHBrowseForFolder和快捷方式

时间:2010-05-17 18:49:49

标签: windows visual-studio-2005 winapi

在我的C ++ Windows应用程序中,我有一个应该允许最终用户选择文件夹的功能。我正在使用SHBrowseForFolder并且它正常工作,除了文件夹快捷方式没有显示在对话框中。

有谁知道是否可以配置SHBrowseForFolder以便最终用户能够导航文件夹快捷方式?

编辑:2010年5月24日,美国东部时间1:10:

好的,我将展示到目前为止的代码。我已经尝试过在我的回调程序中使用BFFM_IUNKNOWN回调的建议,但一直在努力弄清楚如何提供一个有效的IFolderFilter后代。

1。被调用的代码:

Error CFolderChooserDialog::RunDialog()  
{  
    Error runResult = kError_NotInitialized;

    if (VERIFYN(kLyndsey, m_ReferenceCount > 0)) {  
         runResult = kError_Unexpected;  

         m_AllFoldersFilter = new TAllFoldersFilter();  

         if (VERIFYN(kLyndsey, m_AllFoldersFilter))  
         {  
               char selectedDirectoryBuffer[MAX_PATH];  
               m_DirectoryPath.CopyInto(selectedDirectoryBuffer);  

               BROWSEINFO bi;  
               memset(&bi, 0, sizeof(bi));  

               bi.hwndOwner = MyGetMainHWND(m_CBP);  
               bi.pidlRoot = NULL;  
               bi.pszDisplayName = selectedDirectoryBuffer;  
               bi.lpszTitle = (const char*)m_Description;  
               bi.ulFlags |= BIF_RETURNONLYFSDIRS;  
               bi.ulFlags |= BIF_BROWSEINCLUDEFILES;  

               bi.lpfn = SHBrowseForFolderCallbackProc;  
               bi.lParam = (LPARAM)this;  
               bi.iImage = 0;  

               LPITEMIDLIST resultInfo = SHBrowseForFolder(&bi);  
               if (resultInfo) {  
                   runResult = kError_NoError;  
                   if (SHGetPathFromIDList(resultInfo, selectedDirectoryBuffer)) {  
                        m_DirectoryPath = selectedDirectoryBuffer;  
                   }  
              }  
              else {  
                   runResult = kError_Failed;  
              }  
               delete m_AllFoldersFilter;  
               m_AllFoldersFilter = nil;  
               CoTaskMemFree(resultInfo);  
          }  

    }  

    return runResult;  
}  

2。从SHBrowseForFolder调用的回调:

int CALLBACK CFolderChooserDialog::SHBrowseForFolderCallbackProc(HWND window, UINT message, LPARAM messageValue, LPARAM clientData)  
{  
    CFolderChooserDialog* thisPtr = (CFolderChooserDialog*)clientData;  

    if (VERIFYN(kLyndsey, thisPtr)) {  
        switch (message) {  
            case BFFM_INITIALIZED: {  
                if (!thisPtr->m_DialogTitle.IsEmpty()) {  
                    ::SetWindowText(window, (const char*) thisPtr->m_DialogTitle);  
                }  

                if (!thisPtr->m_DirectoryPath.IsEmpty()) {  
                    LPCTSTR startDirectory = thisPtr->m_DirectoryPath;  
                    ::SendMessage(window, BFFM_SETSELECTION, TRUE, (LPARAM)startDirectory);  
                }  
                break;  
            }  
            case BFFM_IUNKNOWN:  
            {  
                IUnknown* theInterface = (IUnknown*)messageValue;  
                if (VERIFYN(kLyndsey, theInterface))  
                {  
                    IFolderFilterSite* filter = NULL;  
                    theInterface->QueryInterface(IID_IFolderFilterSite, (void**)&filter);  
                    if (VERIFYN(kLyndsey, filter))  
                    {  
                        filter->SetFilter((IUnknown*)thisPtr->m_AllFoldersFilter);  
                        filter->Release();  
                    }  
                }  
                break;  
            }  
            default:  
                break;  
        }  
    }  
    return 0;  
}  

3。应该为每个项目调用IFolderFilter,以便在对话框中或从对话框中过滤它:

class TAllFoldersFilter : public IFolderFilter  
{  
public:  
    TAllFoldersFilter() { refCount = 0;}  

    HRESULT STDMETHODCALLTYPE QueryInterface(const IID& iid, void** obj)  
    {  
        if (!obj)  
            return E_INVALIDARG;  
        *obj = NULL;  

        if (iid == IID_IUnknown || iid == IID_IFolderFilter)  
        {  
            *obj = (void*)this;  
            AddRef();  
            return NOERROR;  
        }  
        return E_NOINTERFACE;  
    }  

    ULONG STDMETHODCALLTYPE AddRef()  
    {  
        refCount++;  
        return refCount;  
    }  
    ULONG STDMETHODCALLTYPE Release()  
    {  
        refCount--;  
        return refCount;  
    }  

    HRESULT STDMETHODCALLTYPE GetEnumFlags(IShellFolder* sf, LPCITEMIDLIST pidlFolder, HWND* window, DWORD* flags)  
    {  
        return 0;  
    }  

    HRESULT STDMETHODCALLTYPE ShouldShow(IShellFolder* sf, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlItem)  
    {  
        HRESULT resultCode = S_OK;  

        ULONG attributes = 0UL;  

        if (SUCCEEDED(sf->GetAttributesOf(1, &pidlItem, &attributes)))  
        {  
            if (attributes & SFGAO_FOLDER)  
            {  
                resultCode = S_OK;  // Yes, I see the folders
            }  
            else if (attributes & SFGAO_LINK)  
            {  
                resultCode = S_OK;  // Yes, this shows the folder shortcut links, but I cannot explore them. When I "expand" them (click on the plus-sign-box), nothing happens.
            }  
        }  

        return resultCode;  
    }  
protected:  
    ULONG refCount;  
};  

那么,我在哪里?好吧,我可以显示文件夹,我可以显示文件夹链接,但我不确定以下内容:

  1. 如何轻松确定我的项目是否是文件夹的快捷链接?我写的代码绝对不是在看,而是显示任何快捷方式链接。

  2. 如何轻松允许最终用户将转换为快捷方式链接所代表的文件夹?

  3. 这段代码是否正确且简单/干净?

  4. 感谢您的所有帮助!

    编辑:2010年6月1日:美国东部时间2:14: 答案是技术上提供的,所以我会标记,我会问另一个问题,以帮助我修复此代码。

2 个答案:

答案 0 :(得分:1)

我猜您可以添加BIF_BROWSEINCLUDEFILES样式,然后将项目过滤为仅显示文件夹,将.lnk过滤到文件夹(这就是您追求的对象?)

要过滤这些项目,您需要向BROWSEINFO添加回调功能,抓住BFFM_IUNKNOWN并查询IFolderFilterSite并设置filter

答案 1 :(得分:0)

更好的答案是将IFileOpenDialog与FOS_PICKFOLDERS一起用作Windows Vista及更高版本的选项。