使用PIDL和显示名称

【勇芳软件工作室】汉化HomePreviousNext

本节介绍一个示例,说明如何检索特殊文件夹的位置,走一个项目标识符列表,并使用IShellFolder界面检索显示名称。该示例是一个控制台应用程序,用于打印用户必须打开以访问“程序”文件夹的文件夹的显示名称。要显示它们,应用程序将执行以下步骤:

1.使用SHGetSpecialFolderLocation功能读取程序文件夹的PIDL(获取项目标识符列表的指针)。

2.使用SHGetDesktopFolder功能绑定到桌面文件夹(检索文件夹的IShellFolder界面)。

3.按如下所示列出项目标识符列表和过程元素:打印子文件夹的显示名称,绑定到子文件夹,并释放父文件夹的IShellFolder界面。

在执行上述任何步骤之前,应用程序使用SHGetMalloc函数来检索指向shell的IMalloc接口的指针,它将保存在以下全局变量中。

//指向shell的IMalloc接口的全局指针。

LPMALLOC g_pMalloc;

以下示例显示了应用程序的主要功能。此函数执行前面描述的所有步骤,尽管它调用应用程序定义的GetNextItemID和CopyItemID函数来移动项目标识符列表和应用程序定义的PrintStrRet函数来打印显示名称。这些应用程序定义函数的代码将按照主函数的代码显示。

// main - 应用程序的entrypoint函数

int __cdecl main()

{

LPITEMIDLIST pidlPrograms;

LPSHELLFOLDER pFolder;

//获取shell的分配器。

if(!SUCCEEDED(SHGetMalloc(& g_pMalloc)))

return 1;

//获取程序文件夹的PIDL。

if(SUCCEEDED(SHGetSpecialFolderLocation(NULL,

CSIDL_PROGRAMS,& pidlPrograms))){

//从桌面文件夹开始。

if(SUCCEEDED(SHGetDesktopFolder(& pFolder))){

LPITEMIDLIST pidl;

//处理列表中的每个项目标识符。

for (pidl = pidlPrograms; pidl != NULL;

pidl = GetNextItemID(pidl)) {

STRRET sName;

LPSHELLFOLDER pSubFolder;

LPITEMIDLIST pidlCopy;

//将项目标识符本身复制到列表中。

if ((pidlCopy = CopyItemID(pidl)) == NULL)

break;

//显示子文件夹的名称。

if(SUCCEEDED(pFolder- > lpVtbl- > GetDisplayNameOf(

pFolder,pidlCopy,SHGDN_INFOLDER,

& SNAME)))

PrintStrRet(pidlCopy, &sName);

//绑定到子文件夹。

if(!SUCCEEDED(pFolder- > lpVtbl- > BindToObject(

pFolder,pidlCopy,NULL,

IID_IShellFolder pSubFolder)))

g_pMalloc->lpVtbl->Free(g_pMalloc, pidlCopy);

break;

}

//释放项目标识符的副本。

g_pMalloc->lpVtbl->Free(g_pMalloc, pidlCopy);

//释放父文件夹并指向

//子文件夹。

pFolder->lpVtbl->Release(pFolder);

pFolder = pSubFolder;

}

//释放绑定到的最后一个文件夹。

if (pFolder != NULL)

pFolder->lpVtbl->Release(pFolder);

}

//为程序文件夹释放PIDL。

g_pMalloc->lpVtbl->Free(g_pMalloc, pidlPrograms);

}

//释放shell的分配器。

g_pMalloc->lpVtbl->Release(g_pMalloc);

return 0;

}

以下是GetNextItemID函数。给定一个指向项目标识符列表中的元素的指针,该函数返回一个指向下一个元素的指针(如果没有更多元素,则返回NULL)。主要函数调用此函数来移动“程序”文件夹的项目标识符列表。

// GetNextItemID - 指向项标识符中的下一个元素
//列表。

//如果成功返回PIDL,如果在列表的末尾返回NULL。

// pdil - 上一个元素

LPITEMIDLIST GetNextItemID(LPITEMIDLIST pidl)

{

//获取指定项目标识符的大小。

int cb = pidl->mkid.cb;

//如果大小为零,它是列表的结尾。

if (cb == 0)

return NULL;

//将cb添加到pidl(转换为逐字节增加)。

pidl = (LPITEMIDLIST) (((LPBYTE) pidl) + cb);

//如果为空终止则返回NULL,否则返回一个pidl。

return (pidl->mkid.cb == 0) ? NULL : pidl;

}

以下是CopyItemID函数。给定指向项目标识符列表中的元素的指针,该函数分配一个仅包含指定元素的新列表,后跟终止零。主要函数使用此函数创建单元素PIDL,它将传递给IShellFolder成员函数。

// CopyItemID - 创建包含第一个的项目标识符列表

//指定列表中的项目标识符。

//如果成功返回PIDL,如果内存不足则返回NULL。

LPITEMIDLIST CopyItemID(LPITEMIDLIST PIDL)

{

//获取指定项目标识符的大小。

int cb = pidl->mkid.cb;

//分配一个新的项目标识符列表。

LPITEMIDLIST pidlNew = (LPITEMIDLIST)

g_pMalloc- > lpVtbl- > Alloc(g_pMalloc,cb + sizeof(USHORT));

if (pidlNew == NULL)

return NULL;

//复制指定的项目标识符。

CopyMemory(pidlNew, pidl, cb);

//附加终止零。

*((USHORT *) (((LPBYTE) pidlNew) + cb)) = 0;

return pidlNew;

}

IShellFolder::GetDisplayNameOf成员函数返回STRRET结构中的显示名称。显示名称可以以STRRET结构的UTYPE成员指定的三种方式之一返回。主要函数调用以下PrintStrRet函数来打印显示名称。

// PrintStrRet - 打印STRRET结构的内容。

// pidl - 如果STRRET_OFFSET包含显示名称的PIDL

// lpStr - STRRET结构的地址

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;

}

}