Our community of experts have been thoroughly vetted for their expertise and industry experience. Experts with Gold status have received one of our highest-level Expert Awards, which recognize experts for their valuable contributions.
This article describes how to use the SHBrowseForFolder function and includes how to pre-set an initial folder and how to set any file system folder or other shell object as the "root" folder.
It is a common requirement that a program be able to let the user select a folder; for instance, to specify where to store backup or log files, or to identify where to find a specific kind of input documents. If you didn't know about the
SHBrowseForFolder function, you might try to use the
GetSaveFileName API, but that is awkward, at best. GetSaveFileName is designed to let the user select (or type-in) a filename, not pick a directory. It can be coerced into working as a folder chooser, but it's really not the right tool.
Standard/Simple Usage Let's start by looking at a typical usage of SHBrowseForFolder, with no special features:
Note the final sequence that obtains the selected pathname. You won't find the pathname in the BROWSEINFO structure. You need to use
SHGetPathFromIDList, as shown.
All of the options are set in the
BROWSEINFO structure. In the example, we set
ulFlags to:
BIF_RETURNONLYFSDIRS | BIF_USENEWUI
Neither is needed, but without
BIF_RETURNONLYFSDIRS, the user will see shell objects such as
Recycle Bin and
Control Panel, which we probably don't want him to select.
BIF_USENEWUI is also important. Without it, the user sees a smaller, fixed-size dialog and is limited to only selecting a folder. With BIF_USENEWUI, the user has a much richer U/I experience. He can right-click to access shell functions such as opening an Explorer, doing drag-and-drop of folders, renaming, moving, and even deleting folders. Your user will expect this flexibility.
You might be surprised at the variety of options that are available. For instance, the BIF_BROWSEINCLUDEFILES flag makes this into an unusual browse-for-file dialog with
all files listed in the tree. BIF_BROWSEFORPRINTER and BIF_BROWSEFORCOMPUTER provide specialty functionality for selecting a printer or a computer on the network.
Setting a Specific Root Folder Though most programmers want to give their user maximum flexibility, it is also sometimes important to limit the user's options. For instance, when the user is allowed to choose a folder for output data, you might require that he select a folder on a specific network data drive. Or when selecting a folder containing input data files, you might want to narrow his choices to just certain subfolders of a designated directory, say, where templates are stored.
The BROWSEINFO.
pidlRoot field is the key to this. If you pre-set that value before calling SHBrowseForFolder, the user won't be able to stray "above" it in the hierarchy. For instance, if you set pidlRoot to "C:\" then he can only choose folders on drive C. If you set it to
C:\Program Files\WonderProg\DataBacku
ps
then he'll only be able to select folders that are in that directory (perhaps avoiding that ugly "I can't find my backup!" help-desk phone call).
So, all we need to do is set a pidl. But
what the heck is a pidl? Well, it stands for
Pointer to an
ID List. An ID List is a shell construct that lets it locate user-specific folder such as "My Documents" and
virtual folders such as
Fonts,
Control Panel,
Recycle Bin, special folders that are identified with GUIDs, and so forth. If you had to look at the "List" you'd see a linked chain of nodes leading from the desktop to a location in desktop namespace.
That said... you can forget about it. You don't need to know what a pidl is, you only need to create one that identifies the root location for the folder browsing.
You might try using the
SHSimpleIDListFromPath API. But dire warnings in the MSDN documentation indicate that that function may disappear one day. Anyway, it is of limited use. As a "simple" ID list, it is a single-node "list" and it appears that SHBrowseForFolder is uncomfortable with it. I found that it can be used to set a "high-level" node, such as a drive ID or even a mapped network drive like so...
...but if you try to set it to, for instance,
C:\Program Files\WonderProg
it chokes: It displays a popup error message, then displays only that one folder without the expected selectable tree of subfolders.
The documentation in SHSimpleIDListFromPath describes the alternative way to get a usable pidl, but the description is rather obtuse, and there is a much easier way:: Use the
SHParseDisplayName API. So, at last, here's the code for setting your custom folder-browsing root.
Pre-setting an Initial Folder for Browsing It is poor U/I design to force the user to drill down several layers to locate the same place that he used the previous time he browsed for a folder. The SHBrowseForFolder API provides no
direct way to pre-set an initial folder. We cover how to do this in
=-=-=-=-=-=-=-=-=-=-=-=-=-
=-=-=-=-=-
=-=-=-=-=-
=-=-=-=-=-
=-=-=-=-=-
=-=-=-=-=-
=-=-=-=
If you liked this article and want to see more from
this author, please click the
Yes button near the:
Was this article helpful?
label that is just below and to the right of this text.
Thanks! =-=-=-=-=-=-=-=-=-=-=-=-=-
=-=-=-=-=-
=-=-=-=-=-
=-=-=-=-=-
=-=-=-=-=-
=-=-=-=-=-
=-=-=-=
Our community of experts have been thoroughly vetted for their expertise and industry experience. Experts with Gold status have received one of our highest-level Expert Awards, which recognize experts for their valuable contributions.
Comments (0)