使用IShellFolder接口--如何列举一个文件夹的内容

I

import

Unregistered / Unconfirmed
GUEST, unregistred user!
使用IShellFolder接口--如何列举一个文件夹的内容
为了列举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 ****EMID (ANSI) }
3: (cStr: array[0..MAX_PATH-1] of Char); { Buffer to fill in }
end;
 
uType告诉我们哪个字段保存了名称。注意:pOleStr必须由调用者释放!
 

Similar threads

顶部