В моем приложении 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 июня 2010 года: 2:14 EST:
Технически ответ был предоставлен, поэтому я отмечу это и собираюсь задать еще один вопрос, чтобы помочь мне исправить этот код.