Microsoft KB Archive/192055

{|
 * width="100%"|

PRB: System Image List Does Not Contain Overlay Images

 * }

Q192055

-

The information in this article applies to:


 * Microsoft Win32 Software Development Kit (SDK), on platform(s):
 * the operating system: Microsoft Windows NT
 * Microsoft Windows NT Server version 4.0
 * Microsoft Windows NT Workstation version 4.0
 * Microsoft Internet Explorer (Programming) versions 4.0, 4.01

-

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.

Additional query words:

Keywords : kbIE400 kbie401 kbSDKPlatform kbSDKWin32 kbshell kbGrpDSShell

Issue type : kbprb

Technology : kbWin32SDKSearch kbAudDeveloper kbSDKSearch kbWin32sSearch