一、几个概念(摘)
1.外壳名字空间:
在WINDOWS中又叫外壳名字空间(Shell Name Space).外壳名字空间是Windows下的标准文件系统,它大大扩展了Dos文件系统,形成了以“桌面”(Desktop)为根的单一的文件系统树,原有的C盘、D盘等目录树变成“我的电脑”这一外壳名字空间子树的下一级子树,而像“控制面板”、“回收站”、“网上邻居”等应用程序及“打印机”等设备也被虚拟成了外壳名字空间中的节点。另外,与DOS中物理存储只能和文件系统项一一对应这一点不同的是,一个实际目录在外壳名字空间中可以表现为不同的项。例如“我的文档”与“C:/MyDocuments”其实都指向“C:/My Documents”目录,但它们在外壳名字空间中是不同的项。
2. 外壳名字空间下的路径: PIDL
PIDL是一个元素类型为ITEMIDLIST结构的数组,数组中元素的个数是未知的,但紧接着数组末尾的必是一个双字节的零。每个数组元素代表了外壳名字空间树中的一层(即一个文件夹或文件),数组中的前一元素代表的是后一元素的父文件夹。由此可见, PIDL实际上就是指向一块由若干个顺序排列的ITEMIDLIST结构组成、并在最后有一个双字节零的空间的指针。所以PIDL的类型就被Windows定义为ITEMIDLIST结构的指针。
PIDL亦有“绝对路径”与“相对路径”的概念。表示“相对路径”的PIDL只有一个ITEMIDLIST结构的元素,用于标识相对于父文件夹的“路径”;表示“绝对路径”的PIDL(简称为“绝对PIDL”)有若干个ITEMIDLIST结构的元素,第一个元素表示外壳名字空间根文件夹(“桌面”)下的某一子文件夹A,第二个元素则表示文件夹A下的某一子文件夹B,其余依此类推。这样绝对PIDL就通过保存一条从“桌面”下的直接子文件夹或文件的绝对PIDL与相对PIDL是相同的,而其他的文件夹或文件的相对PIDL就只是其绝对PIDL的最后一部分了。由于所有的PIDL都是从桌面下的某一个子文件夹开始的,所以对于桌面本身来说,它的PIDL数组显然一个元素都没有。这样就只剩下PIDL数组最后的那个双字节的零了。所以,“桌面”的PIDL就是一个16位的零。
二、几个API
1.HRESULT SHGetSpecialFolderLocation(
HWND hwndOwner,
int nFolder, //CSIDL
LPITEMIDLIST *ppidl //返回CSIDL所对应的绝对PIDL(输出)
);
2.DWORD_PTR SHGetFileInfo(
LPCTSTR pszPath, //uFlags含SHGFI_PIDL时为绝对PIDL(输入)
DWORD dwFileAttributes, //绝对PIDL所对应文件的 file attribute flags (输出)
SHFILEINFO *psfi, //返回file information
UINT cbFileInfo, //SHFILEINFO结构大 UINT uFlags //指定你所要获取的信息
); //该函数返回系统HIMAGELIST
说明:
typedef struct _SHFILEINFO {
HICON hIcon;
int iIcon; //图标索引
DWORD dwAttributes; //文件属性
TCHAR szDisplayName[MAX_PATH]; // 显示名称
TCHAR szTypeName[80]; //文件类型:一个值对应一个二进制位
} SHFILEINFO;
uFlags :SHGFI_DISPLAYNAME | SHGFI_TYPENAME :psfi返回中包含显示名称和文件类型 (其他类推)
3.HRESULT SHGetDesktopFolder(
IShellFolder** ppshf //f返回桌面IShellFolder接口
);
IShellFolder的几个方法:
(1).BingToObject 获取子文件夹的IShellFolder接口
(2).EnumObject获取IEnumIDList ,IEnumIDList ->Next方法获取子文件的相对PIDL(详见MSDN)
(3)GetAttributesOf获取文件属性
注意事项:参数中是绝对PIDL还是相对PIDL。SHGet绝对,IShellFolder相对。PIDL用IMalloc接口开辟空间
三、仿系统目录树
注:本程序在VS2005编译通过(存在小Bug:树节点的加号要展开后才显示,待修改)。
下面是原码
//
#pragma once
#include " afxcmn.h "
// CBrowseSysTreeDlg 对话框
class CBrowseSysTreeDlg : public CDialog
... {
// 构造
public:
CBrowseSysTreeDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
enum ...{ IDD = IDD_BROWSESYSTREE_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
//添加
protected:
HTREEITEM CreateFolderNode(LPITEMIDLIST lpPidl,HTREEITEM hParent);
BOOL AttachFolders(HTREEITEM hNode);
void FreeNode(HTREEITEM hNode);
// 实现
protected:
HICON m_hIcon;
CTreeCtrl m_ctrlTree;
CImageList m_imageList;
IMalloc* m_pMalloc;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnNMDblclkSysTree(NMHDR *pNMHDR, LRESULT *pResult);
public:
afx_msg void OnTvnItemexpandingSysTree(NMHDR *pNMHDR, LRESULT *pResult);
public:
afx_msg void OnDestroy();
} ;
//
#include " stdafx.h "
#include " BrowseSysTree.h "
#include " BrowseSysTreeDlg.h "
#include " shlobj.h "
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialog
... {
public:
CAboutDlg();
// 对话框数据
enum ...{ IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
} ;
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
... {
}