PRB: System Image List Does Not Contain Overlay Images (192055)
The information in this article applies to:
- Microsoft Platform Software Development Kit (SDK) 1.0, when used with:
- the operating system: Microsoft Windows NT
- Microsoft Windows NT Server 4.0
- Microsoft Windows NT Workstation 4.0
- Microsoft Internet Explorer (Programming) 4.0
- Microsoft Internet Explorer (Programming) 4.01
This article was previously published under Q192055 SYMPTOMS
When you are using the system image list in an application, you might want
to be able to use the standard overlay images, such as the shared and
shortcut overlay images. However, when you have the Internet Explorer 4.0x
Desktop Update installed on Windows NT 4.0, the standard overlay images are
not contained in the process' copy of the system image list.
CAUSE
You can obtain the handle to the system image list with a function call
similar to the following:
HIMAGELIST himl;
SHFILEINFO sfi;
himl = (HIMAGELIST)SHGetFileInfo(TEXT("C:\\"), 0, &sfi,
sizeof(SHFILEINFO), SHGFI_SYSICONINDEX);
On Windows 95 and Windows 98, this function returns the handle of the
actual system image list. However, on Windows NT version 4.0 this function
returns a handle to a copy of the system image. Each process gets its own
copy of the system image list. Windows NT does this to maintain security
requirements so that one application cannot destroy the system image list.
The proper images are added to the process' copy of the system image list
whenever a call to SHGetFileInfo is made to retrieve the icon index for a
specific item type.
The copy of the system image list on Windows NT version 4.0 initially
contains the standard document and folder icons, as well as the shared and
shortcut overlay images. However, when you have the Internet Explorer 4.0x
Desktop Update installed then the standard overlay images are not included
in the copy of the system image list. You cannot add them by calling
SHGetFileInfo because the Internet Explorer 4.0x desktop Update implements
the IShellIconOverlay interface to provide callers with the proper overlay
index.
RESOLUTION
To add the standard overlay images to the process' copy of the system image
list with the Desktop Update, you need to get an IShellIconOverlay
interface pointer for a file system folder and call its GetOverlayIndex
method for a shortcut (.lnk) file that is contained in the folder. This
causes both standard overlay images to be added to the process' copy of the
system image list. GetOverlayIndex also registers the overlay images using
the ImageList_SetOverlayImage function.
The following function retrieves the handle of the system image list, and,
if you are running under Windows NT version 4.0, it creates a temporary
.lnk file. Then it gets the IShellIconOverlay interface from the parent
folder and calls IShellIconOverlay::GetOverlayIndex, passing the PIDL for
the temporary .lnk file. Finally, the handle to the system image list is
returned from the function. The fSmall flag indicates if the small or large
image list is being requested. If fSmall is zero, the system image list
that contains large icons is retrieved. If fSmall is non-zero, the system
image list that contains large icons is retrieved. If Internet Explorer 4.0
with the Desktop Update is not installed on your computer, the function
cannot retrieve the IShellIconOverlay interface, so the function will
simply return the image list handle.
/********************************************************************
GetSystemImageList()
********************************************************************/
HIMAGELIST GetSystemImageList(BOOL fSmall)
{
HIMAGELIST himl;
SHFILEINFO sfi;
himl = (HIMAGELIST)SHGetFileInfo(TEXT("C:\\"), 0, &sfi,
sizeof(SHFILEINFO), SHGFI_SYSICONINDEX |
(fSmall ? SHGFI_SMALLICON : SHGFI_LARGEICON));
/*
Do a version check first because you only need to use this code on
Windows NT version 4.0.
*/
OSVERSIONINFO vi;
vi.dwOSVersionInfoSize = sizeof(vi);
GetVersionEx(&vi);
if(VER_PLATFORM_WIN32_WINDOWS == vi.dwPlatformId)
return himl;
/*
You need to create a temporary, empty .lnk file that you can use to
pass to IShellIconOverlay::GetOverlayIndex. You could just enumerate
down from the Start Menu folder to find an existing .lnk file, but
there is a very remote chance that you will not find one. By creating
your own, you know this code will always work.
*/
HRESULT hr;
IShellFolder *psfDesktop = NULL;
IShellFolder *psfTempDir = NULL;
IMalloc *pMalloc = NULL;
LPITEMIDLIST pidlTempDir = NULL;
LPITEMIDLIST pidlTempFile = NULL;
TCHAR szTempDir[MAX_PATH];
TCHAR szTempFile[MAX_PATH] = TEXT("");
TCHAR szFile[MAX_PATH];
HANDLE hFile;
int i;
OLECHAR szOle[MAX_PATH];
DWORD dwAttributes;
DWORD dwEaten;
IShellIconOverlay *psio = NULL;
int nIndex;
// Get the desktop folder.
hr = SHGetDesktopFolder(&psfDesktop);
if(FAILED(hr))
goto exit;
// Get the shell's allocator.
hr = SHGetMalloc(&pMalloc);
if(FAILED(hr))
goto exit;
// Get the TEMP directory.
if(!GetTempPath(MAX_PATH, szTempDir))
{
/*
There might not be a TEMP directory. If this is the case, use the
Windows directory.
*/
if(!GetWindowsDirectory(szTempDir, MAX_PATH))
{
hr = E_FAIL;
goto exit;
}
}
// Create a temporary .lnk file.
if(szTempDir[lstrlen(szTempDir) - 1] != '\\')
lstrcat(szTempDir, TEXT("\\"));
for(i = 0, hFile = INVALID_HANDLE_VALUE;
INVALID_HANDLE_VALUE == hFile;
i++)
{
lstrcpy(szTempFile, szTempDir);
wsprintf(szFile, TEXT("temp%d.lnk"), i);
lstrcat(szTempFile, szFile);
hFile = CreateFile( szTempFile,
GENERIC_WRITE,
0,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Do not try this more than 100 times.
if(i > 100)
{
hr = E_FAIL;
goto exit;
}
}
// Close the file you just created.
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
// Get the PIDL for the directory.
LocalToWideChar(szOle, szTempDir, MAX_PATH);
hr = psfDesktop->ParseDisplayName( NULL,
NULL,
szOle,
&dwEaten,
&pidlTempDir,
&dwAttributes);
if(FAILED(hr))
goto exit;
// Get the IShellFolder for the TEMP directory.
hr = psfDesktop->BindToObject( pidlTempDir,
NULL,
IID_IShellFolder,
(LPVOID*)&psfTempDir);
if(FAILED(hr))
goto exit;
/*
Get the IShellIconOverlay interface for this folder. If this fails,
it could indicate that you are running on a pre-Internet Explorer 4.0
shell, which doesn't support this interface. If this is the case, the
overlay icons are already in the system image list.
*/
hr = psfTempDir->QueryInterface(IID_IShellIconOverlay, (LPVOID*)&psio);
if(FAILED(hr))
goto exit;
// Get the PIDL for the temporary .lnk file.
LocalToWideChar(szOle, szFile, MAX_PATH);
hr = psfTempDir->ParseDisplayName( NULL,
NULL,
szOle,
&dwEaten,
&pidlTempFile,
&dwAttributes);
if(FAILED(hr))
goto exit;
/*
Get the overlay icon for the .lnk file. This causes the shell
to put all of the standard overlay icons into your copy of the system
image list.
*/
hr = psio->GetOverlayIndex(pidlTempFile, &nIndex);
exit:
// Delete the temporary file.
DeleteFile(szTempFile);
if(psio)
psio->Release();
if(INVALID_HANDLE_VALUE != hFile)
CloseHandle(hFile);
if(psfTempDir)
psfTempDir->Release();
if(pMalloc)
{
if(pidlTempFile)
pMalloc->Free(pidlTempFile);
if(pidlTempDir)
pMalloc->Free(pidlTempDir);
pMalloc->Release();
}
if(psfDesktop)
psfDesktop->Release();
return himl;
}
STATUS
This behavior is by design.
MORE INFORMATION
On computers that do not have the Internet Explorer 4.0x Desktop Update
installed, the overlay indexes (not to be confused with the image index--
see the documentation for ImageList_SetOverlayImage for more information)
for the two standard overlay images are fixed. On these systems, one is the
overlay index for the shared overlay and two is the overlay index for the
shortcut overlay. However, if the installed shell exposes the
IShellIconOverlay interface for folders, you should use
IShellIconOverlay::GetOverlayIndex to obtain the overlay index. This will
allow you to add additional overlay images in the future and allow
applications to retrieve the correct overlay index without having to hard-
code these indexes.
To maintain backward compatibility, the overlay indexes for the shared and
shortcut overlays remain fixed.
Modification Type: | Minor | Last Reviewed: | 7/11/2005 |
---|
Keywords: | kbprb kbshell KB192055 |
---|
|