This section presents an example illustrating how to retrieve the location of a special folder, walk an item identifier list, and use the IShellFolder interface to retrieve display names. The example is a console application that prints the display names of the folders a user would have to open to get to the Programs folder. To display them, the application would carry out these steps:
1.Retrieve the PIDL (obtain a pointer to an item identifier list) for the Programs folder by using the SHGetSpecialFolderLocation function.
2.Bind to the desktop folder (retrieve the folder's IShellFolder interface) by using the SHGetDesktopFolder function.
3.Walk the item identifier list and process elements as follows: print the subfolder's display name, bind to the subfolder, and release the parent folder's IShellFolder interface.
Before carrying out any of the preceding steps, the application uses the SHGetMalloc function to retrieve a pointer to the shell's IMalloc interface, which it saves in the following global variable.
// Global pointer to the shell's IMalloc interface.
LPMALLOC g_pMalloc;
The following example shows the application's main function. This function carries out all of the steps described previously, although it calls the application-defined GetNextItemID and CopyItemID functions to walk the item identifier list and the application-defined PrintStrRet function to print the display names. Code for these application-defined functions is shown following the code for the main function.
// main - the application's entrypoint function
int __cdecl main()
{
LPITEMIDLIST pidlPrograms;
LPSHELLFOLDER pFolder;
// Get the shell's allocator.
if (!SUCCEEDED(SHGetMalloc(&g_pMalloc)))
return 1;
// Get the PIDL for the Programs folder.
if (SUCCEEDED(SHGetSpecialFolderLocation(NULL,
CSIDL_PROGRAMS, &pidlPrograms))) {
// Start with the desktop folder.
if (SUCCEEDED(SHGetDesktopFolder(&pFolder))) {
LPITEMIDLIST pidl;
// Process each item identifier in the list.
for (pidl = pidlPrograms; pidl != NULL;
pidl = GetNextItemID(pidl)) {
STRRET sName;
LPSHELLFOLDER pSubFolder;
LPITEMIDLIST pidlCopy;
// Copy the item identifier to a list by itself.
if ((pidlCopy = CopyItemID(pidl)) == NULL)
break;
// Display the name of the subfolder.
if (SUCCEEDED(pFolder->lpVtbl->GetDisplayNameOf(
pFolder, pidlCopy, SHGDN_INFOLDER,
&sName)))
PrintStrRet(pidlCopy, &sName);
// Bind to the subfolder.
if (!SUCCEEDED(pFolder->lpVtbl->BindToObject(
pFolder, pidlCopy, NULL,
&IID_IShellFolder, &pSubFolder))) {
g_pMalloc->lpVtbl->Free(g_pMalloc, pidlCopy);
break;
}
// Free the copy of the item identifier.
g_pMalloc->lpVtbl->Free(g_pMalloc, pidlCopy);
// Release the parent folder and point to the
// subfolder.
pFolder->lpVtbl->Release(pFolder);
pFolder = pSubFolder;
}
// Release the last folder that was bound to.
if (pFolder != NULL)
pFolder->lpVtbl->Release(pFolder);
}
// Free the PIDL for the Programs folder.
g_pMalloc->lpVtbl->Free(g_pMalloc, pidlPrograms);
}
// Release the shell's allocator.
g_pMalloc->lpVtbl->Release(g_pMalloc);
return 0;
}
Following is the GetNextItemID function. Given a pointer to an element in an item identifier list, the function returns a pointer to the next element (or NULL if there are no more elements). The main function calls this function to walk the item identifier list for the Programs folder.
// GetNextItemID - points to the next element in an item identifier
// list.
// Returns a PIDL if successful or NULL if at the end of the list.
// pdil - previous element
LPITEMIDLIST GetNextItemID(LPITEMIDLIST pidl)
{
// Get the size of the specified item identifier.
int cb = pidl->mkid.cb;
// If the size is zero, it is the end of the list.
if (cb == 0)
return NULL;
// Add cb to pidl (casting to increment by bytes).
pidl = (LPITEMIDLIST) (((LPBYTE) pidl) + cb);
// Return NULL if it is null-terminating or a pidl otherwise.
return (pidl->mkid.cb == 0) ? NULL : pidl;
}
Following is the CopyItemID function. Given a pointer to an element in an item identifier list, the function allocates a new list containing only the specified element followed by a terminating zero. The main function uses this function to create single-element PIDLs, which it passes to IShellFolder member functions.
// CopyItemID - creates an item identifier list containing the first
// item identifier in the specified list.
// Returns a PIDL if successful or NULL if out of memory.
LPITEMIDLIST CopyItemID(LPITEMIDLIST pidl)
{
// Get the size of the specified item identifier.
int cb = pidl->mkid.cb;
// Allocate a new item identifier list.
LPITEMIDLIST pidlNew = (LPITEMIDLIST)
g_pMalloc->lpVtbl->Alloc(g_pMalloc, cb + sizeof(USHORT));
if (pidlNew == NULL)
return NULL;
// Copy the specified item identifier.
CopyMemory(pidlNew, pidl, cb);
// Append a terminating zero.
*((USHORT *) (((LPBYTE) pidlNew) + cb)) = 0;
return pidlNew;
}
The IShellFolder::GetDisplayNameOf member function returns a display name in a STRRET structure. The display name may be returned in one of three ways, which is specified by the uType member of the STRRET structure. The main function calls the following PrintStrRet function to print the display name.
// PrintStrRet - prints the contents of a STRRET structure.
// pidl - PIDL containing the display name if STRRET_OFFSET
// lpStr - address of the STRRET structure
void PrintStrRet(LPITEMIDLIST pidl, LPSTRRET lpStr)
{
LPSTR lpsz;
int cch;
switch (lpStr->uType) {
case STRRET_WSTR:
cch = WideCharToMultiByte(CP_OEMCP, WC_DEFAULTCHAR,
lpStr->pOleStr, -1, NULL, 0, NULL, NULL);
lpsz = (LPSTR) g_pMalloc->lpVtbl->Alloc(g_pMalloc, cch);
if (lpsz != NULL) {
WideCharToMultiByte(CP_OEMCP, WC_DEFAULTCHAR,
lpStr->pOleStr, -1, lpsz, cch, NULL, NULL);
printf("%s\n", lpsz);
g_pMalloc->lpVtbl->Free(g_pMalloc, lpsz);
}
break;
case STRRET_OFFSET:
printf("%s\n", ((char *) pidl) + lpStr->uOffset);
break;
case STRRET_CSTR:
printf("%s\n", lpStr->cStr);
break;
}
}