[转载]如何列举一个文件夹的内容``
?为了列举Windows的Namespace中的对象,我们不得不使用到IShellFolder接口。每个容器对象(通常是文件夹)都必须实现这个接口。?
?以下是IShellFolder的声明 (ShlObj.pas):
?
?IShellFolder = interface(IUnknown)
???[SID_IShellFolder]
???function ParseDisplayName(hwndOwner: HWND;
????pbcReserved: Pointer; lpszDisplayName: POLESTR; out pchEaten: ULONG;
????out ppidl: PItemIDList; var dwAttributes: ULONG): HResult; stdcall;
???function EnumObjects(hwndOwner: HWND; grfFlags: DWORD;
????out EnumIDList: IEnumIDList): HResult; stdcall;
???function BindToObject(pidl: PItemIDList; pbcReserved: Pointer;
????const riid: TIID; out ppvOut): HResult; stdcall;
???function BindToStorage(pidl: PItemIDList; pbcReserved: Pointer;
????const riid: TIID; out ppvObj): HResult; stdcall;
???function CompareIDs(lParam: LPARAM;
????pidl1, pidl2: PItemIDList): HResult; stdcall;
???function CreateViewObject(hwndOwner: HWND; const riid: TIID;
????out ppvOut): HResult; stdcall;
???function GetAttributesOf(cidl: UINT; var apidl: PItemIDList;
????var rgfInOut: UINT): HResult; stdcall;
???function GetUIObjectOf(hwndOwner: HWND; cidl: UINT; var apidl: PItemIDList;
????const riid: TIID; prgfInOut: Pointer; out ppvOut): HResult; stdcall;
???function GetDisplayNameOf(pidl: PItemIDList; uFlags: DWORD;
????var lpName: TStrRet): HResult; stdcall;
???function SetNameOf(hwndOwner: HWND; pidl: PItemIDList; lpszName: POLEStr;
????uFlags: DWORD; var ppidlOut: PItemIDList): HResult; stdcall;
??end;
?
?主要的方法就是EnumObjects()和BindToObject()。前者用于列举当前文件夹中的对象,后者用于获取容器对象的IShellFolder接口。
?
?EnumObjects()返回一个IEnumIDList接口,用于遍历所有的对象。通过grfFlags参数,你可以控制列举的对象类型,这个参数可以是以下值或其组合:
?
???SHCONTF_FOLDERS = 32,???? // for shell browser
???SHCONTF_NONFOLDERS = 64,???// for default view
???SHCONTF_INCLUDEHIDDEN = 128,?// for hidden or system objects
?
?IEnumIDList的声明如下:
?
?IEnumIDList = interface(IUnknown)
???[SID_IEnumIDList]
???function Next(celt: ULONG; out rgelt: PItemIDList;
????var pceltFetched: ULONG): HResult; stdcall;
???function Skip(celt: ULONG): HResult; stdcall;
???function Reset: HResult; stdcall;
???function Clone(out ppenum: IEnumIDList): HResult; stdcall;
??end;
?
?Next()返回一个PIDL(对象标志符列表指针)数组,上至"celt"。"pceltFetched"保存获取的PIDL的数目。Skip()向前移动"celt"对象,而Reset()返回列举列表的最开始处。使用Clone()方法你可以得到一个与当前状态相同的IEnumIDList接口的拷贝,非常有用,例如你可以在列举的时候放置一个“书签”。
?
?这里是一个列举桌面上所有对象的例子:
?...
?var
??Desktop: IShellFolder
??EnumIDLIst: IEnumIDList;
??CurPidl: PItemIDLIst;
??Fetched: ULONG;
?begin
??if SHGetDesktopFolder(Desktop) <> NOERROR then
??begin
???if Desktop.EnumObjects(Handle, SHCONTF_FOLDERS, EnumIDList) = NOERROR then
???begin
???? // Retrieve objects one at a time...
???? while EnumIDList.Next(1, CurPidl, Fetched) = S_OK do
???? begin
????? ... // Add code here to do something with the objects
????? CoTaskMemFree(CurPidl); // Remember to free PIDLs!
???? end;
???end;
??end;
?end;
?
?要列举一个子文件夹的内容,我们必须获取它的IShellFodler接口。如果父文件夹已经包含了一个IShellFodler接口,而且ChildPidl包含一个有效的子文件夹的PIDL(例如用IEnumIDList.Next()返回的),我们可以这样做:
?
?var
??ChildFolder: IShellFolder;
?...
?if ParentFolder.BindToObject(ChildPidl, nil, IID_IShellFolder, pointer(ChildFolder)) <> NOERROR then
?begin
??with ChildFolder do
??begin
???// 使用新的IShellFolder接口做些事情...
??end;
?
?end;
?
?IShellFolder其余的方法用于操作对象:
?
?ParseDisplayName() 用于将一个显示名称(例如路径)翻译为对象标志符列表。
?
?CompareIDs() 判断两个文件对象或者文件夹的相对顺序,使用它们的对象标志符列表。
?
?GetAttributeOf() 获取一个或者多个文件对象或者子文件夹的属性。可以为以下值:
?
?SFGAO_CANCOPY 指定文件对象或者文件夹可以被复制
?SFGAO_CANDELETE 指定文件对象或者文件夹可以被删除
?SFGAO_CANLINK 可以给指定文件对象或者文件夹生成快捷方式
?SFGAO_CANMOVE 指定文件对象或者文件夹可以被移动
?SFGAO_CANRENAME 指定文件对象或者文件夹可以被重命名
?SFGAO_CAPABILITYMASK 性能(capability)标志位掩码
?SFGAO_DROPTARGET 指定文件对象或者文件夹是拖动目标(drop target)
?SFGAO_HASPROPSHEET 指定文件对象或者文件夹有属性页
?SFGAO_DISPLAYATTRMASK 显示属性掩码
?SFGAO_GHOSTED The 指定文件对象或者文件夹显示时应该使用虚图标
?SFGAO_LINK 指定文件对象是快捷方式
?SFGAO_READONLY 指定文件对象或者文件夹是只读的
?SFGAO_SHARE 指定文件夹是共享的
?SFGAO_CONTENTSMASK 内容属性掩码
?SFGAO_HASSUBFOLDER 指定文件夹含有子文件夹(因此,可以在Windows的Explorer的左边面板里展开
?SFGAO_FILESYSTEM 指定文件对象或者文件夹是系统文件的一部分
?SFGAO_FILESYSANCESTOR 指定文件夹包含一个或者多个系统文件夹
?SFGAO_FOLDER 指定对象是文件夹
?SFGAO_REMOVABLE 指定文件对象或者文件夹在可移动介质上(如软盘)
?
?例如,我们可以使用GetAttributeOf来选择对应的图标。
?
?GetDisplayNameOf()和SetName()获取或者设置对象名。
?
?注意,显示名是用一个不同的结构返回的:
?
?_STRRET = record
??? uType: UINT;???????{ One of the STRRET_* values }
??? case Integer of
???? 0: (pOleStr: LPWSTR);??????????{ must be freed by caller?}
???? 1: (pStr: LPSTR);????????????{ NOT USED }
???? 2: (uOffset: UINT);???????????{ Offset into SHITEMID (ANSI) }
???? 3: (cStr: array[0..MAX_PATH-1] of Char); { Buffer to fill in }
???end;
?
?uType告诉我们哪个字段保存了名称。注意:pOleStr必须由调用者释放!