![]() |
Desktop Development »
Shell and IE programming »
General
Intermediate
"Browse For Folder" dialog alike with sourceBy Marat BedretdinovShell interfaces in use. IShellFolder, IEnumIDList, etc. |
VC6, MFC, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

This code demonstrates the use of Windows shell interfaces.
The interfaces are:
IShellFolderIEnumIDListThe shell functions are:
SHGetMallocSHGetDesktopFolderSHGetFileInfoSHGetSpecialFolderLocationI've never worked with the Windows shell API before and this is my first try at it. I wanted to implement a common way of retrieving shell namespaces, using provided and documented shell interfaces.
This sample is a substitute for SHBrowseForFolder shell function. This code does not
implement evrything SHBrowseForFolder does, but it provides basic functionality
for navigating namespaces and selecting a desired path.
The source code is separated into a shell extension DLL BFF{D}.DLL and a sample app App{D}.exe. The DLL contains everything that you need. The sample app shows how to use the DLL's functionality.
When you need to call the "browse for folder" dialog put in the source code that will look like this:
CBrowseForFolderDlg::BFFINFO info; memset(&info, 0, sizeof(info)); info.m_pParent = this; strcpy(info.m_szTitle, "Browse For Folder"); strcpy(info.m_szMsg, "Select the Voice Mail Folder"); info.m_pidlRoot = m_pidlMainPath; /* Line 1 */ info.m_pidlSelected = m_pidlSelected; info.m_nFlags |= BFF_IDL_ROOT | BFF_IDL_SELECTED; /* Line 2 */ info.m_nFlags |= (m_bIncFiles) ? BFF_INCLUDE_FILES : info.m_nFlags; info.m_nFlags |= (m_bSysOnly) ? BFF_SYSTEM_ONLY : info.m_nFlags; CBrowseForFolderDlg dlg(&info); if (dlg.DoModal() == IDCANCEL) return; // release memory for the previous default SHFree(m_pidlSelected); // allocate and copy newly selected m_pidlSelected = dlg.GetTreeSelectedFullIdl();
The above code assumes that you have preallocated and assigned the m_pidlMainPath
and m_pidlSelected values. If you wish to work with null terminated strings,
rather than with ITEMIDLIST you would change line 1 and 2 as follows:
strcpy(info.m_szRoot, "c:\\windows\\system"); info.m_nFlags |= BFF_CHAR_ROOT;
Note, that you can specify network paths as well.
strcpy(info.m_szRoot, "\\\\ABERRESFORD\\views"); info.m_nFlags |= BFF_CHAR_ROOT;
Or CSIDL values.
info.m_pidlRoot = CSIDL_DESKTOP; info.m_nFlags |= BFF_CSIDL_ROOT;
Exactly the same rules apply to the m_pidlSelected and m_szSelected
member variable of the CBrowseForFolderDlg::BFFINFO structure. Just make
sure that selected path is a subpath of your base root, otherwise you
will get a message that specified path does not exist.
I've added a button on the dialog, "Set as Root", and made it invisible for the debugging purposes. You can make it visible and set the roots dynamically in the demo application.
You also have to add the BFF{D}.LIB library to your link list. The letter "D" signifies that you're linking with debug version of DLL.
That's all. You should be able to run your app and use CBrowseForFolderDlg class.
I've applied the "Visitor" design patter to this example. I've introduced an abstract
ITreeNode interface and made all its member variables virtual. ITreeNode
represents the "data". The meat of the functionality resides in the CShellTreeNode class.
CShellTreeNode uses the shell API to get to shell objects. The "visual" is the
MFC's CTreeCtrl class, and the "visitor" is the CTreeVisitor class, which has
a derivable CUITreeVisitor. CUITreeVisitor
knows what methods of CTreeCtrl to tackle to make it work and reflect the
hierarchy built upon ITreeNode. CUITreeVisitor knows nothing
about the concrete CShellTreeNode and only deals with the
methods exposed by ITreeNode, so you can easily change the implementation of this interface.
The CShellHelper class is used by the CShellTreeNode class and
is a keeper of all "static" data. That is, data that is not about to change during the lifetime
of the application. This class attaches to the global system image list (on WinNT I believe,
each process gets its own copy of the system image list) and lets others read/write from/to this list.
ITreeNode::SetFindDepth() method. the depth of <1> means just get
immediate children.
CTreeCtrl will be sending a message for each visible node when it needs text and an icon for it -
CTreeCtrl::OnGetdispinfo. The TVITEM::lParam member points at an instance of ITreeNode.
Only then I provide the tree control with the text and the icon id in the
image list.
According to the data retrieval approach I described above, whenever a user expands a node
I will request this ITreeNode to go and fetch its immediate children. Then I will request
CUITreeVisitor to go and visit (display) found nodes in the tree control. This is done
through a method CTreeCtrl calls every time a node with children gets expanded
CTreeCtrl::OnItemexpanding(). Therefore, whether a user expands just
one level or the "*" button on the numpad was clicked the same algorithm does the job.
CFileTreeCtrl::CompFunc() method in our case.
CBrowseForFolderDlg::BFFINFO structure has been extended to support an arbitrary root.
You can specify the base root in the form of an ITEMIDLIST, CSIDL or
char*. The same goes to the default selection. You can type in a network path
and the synchronize button should be working.
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 5 Sep 2001 Editor: Chris Maunder |
Copyright 2001 by Marat Bedretdinov Everything else Copyright © CodeProject, 1999-2009 Web21 | Advertise on the Code Project |