SHBrowseForFolder и ярлыки - PullRequest
0 голосов
/ 17 мая 2010

В моем приложении C ++ для Windows у меня есть функция, которая должна позволить конечному пользователю выбрать папку. Я использую SHBrowseForFolder, и он работает нормально, за исключением того, что ярлыки папок не отображаются в диалоговом окне.

Кто-нибудь знает, возможно ли настроить SHBrowseForFolder так, чтобы конечные пользователи могли перемещаться по ярлыкам папок?

Редактировать: 24 мая 2010 г., 1:10 EST:

Хорошо, я покажу код того, что у меня есть. Я пытался использовать предложение о включении обратного вызова 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. Является ли этот код правильным и настолько простым / чистым, насколько это возможно?

Спасибо за вашу помощь!

Редактировать: 1 июня 2010 года: 2:14 EST: Технически ответ был предоставлен, поэтому я отмечу это и собираюсь задать еще один вопрос, чтобы помочь мне исправить этот код.

Ответы [ 2 ]

1 голос
/ 17 мая 2010

Полагаю, вы могли бы добавить стиль BIF_BROWSEINCLUDEFILES, а затем отфильтровать элементы, чтобы отображать только папки и папки .lnk (это то, что вам нужно, верно?)

Чтобы отфильтровать элементы, вам нужно добавить функцию обратного вызова в BROWSEINFO , перехватить BFFM_IUNKNOWN и запросить IFolderFilterSite и установить фильтр

0 голосов
/ 21 октября 2010

Лучшим ответом является использование IFileOpenDialog с FOS_PICKFOLDERS в качестве опции для Windows Vista и более поздних версий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...