![]() |
Desktop Development »
Shell and IE programming »
General
Intermediate
Multiple Folder IconsBy Keith SkillingShell Icon Overlay Handler that allows you to map folder icons to folder paths. |
VC6Win2K, WinXP, Dev
|
||||||||||
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
There are two ways to change a folder icon in Windows:
But what if you want to use different icons for a subset of folders ? Why would you want to ? Consider the following situations:
In all the above examples the ability to select an icon for parts of the folder structure can be a real benefit. Unfortunately there is no easy way in Windows to do this (you could of course change the icon manually for each folder !).
Multi-Folder Icons (MFI) lets you do this easily - the image above shows it in operation with several distinct groups of folders shown using different icons.
Many File Open dialogs are implemented using an Explorer view so you also get the benefit of the custom icons when opening and saving files:
MFI is an Icon Overlay Handler (IOH). Here is a brief extract from the Microsoft documentation about these components:
Icon overlays are small images placed at the lower-left corner of the icon that represents a Shell object in Microsoft Windows Explorer or on the desktop. They are used to add some extra information to the object's normal icon. A commonly used icon overlay is the small arrow that indicates that a file or folder is actually a link. You can specify custom icon overlays for Shell objects by implementing and registering an icon overlay handler.
The basics of implementing an IOH are described in various places - here for example. This article assumes familiarity with the basic concepts involved.
As noted above the intention is that an IOH provides the shell with "small images" to overlay on certain Shell objects. However there is nothing to prevent us using a 'full-sized' icon. Thus we can return an icon that completely overlays the normal folder icon with an image of our choosing.
It is easy enough to develop an IOH which checks each file path passed to the
IsMemberOf method of the IShellIconOverlayIdentifier interface.
The component can use simple string comparison functions on the path to identify
the folders of interest, e.g. all folders on the "Z:" drive. Obviously we also need
to test whether the path actually points to a folder - again this is a straightforward
use of the Shell API function SHGetFileInfo.
Things get more complicated when we want to have a different icon for folders on the Z: drive and folders on the Y: drive, for instance. Unfortunately, Explorer only allows one icon for each IOH and this is requested when the IOH is initialized. There is no way for a single instance of an IOH to use different icons for different sets of folders.
The solution is to register multiple IOHs - one for each set of folders you want to match. Of course each IOH can be an instance of the same component which configures itself when Explorer creates it (based on some information stored in the registry). If you want another set of folders to be displayed with a different icon you only have to add another configuration entry to the registry - this is what MFI does.
The next two sections describe the implementation and the configuration required to use the component.
We need to provide multiple IOH components in the same dll. The obvious way to implement several near identical classes would be to provide a template class to handle the common functionality, e.g.
////////////////////////////////////////////////////////// // CMFI_IconImpl - Template class for common functionality template <CLASS _T,const CLSID* _pCLSID,UINT _RES, UINT _ICONINDEX> class ATL_NO_VTABLE CMFU_IconImpl : public CComObjectRootEx<CCOMSINGLETHREADMODEL>, public CComCoClass<_T,_pCLSID>, public IShellIconOverlayIdentifier { public: CMFI_IconImpl() { } DECLARE_MY_REGISTRY_RESOURCEID(_RES) DECLARE_NOT_AGGREGATABLE(_T) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(_T) COM_INTERFACE_ENTRY(IShellIconOverlayIdentifier) END_COM_MAP() public: // IShellIconOverlayIdentifier Methods STDMETHOD(GetOverlayInfo)(LPWSTR pwszIconFile,int cchMax,int* pIndex,DWORD* pdwFlags); STDMETHOD(GetPriority)(int* pIPriority); STDMETHOD(IsMemberOf)(LPCWSTR pwszPath, DWORD dwAttrib); };
Specialised versions derived from this class can then be used to implement the specifics for each component, passing the CLSID as a template parameter.
This approach has the benefit of reducing the amount of code you need to write (in fact I use it in another dll which implements a number of IOH components which identify files which are ReadOnly, Unicode or "Loaded-in-memory" - If you are interested these will soon be available here.
Unfortunately, this would still not solve the problem of being able to dynamically create instances of the IOH for each folder class - we would have to rebuild the dll each time we needed to add a new one.
What is needed is a component which can initialize itself based on some piece of
configuration information - the CLSID is the outstanding candidate for this. For
each IOH the CLSID will be passed to GetClassObject in order to get
an IClassFactory interface so that Explorer can generate an instance
of the IOH component. The class factory component that we create can cache this
value and later use it to look up the appropriate settings for each IOH instance
it generates (there will only be one as it happens). When CreateInstance
is called on the IClassFactory interface each new instance of a generic
IOH component can then be initialized using the stored settings.
In the implementation of MFI, both the class factory object and the IOH component implement this interface:
interface IMFI_Control : IUnknown { [id(1)] HRESULT Configure(REFCLSID refclsid); };
which does the necessary lookup of parameters based on CLSID.
The only thing left to do is to make sure our initialization code is called so that
we can add the necessary entries under ShellIconOverlayIdentifiers.
This will be done when we first register our COM component using RegSrv32.exe. Once
this has happened Explorer will always load our dll (unless we remove all the keys).
Explorer opens the following registry key when it starts:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers
Each subkey found is treated as an Icon Overlay Handler component and the default value of the key is the CLSID of the component in question.
MFI dynamically creates entries under this key for each folder mapping that you want. It also creates the registry entries that COM requires to locate the component. The configuration is held in the registry and looks like this:
Where the set of values for each key looks like this:

The entries have the following meaning:
|
MatchType |
Operation |
|
0 |
Matches if the partial path appears anywhere in the target path. This is the default. |
|
1 |
Matches only if both paths are the same. |
|
2 |
Matches if the partial path matches the start of the target path. Additional trailing characters are ignored. |
|
3 |
Matches if the partial path matches the end of the target path. Preceding characters are ignored. |
There is one more configuration parameter which MFI handles - IgnorePaths. This is a REG_SZ value of partial paths delimited by ";". Each path is matched against the start of the target path. If it matches then MFI ignores it - this can be useful for network drives which may not always be switched on. Note - it is a good idea to put the "A:" (or other floppy drive) in this list as MFI wastes about a second at startup trying to access this drive. The delay only happens when Explorer is started for the first time.
SHLoadNonloadedIconOverlayIdentifiers
which is supposed to force the Shell to load new Icon Overlay Handlers - this would
solve the above problem if it worked ! Unfortunately it doesn't appear to make any
difference if the dll is already loaded even if a new registry entry has been added
under the ShellIconOverlayIdentifiers key.
A better test for Network connectivity to a machine would eliminate the need for
IgnorePaths.
According to Microsoft's documentation there is a limit of 15 Icon Overlay Handlers.
I am an independent software contractor based in the UK. I am currently working for SwissRe in London.
I am also the author of a fantastic utility called CMU - trust me you'll love it as well !
05/07/07 Links to Configurator added.
04/05/07 First posted to CodeProject.
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 5 Jul 2007 Editor: |
Copyright 2007 by Keith Skilling Everything else Copyright © CodeProject, 1999-2009 Web19 | Advertise on the Code Project |