You've run into an area of the NSEs that really stinks. Fortunately,
workarounds do exist. I cover this exact issue on pages 309-311 of my book,
Windows Shell Programming. "What's it say?" you ask. Basically, you've run
into an issue with Explorer's caching mechanism. First off, you have to let
Explorer cache the icons (shell team, correct me if I'm wrong here-- but
this is what the behavior appears to be). If you tell it not to, it's
behavior becomes erratic and unpredictable. If I remember correctly,
Explorer will eventually crash. So, you let Explorer cache the icons-- big
deal. This presents you with a new problem: What do you do if you developed
a library that does most of the work for you? When I developed multiple
NSEs using the same library/wizard, I discovered that when I changed the
icons around I didn't always get the correct icons for the various NSEs.
Whichever NSE opened first got its icons reflected in the other NSE. A
workaround exists here too.
For your application object (CWinApp derived, maybe?), declare a few UINT
member variables (NOT STATIC!!!). In InitInstance(), initialize them like
so: m_yourIcon = (UINT)AfxGetApp()->LoadIcon( ICON_ID); You are casting the
HICON to a UINT. You'll see why in a moment.
Then, to be a good C++ encapsulator, add a getter (no setter!) to your
CWinApp derived class.
For your IExtractIcon::Extract()/GetIconLocation() implementation do
something like this:
STDMETHODIMP CNSEIcon::Extract(LPCTSTR pszFile,
UINT nIconIndex, HICON *phiconLarge,
HICON *phiconSmall, UINT nIconSize)
// Load the large version
*phiconLarge = reinterpret_cast<HICON>( nIconIndex );
// Load the small version
*phiconSmall = reinterpret_cast<HICON>( nIconIndex );
STDMETHODIMP CNSEIcon::GetIconLocation(UINT uFlags,
LPTSTR szIconFile, UINT cchMax,
int *piIndex, UINT *pwFlags)
// Tell the caller that the icon is
// allocated on a per-folder basis.
CNSEApp* pApp =
*pwFlags |= GIL_NOTFILENAME;
switch( m_type )
*piIndex = (( uFlags & GIL_OPENICON )
? pApp->OpenIcon() : pApp->ClosedIcon() );
*piIndex = IDI_DATA;
You have to load the icon into memory when the DLL is first loaded. If you
don't the behavior will not work as intended. I have no idea why a LoadIcon
works fine in InitInstance() but does not good in
ExtractIcon/GetIconLocation. Voodoo programming is sometimes necessary:(
> hi there,
> i want each of my subfolders to have different icons.
> to achieve this in the shell view list, i explicitly call
> IExtractIcon::GetIconLocation for each pidl in my enumerated list. it's a
> simple matter to then derive the icon required for that pidl - all works
> in the tree, i note the pidl of the folder within which GetUIObjectOf is
> called and check that in IExtractIcon::GetIconLocation. this works fine
> when stepping into my subfolders, but if i go back and select a folder's
> ancestor, the icon that is being displayed is incorrect.
> is there a generally accepted way of approaching this problem and a
> recommended strategy for displaying per-folder icons ?