Customising the Browse for Folder dialogue
by Richard Russell, July 2009
The main Help documentation explains how you can use the Windows API to display a Browse for Folder dialogue box, allowing the user to select a folder (directory) for some purpose.
Unfortunately the basic functionality of SHBrowseForFolder is not very flexible, so below are listed two functions, the first of which lets you specify the root folder that the browse operation starts from, and the second lets you specify the initial folder selection. In both cases the default folder (i.e. the one returned if you simply click on OK) is the specified folder, but the difference is that in the first case you cannot navigate 'above' that folder, whereas in the second case you can.
The first function, FNbrowseforfolderroot, is called in the following context:
title$ = "Set root selection" root$ = "C:\bbcbasic\windows\programs" folder$ = FNbrowseforfolderroot(title$, root$)
The second function, FNbrowseforfolderinit, is called in the following context:
INSTALL @lib$+"CALLBACK" title$ = "Set initial selection" init$ = "C:\bbcbasic\windows\programs" folder$ = FNbrowseforfolderinit(title$, init$)
It would in principle be possible to combine the functions of the two routines, so that both the root and the initial selection may be specified, however that's not very likely to be required in practice.
Here are the functions:
DEF FNbrowseforfolderroot(title$, root$) LOCAL folder%, pathw%, pidl%, malloc%, bi{} title$ += CHR$0 : root$ += CHR$0 BIF_USENEWUI = &40 DIM folder% LOCAL 260, pathw% LOCAL 520 SYS "MultiByteToWideChar", 0, 0, root$, -1, pathw%, 260 SYS "ILCreateFromPath", pathw% TO pidl% DIM bi{hOwner%, pidlRoot%, pszDisplayName%, \ \ lpszTitle%, ulFlags%, lpfn%, lParam%, iImage%} bi.hOwner% = @hwnd% bi.pidlRoot% = pidl% bi.pszDisplayName% = folder% bi.lpszTitle% = !^title$ bi.ulFlags% = BIF_USENEWUI SYS "SHBrowseForFolder", bi{} TO pidl% IF pidl% THEN SYS "SHGetPathFromIDList", pidl%, folder% SYS "SHGetMalloc", ^malloc% SYS !(!malloc%+20), malloc%, pidl% ENDIF =$$folder% DEF FNbrowseforfolderinit(title$, init$) LOCAL folder%, pidl%, malloc%, bi{} title$ += CHR$0 : init$ += CHR$0 BFFM_INITIALIZED = 1 BFFM_SETSELECTION = &466 BIF_USENEWUI = &40 DIM folder% LOCAL 260 DIM bi{hOwner%, pidlRoot%, pszDisplayName%, \ \ lpszTitle%, ulFlags%, lpfn%, lParam%, iImage%} bi.hOwner% = @hwnd% bi.pszDisplayName% = folder% bi.lpszTitle% = !^title$ bi.ulFlags% = BIF_USENEWUI bi.lpfn% = FN_callback(FNBrowseCallbackProc(),4) bi.lParam% = !^init$ SYS FN_syscalls("SHBrowseForFolder"), bi{} pidl% = FN_sysresult IF pidl% THEN SYS "SHGetPathFromIDList", pidl%, folder% SYS "SHGetMalloc", ^malloc% SYS !(!malloc%+20), malloc%, pidl% ENDIF =$$folder% DEF FNBrowseCallbackProc(hwnd%, uMsg%, lParam%, lpData%) IF uMsg% <> BFFM_INITIALIZED THEN = 0 lParam% = FN_sendmessage(hwnd%, BFFM_SETSELECTION, TRUE, lpData%) = 0