Thread View: borland.public.cppbuilder.nativeapi
6 messages
6 total messages
Started by Mike Collins
Wed, 07 Feb 2007 15:06
SHBrowseForFolder and filtering
Author: Mike Collins
Date: Wed, 07 Feb 2007 15:06
Date: Wed, 07 Feb 2007 15:06
12 lines
1431 bytes
1431 bytes
Hi all, can anyone point me in the right direction with this -not sure if it is possible though. I 'm using the SHBrowseForFolder api to display a browser dialog. However, i want to control what is displayed, and thus selected within this dialog. I want to limit the users display to only removale drives, CD / DVD drives and folders within these drives. I've coded a custome callback for the browser but i'm not sure what messages to look for and how to process then. Many thanks in advance Mike C
Re: SHBrowseForFolder and filtering
Author: Bob Gonder
Date: Wed, 07 Feb 2007 17:48
Date: Wed, 07 Feb 2007 17:48
49 lines
2745 bytes
2745 bytes
Mike Collins wrote:
>Hi all, can anyone point me in the right direction with this -not sure if it
>is possible though.
Sounds COMplicated but doable.
(I haven't done it, just reading the docs...)
>I 'm using the SHBrowseForFolder api to display a browser dialog. However,
>i want to control what is displayed, and thus selected within this dialog.
>I want to limit the users display to only removale drives, CD / DVD drives
>and folders within these drives. I've coded a custome callback for the
>browser but i'm not sure what messages to look for and how to process then.
The remarks section here
http://msdn2.microsoft.com/en-us/library/ms647664.aspx
mentions Custom Filtering (with 6 steps)
Step3
You will be catching BFFM_IUNKNOWN message in your callback
http://msdn2.microsoft.com/en-us/library/ms649522.aspx
case BFFM_IUNKNOWN:
IFolderFilterSite* FFS;
((IUnknown*)lParam)->QueryInterface( Unsure, &FFS );
Step 5
Then making your COM filter interface available to the dialog.
http://msdn2.microsoft.com/en-us/library/ms645491.aspx
FFS->SetFilter( MyIUnknownCOMInterfaceThatHasAnIFolderFilter);
Step 6
FFS->Release();
Step 4
You would then need a COM Interface
(MyIUnknownCOMInterfaceThatHasAnIFolderFilter) that returns a pointer
to an IFolderFilter which implements your 2 filtering procs.
http://msdn2.microsoft.com/en-us/library/ms645494.aspx
In particular your IFolderFilter::ShouldShow() method returns S_OK to
show and S_FALSE to hide.
http://msdn2.microsoft.com/en-us/library/ms645496.aspx
Apparently after all that, the dialog automatically calls your COM
filters for each item.
COM interfaces are currently beyond my knowledge base.
Perhaps you have ventured there?
Re: SHBrowseForFolder and filtering
Author: Remy Lebeau (TeamB)
Date: Wed, 07 Feb 2007 18:27
Date: Wed, 07 Feb 2007 18:27
80 lines
3550 bytes
3550 bytes
"Mike Collins" <its@TheBottomOfThePost.com> wrote in message
news:45c9eb0a@newsgroups.borland.com...
> I want to limit the users display to only removale drives, CD / DVD
> drives and folders within these drives.
SHBrowseForFolder() does not support that. You can use the pidlRoot
member of the BROWSEINFO structure to limit the dialog to drive
letters only by setting it to the ITEMIDLIST returned by
SHGetSpecialFolderLocation(CSIDL_DRIVES). But you cannot filter out
which individual drives are actually displayed. The only thing you
can do is use the callback function to prevent the dialog from being
closed if the user tries to select an incorrect drive/folder.
> I've coded a custome callback for the browser but i'm not sure what
> messages to look for and how to process then.
For example:
int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM
lParam, LPARAM lpData)
{
if( uMsg == BFFM_SELCHANGED )
{
LPITEMIDLIST pidl = (LPITEMIDLIST) lpData;
TCHAR path[MAX_PATH+1] = {0};
if( SHGetPathFromIDList(pidl, path) )
{
if( path[1] == TEXT(':') )
{
path[2] = 0;
UINT type = GetDriveType(path);
if( (type == DRIVE_REMOVABLE) || (type ==
DRIVE_CDROM) )
{
SendMessage(hwnd, BFFM_ENABLEOK, TRUE, 0);
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0,
(LPARAM) TEXT(""));
return 0;
}
}
SendMessage(hwnd, BFFM_ENABLEOK, FALSE, 0);
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)
TEXT("Select a removable drive/folder only!"));
}
return 0;
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TCHAR buffer[MAX_PATH+1];
LPITEMIDLIST pidlRoot = NULL;
SHGetSpecialFolderLocation(Handle, CSIDL_DRIVES, &pidlRoot);
BROWSEINFO bi = {0};
bi.hwndOwner = Handle;
bi.pidlRoot = pidlRoot;
bi.pszDisplayName = buffer;
bi.lpszTitle = TEXT("Select a removalbe drive/folder");
bi.ulFlags = BIF_STATUSTEXT | BIF_RETURNONLYFSDIRS;
bi.lpfn = &BrowseCallbackProc;
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
if( pidlRoot ) CoTaskMemFree(pidlRoot);
if( pidl )
{
//...
CoTaskMemFree(pidl);
}
}
Gambit
Re: SHBrowseForFolder and filtering
Author: Remy Lebeau (TeamB)
Date: Wed, 07 Feb 2007 18:59
Date: Wed, 07 Feb 2007 18:59
171 lines
5567 bytes
5567 bytes
"Bob Gonder" <notbg@notmindspring.invalid> wrote in message
news:6f0ks2166gv2qvl1v7oq0kofrmitcu4mio@4ax.com...
> The remarks section here
> http://msdn2.microsoft.com/en-us/library/ms647664.aspx
> mentions Custom Filtering (with 6 steps)
I stand corrected. I never noticed that Microsoft added filtering to
the dialog in XP. In which case, my earlier example then becomes
something like the following instead:
#include <shobjidl.h>
class MyFilter : public IFolderFilter
{
private:
ULONG mRef;
public:
MyFilter()
: mRef(0)
{
}
HRESULT __stdcall QueryInterface(const REFIID riid, void**
ppv)
{
if( !ppv )
return E_POINTER;
*ppv = NULL;
if( riid == IID_IUnknown )
*ppv = (IUnknown*) this;
else if( riid == IID_IFolderFilter )
*ppv = (IFolderFilter*) this;
if( *ppv == NULL )
return E_NOINTERFACE;
AddRef();
return S_OK;
}
ULONG __stdcall AddRef()
{
return ++mRef;
}
ULONG __stdcall Release()
{
if( --mRef > 0 )
return mRef;
delete this;
return 0;
}
HRESULT __stdcall GetEnumFlags(IShellFolder *psf,
PCIDLIST_ABSOLUTE pidlFolder, HWND *phwnd, DWORD *pgrfFlags)
{
*pgrfFlags = SHCONTF_FOLDERS;
return S_OK;
}
HRESULT __stdcall ShouldShow(IShellFolder *psf,
PCIDLIST_ABSOLUTE pidlFolder, PCUITEMID_CHILD pidlItem)
{
ULONG attrs = 0;
psf->GetAttributesOf(1, &pidlFolder, &attrs);
if( (attrs & SFGAO_FILESYSTEM) && (attrs &
SFGAO_REMOVABLE) )
return S_OK;
return S_FALSE;
}
};
#ifndef BFFM_IUNKNOWN
#define BFFM_IUNKNOWN 5
#endif
int CALLBACK FilterCallbackProc(HWND hwnd, UINT uMsg, LPARAM
lParam, LPARAM lpData)
{
if( uMsg == BFFM_IUNKNOWN )
{
IFolderFilterSite *pSite = NULL;
((IUnknown*)
lParam)->QueryInterface(IID_IFolderFilterSite, (void**)&pSite);
MyFilter *filter = new MyFilter;
if( FAILED(pSite->SetFilter(filter)) )
delete filter;
pSite->Release();
}
return 0;
}
int CALLBACK FolderCallbackProc(HWND hwnd, UINT uMsg, LPARAM
lParam, LPARAM lpData)
{
if( uMsg == BFFM_SELCHANGED )
{
LPITEMIDLIST pidl = (LPITEMIDLIST) lpData;
TCHAR path[MAX_PATH+1] = {0};
if( SHGetPathFromIDList(pidl, path) )
{
if( path[1] == TEXT(':') )
{
path[2] = 0;
UINT type = GetDriveType(path);
if( (type == DRIVE_REMOVABLE) || (type ==
DRIVE_CDROM) )
{
SendMessage(hwnd, BFFM_ENABLEOK, TRUE, 0);
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0,
(LPARAM) TEXT(""));
return 0;
}
}
}
SendMessage(hwnd, BFFM_ENABLEOK, FALSE, 0);
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)
TEXT("Select a removable drive/folder only!"));
}
return 0;
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TCHAR buffer[MAX_PATH+1];
LPITEMIDLIST pidlRoot = NULL;
SHGetSpecialFolderLocation(Handle, CSIDL_DRIVES, &pidlRoot);
BROWSEINFO bi = {0};
bi.hwndOwner = Handle;
bi.pidlRoot = pidlRoot;
bi.pszDisplayName = buffer;
bi.lpszTitle = TEXT("Select a removable drive/folder");
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS;
if( (Win32Platform != VER_PLATFORM_WIN32_NT) ||
(Win32MajorVersion < 5) || ((Win32MajorVersion == 5) &&
(Win32MinorVersion < 1)) )
{
bi.lpfn = &FolderCallbackProc;
bi.ulFlags |= BIF_STATUSTEXT;
}
else
bi.lpfn = &FilterCallbackProc;
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
if( pidlRoot ) CoTaskMemFree(pidlRoot);
if( pidl )
{
//...
CoTaskMemFree(pidl);
}
}
Gambit
Re: SHBrowseForFolder and filtering
Author: Mike Collins
Date: Thu, 08 Feb 2007 01:11
Date: Thu, 08 Feb 2007 01:11
68 lines
3416 bytes
3416 bytes
Cheers bob, i had looked at the MSDN references that you so kindly posted below and they scare the s&%t out of me - was naively hoping that someone would tell me that it was all that complicated - but alas. I actual ended up doing it as remy suggested by processing the users selection on the fly and then disallowing the OK button and setting the status text Thanks again - might brave it when i'm not so busy. Mike "Bob Gonder" <notbg@notmindspring.invalid> wrote in message news:6f0ks2166gv2qvl1v7oq0kofrmitcu4mio@4ax.com... > Mike Collins wrote: > >>Hi all, can anyone point me in the right direction with this -not sure if >>it >>is possible though. > > Sounds COMplicated but doable. > (I haven't done it, just reading the docs...) > >>I 'm using the SHBrowseForFolder api to display a browser dialog. >>However, >>i want to control what is displayed, and thus selected within this dialog. >>I want to limit the users display to only removale drives, CD / DVD drives >>and folders within these drives. I've coded a custome callback for the >>browser but i'm not sure what messages to look for and how to process >>then. > > The remarks section here > http://msdn2.microsoft.com/en-us/library/ms647664.aspx > mentions Custom Filtering (with 6 steps) > > Step3 > You will be catching BFFM_IUNKNOWN message in your callback > http://msdn2.microsoft.com/en-us/library/ms649522.aspx > > case BFFM_IUNKNOWN: > IFolderFilterSite* FFS; > ((IUnknown*)lParam)->QueryInterface( Unsure, &FFS ); > > Step 5 > Then making your COM filter interface available to the dialog. > http://msdn2.microsoft.com/en-us/library/ms645491.aspx > > FFS->SetFilter( MyIUnknownCOMInterfaceThatHasAnIFolderFilter); > Step 6 > FFS->Release(); > > Step 4 > You would then need a COM Interface > (MyIUnknownCOMInterfaceThatHasAnIFolderFilter) that returns a pointer > to an IFolderFilter which implements your 2 filtering procs. > http://msdn2.microsoft.com/en-us/library/ms645494.aspx > > In particular your IFolderFilter::ShouldShow() method returns S_OK to > show and S_FALSE to hide. > http://msdn2.microsoft.com/en-us/library/ms645496.aspx > > Apparently after all that, the dialog automatically calls your COM > filters for each item. > > COM interfaces are currently beyond my knowledge base. > Perhaps you have ventured there? > >
Re: SHBrowseForFolder and filtering
Author: Mike Collins
Date: Thu, 08 Feb 2007 01:12
Date: Thu, 08 Feb 2007 01:12
12 lines
1407 bytes
1407 bytes
Bingo - exactly how i did it in then end - thats for the suggestion though - com filters were too scarey "Remy Lebeau (TeamB)" <no.spam@no.spam.com> wrote in message news:45ca1a14$1@newsgroups.borland.com... > > "Mike Collins" <its@TheBottomOfThePost.com> wrote in message > news:45c9eb0a@newsgroups.borland.com... > >> I want to limit the users display to only removale drives, CD / DVD >> drives and folders within these drives.
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads