首页  编辑  

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

Tags: /超级猛料/OS.操作系统/Shell.扩展/   Date Created:

使用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 SHITEMID (ANSI) }

        3: (cStr: array[0..MAX_PATH-1] of Char); { Buffer to fill in }

     end;

 

 uType告诉我们哪个字段保存了名称。注意:pOleStr必须由调用者释放!