|
Using PIDLs and Display Names
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:
- Retrieve the PIDL (obtain a pointer to an item identifier list) for the
Programs folder by using the SHGetSpecialFolderLocation function.
- Bind to the desktop folder (retrieve the folder's IShellFolder interface) by using the SHGetDesktopFolder function.
- 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
- oid 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;
}
}
| Last news from Greatis Software |
 |
|
Nostalgia .Net |
|
.Net is powerful, but not all-powerful, so sometimes we need to use Win32 API for our .Net applications. It's simple enough with Platform Invoke if you have Win32 skill, but we do not always have time to dig the ancient documentation, declare the special types that are compatible with Win32, find the values of the Win32's constants and so on. Nostalgia .Net offers several simple-to-use classes, and components that will allow you to forget about the headache of Win32 and just use the power of Win32 in your application the same way as you use the native. Net classes. More » |
| Recommended software for developers |
 |
|
Ultimate Pack |
|
Component pack for Delphi and C++ Builder that contains runtime form designer, runtime object inspector, print suite and much more for the very special price. More » |
 |
|
Form Designer .Net |
|
Unique runtime form design solution that allows to edit any form in .Net WinForms application at runtime with full source codes for only 300 euro! More » |
 |
|
Print Suite .Net |
|
Print Suite .Net is a set of components for easy printing texts, images and grids from your WinForms applications. Full C# source codes are available More » |
 |
|
Gradient Controls .Net |
|
Gradient Controls .Net offers controls with gradient background feature. Labels, panels and so on... Full C# source codes are available More » |
 |
|
Greatis iGrid |
|
iGrid plots drawing grid right over your desktop, so you can use it everywhere, with any drawing application without any special plugins for different graphic editors. More » |
All the contacts and projectsDmitry Vasiliev (just.dmitry)
Related LinksSoftware for Visual Studio .NET developers Software for Delphi and C++ Builder developers Software for Visual Basic 6 developers Delphi Tips&Tricks MegaDetailed.NET More Online Helps Win32 Programmer's Reference Win32 Multimedia Programmer's Reference OLE Programmer's Reference Microsoft Windows Pen API Programmer's Reference Microsoft Windows Sockets 2 Reference Microsoft Windows Telephony API (TAPI) Programmer's Reference Unix Manual Pages
|