知识大全 用Delphi实现Windows文件夹管理树

Posted

篇首语:古人已用三冬足,年少今开万卷余。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 用Delphi实现Windows文件夹管理树相关的知识,希望对你有一定的参考价值。

用Delphi实现Windows文件夹管理树  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  摘要 本文利用Windows名空间所提供的IShellFolder接口 用Delphi实现了文件夹管理树的生成

  关键字 文件夹 接口 Delphi

  一 概述

  Windows / 视觉感观上区别Windows 的一个重要方面就是大量采用了树形视图控件 资源管理器左侧的文件夹管理树便是如此 它将本地和网络上的文件夹和文件等资源以层次树的方式罗列出来 为用户集中管理计算机提供了极大便利 同时在外貌上也焕然一新 Delphi为我们提供了大量Windows标准控件 但遗憾的是在目录浏览方面却只提供了一个Windows 样式的DirectoryListBox(Delphi 的测试版也是如此) 因此 在Delphi中实现Windows文件夹管理树对开发更 地道 的Windows程序有着重大意义

  二 实现原理

  Windows文件夹管理树的实现实质上是对Windows名空间(Namespace)的遍历 名空间中每个文件夹都提供了一个IShellFolder接口 遍历名空间的方法是

   )调用SHGetDesktopFolder函数获得桌面文件夹的IShellFolder接口 桌面文件夹是文件夹管理树的根节点

   )再调用所获得的IShellFolder接口的EnumObjects成员函数列举出子文件夹

   )调用IShellFolder的BindToObject成员函数获得子文件夹的IShellFolder接口 )重复步骤 ) )列举出某文件夹下的所有子文件夹 只至所获得的IShellFolder接口为nil为止

  下面解释将要用到的几个主要函数 它们在ShlObj单元中定义

   )function SHGetDesktopFolder(var ppshf: IShellFolder): HResult;

  该函数通过ppshf获得桌面文件夹的IShellFolder接口

   )function IShellFolder EnumObjects(hwndOwner: HWND; grfFlags: DWORD;out EnumIDList: IEnumIDList): HResult;

  该函数获得一个IEnumIDList接口 通过调用该接口的Next等函数可以列举出IShellFolder接口所对应的文件夹的内容 内容的类型由grfFlags来指定 我们需要列举出子文件夹来 因此grfFlags的值指定为SHCONTF_FOLDERS HwndOwner是属主窗口的句柄

   )function IShellFolder BindToObject(pidl: PItemIDList; pbcReserved: Pointer;const riid: TIID; out ppvOut: Pointer): HResult;

  该函数获得某个子文件夹的IShellFolder接口 该接口由ppvOut返回 pidl是一个指向元素标识符列表的指针 Windows / 中用元素标识符和元素标识符列表来标识名空间中的对象 它们分别类似于文件名和路径 需要特别指出的是 pidl作为参数传递给Shell API函数时 必须是相对于桌面文件夹的绝对路径 而传递给IShellFolder接口的成员函数时 则应是相对于该接口所对应文件夹的相对路径 pbcReserved应指定为nil riid则应指定为IID_IShellFolder

  其它函数可以查阅Delphi提供的《Win Programmer s Reference》

  三 程序清单

  下面的源代码在Windows 中实现 并在Windows 测试版中测试无误(程序运行结果如图 所示) 有兴趣的读者可以将其改写成Delphi组件 以备常用

unit BrowseTreeView;

interface

uses

Windows Messages SysUtils Classes Graphics Controls Forms Dialogs

ShlObj ComCtrls;

type

PTreeViewItem = ^TTreeViewItem;

TTreeViewItem = record

ParentFolder: IShellFolder; // 接点对应的文件夹的父文件夹的IShellFolder接口

Pidl FullPidl: PItemIDList; // 接点对应的文件夹的相对和绝对项目标识符列表

HasExpanded: Boolean; // 接点是否展开

end;

TForm = class(TForm)

TreeView : TTreeView;

procedure FormDestroy(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure TreeView Expanding(Sender: TObject; Node: TTreeNode;

var AllowExpansion: Boolean);

private

FItemList: TList;

procedure SetTreeViewImageList;

procedure FillTreeView(Folder: IShellFolder; FullPIDL: PItemIDList; ParentNode: TTreeNode);

end;

var

Form : TForm ;

implementation

$R * DFM

uses

ActiveX ComObj ShellAPI CommCtrl;

// 以下是几个对项目标识符进行操作的函数

procedure DisposePIDL(ID: PItemIDList);

var

Malloc: IMalloc;

begin

if ID = nil then Exit;

OLECheck(SHGetMalloc(Malloc));

Malloc Free(ID);

end;

function CopyItemID(ID: PItemIDList): PItemIDList;

var

Malloc: IMalloc;

begin

Result := nil;

OLECheck(SHGetMalloc(Malloc));

if Assigned(ID) then

begin

Result := Malloc Alloc(ID^ mkid cb + sizeof(ID^ mkid cb));

CopyMemory(Result ID ID^ mkid cb + sizeof(ID^ mkid cb));

end;

end;

function NextPIDL(ID: PItemIDList): PItemIDList;

begin

Result := ID;

Inc(PChar(Result) ID^ mkid cb);

end;

function GetPIDLSize(ID: PItemIDList): Integer;

begin

Result := ;

if Assigned(ID) then

begin

Result := sizeof(ID^ mkid cb);

while ID^ mkid cb <> do

begin

Inc(Result ID^ mkid cb);

ID := NextPIDL(ID);

end;

end;

end;

function CreatePIDL(Size: Integer): PItemIDList;

var

Malloc: IMalloc;

HR: HResult;

begin

Result := nil;

HR := SHGetMalloc(Malloc);

if Failed(HR) then Exit;

try

Result := Malloc Alloc(Size);

if Assigned(Result) then

FillChar(Result^ Size );

finally

end;

end;

function ConcatPIDLs(ID ID : PItemIDList): PItemIDList;

var

cb cb : Integer;

begin

if Assigned(ID ) then

cb := GetPIDLSize(ID ) sizeof(ID ^ mkid cb)

else

cb := ;

cb := GetPIDLSize(ID );

Result := CreatePIDL(cb + cb );

if Assigned(Result) then

begin

if Assigned(ID ) then

CopyMemory(Result ID cb );

CopyMemory(PChar(Result) + cb ID cb );

end;

end;

// 将二进制表示的项目标识符列表转换成有可识的项目名

function GetDisplayName(Folder: IShellFolder; PIDL: PItemIDList;

ForParsing: Boolean): String;

var

StrRet: TStrRet;

P: PChar;

Flags: Integer;

begin

Result := ;

if ForParsing then

Flags := SHGDN_FORPARSING

else

Flags := SHGDN_NORMAL;

Folder GetDisplayNameOf(PIDL Flags StrRet);

case StrRet uType of

STRRET_CSTR:

SetString(Result StrRet cStr lStrLen(StrRet cStr));

STRRET_OFFSET:

begin

P := @PIDL mkid abID[StrRet uOffset sizeof(PIDL mkid cb)];

SetString(Result P PIDL mkid cb StrRet uOffset);

end;

STRRET_WSTR:

Result := StrRet pOleStr;

end;

end;

function GetIcon(PIDL: PItemIDList; Open: Boolean): Integer;

const

IconFlag = SHGFI_PIDL or SHGFI_SYSICONINDEX or SHGFI_SMALLICON;

var

FileInfo: TSHFileInfo;

Flags: Integer;

begin

if Open then

Flags := IconFlag or SHGFI_OPENICON

else

Flags := IconFlag;

SHGetFileInfo(PChar(PIDL) FileInfo sizeof(TSHFileInfo) Flags);

Result := FileInfo iIcon;

end;

// 获得每个文件夹在系统中的图标

procedure GetItemIcons(FullPIDL: PItemIDList; TreeNode: TTreeNode);

begin

with TreeNode do

begin

ImageIndex := GetIcon(FullPIDL False);

SelectedIndex := GetIcon(FullPIDL True);

end;

end;

// 获得系统的图标列表

procedure TForm SetTreeViewImageList;

var

ImageList: THandle;

FileInfo: TSHFileInfo;

begin

ImageList := SHGetFileInfo(PChar( C:\\ ) FileInfo

sizeof(TSHFileInfo) SHGFI_SYSICONINDEX or SHGFI_SMALLICON);

if ImageList <> then

TreeView_SetImageList(TreeView Handle ImageList );

end;

// 生成文件夹管理树

procedure TForm FillTreeView(Folder: IShellFolder;

FullPIDL: PItemIDList; ParentNode: TTreeNode);

var

TreeViewItem: PTreeViewItem;

EnumIDList: IEnumIDList;

PIDLs FullItemPIDL: PItemIDList;

NumID: LongWord;

ChildNode: TTreeNode;

Attr: Cardinal;

begin

try

OLECheck(Folder EnumObjects(Handle SHCONTF_FOLDERS EnumIDList));

while EnumIDList Next( PIDLs NumID) = S_OK do

begin

FullItemPIDL := ConcatPIDLs(FullPIDL PIDLs);

TreeViewItem := New(PTreeViewItem);

TreeViewItem ParentFolder := Folder;

TreeViewItem Pidl := CopyItemID(PIDLs);

TreeViewItem FullPidl := FullItemPIDL;

TreeViewItem HasExpanded := False;

FItemList Add(TreeViewItem);

ChildNode := TreeView Items AddChildObject(ParentNode

GetDisplayName(Folder PIDLs False) TreeViewItem);

GetItemIcons(FullItemPIDL ChildNode);

Attr := SFGAO_HASSUBFOLDER or SFGAO_FOLDER;

Folder GetAttributesOf( PIDLs Attr);

if Bool(Attr and (SFGAO_HASSUBFOLDER or SFGAO_FOLDER)) then

if Bool(Attr and SFGAO_FOLDER) then

if Bool(Attr and SFGAO_HASSUBFOLDER) then

ChildNode HasChildren := True;

end;

except

// 你可在此处对异常进行处理

end;

end;

procedure TForm FormDestroy(Sender: TObject);

var

I: Integer;

begin

try

for I := to FItemList Count do

begin

DisposePIDL(PTreeViewItem(FItemList[i]) PIDL);

DisposePIDL(PTreeViewItem(FItemList[i]) FullPIDL);

end;

FItemList Clear;

FItemList Free;

except

end;

end;

procedure TForm FormCreate(Sender: TObject);

var

Folder: IShellFolder;

begin

SetTreeViewImageList;

OLECheck(SHGetDesktopFolder(Folder));

FItemList := TList Create;

FillTreeView(Folder nil nil);

end;

procedure TForm TreeView Expanding(Sender: TObject; Node: TTreeNode;

var AllowExpansion: Boolean);

var

TVItem: PTreeViewItem;

SHFolder: IShellFolder;

begin

TVItem := PTreeViewItem(Node Data);

if TVItem HasExpanded then Exit;

OLECheck(TVItem ParentFolder BindToObject(TVItem^ Pidl

nil IID_IShellFolder Pointer(SHFolder)));

FillTreeView(SHFolder TVItem^ FullPidl Node);

Node AlphaSort;

TVItem^ HasExpanded := True;

cha138/Article/program/Delphi/201311/25086

相关参考

在Wndows资源管理器中,按住__键的同时,用鼠标将选定的文件拖放至同一驱动器的另一文件夹中,可以实现该文件的复

在Wndows资源管理器中,按住_____键的同时,用鼠标将选定的文件拖放至同一驱动器的另一文件夹中,可以实现该文件的复制。A、ShiftB、空格C、AltD、Ctrl答案:D解析:在同一个系统盘下,

知识大全 树 - 哈夫曼树及其应用 - 哈夫曼编码 (二)

  根据最优二叉树构造哈夫曼编码  利用哈夫曼树很容易求出给定字符集及其概率(或频度)分布的最优前缀码哈夫曼编码正是一种应用广泛且非常有效的数据压缩  技术该技术一般可将数据文件压缩掉%至%其压缩效率

知识大全 查找 - 树上的查找 - B-树

查找-树上的查找-B-树  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  当查找的文件较大且存放在

知识大全 幸福树用什么土栽培

幸福树用什么土栽培【特征和习性】幸福树学名菜豆树,为紫葳科、菜豆树属的乔木.它属于中等落叶乔木,主干可以长到15m以上,二回至三回羽状复叶,叶轴长约30cm,无毛,中叶对生,呈卵形或卵状控针形,长4-

知识大全 树 - 哈夫曼树及其应用 - 哈夫曼编码 (一)

  编码方案  编码和解码  数据压缩过程称为编码即将文件中的每个字符均转换为一个惟一的二进制位串  数据解压过程称为解码即将二进制位串转换为对应的字符  等长编码方案和变长编码方案  给定的字符集C

知识大全 大家帮帮忙 功劳树是什么树啊 急 治病用

大家帮帮忙功劳树是什么树啊急治病用估计是阔叶十大功劳,也叫土黄柏、土黄连、八角刺、刺黄柏、黄天竹十大功劳花性凉,味甘。根、茎性寒,味苦。含小檗碱、药根碱、木兰花碱等。有清热解毒、止咳化痰之功效。对金黄

知识大全 有谁知道客户档案管理软体哪个好?

有谁知道客户档案管理软体哪个好?8Manage客户档案管理软体还不错,分门别类进行文件管理,实时管理每个文件的查阅与下载等使用情况,支援全域性模糊搜寻,轻松快捷查询所需资讯。客户档案管理软体用8Man

怎样用树落花制造有机肥?

杨树是雌雄异株树种,每年3月份雌株上的花序有相当一部分花序落地。这不但影响了卫生而且影响了美观。若把蕾期的落花序收集起来稍加沤制,即是一种不错的肥源。一般的沤制方法如下:  把地上的杨花花序扫成一堆,

怎样用树落花制造有机肥?

杨树是雌雄异株树种,每年3月份雌株上的花序有相当一部分花序落地。这不但影响了卫生而且影响了美观。若把蕾期的落花序收集起来稍加沤制,即是一种不错的肥源。一般的沤制方法如下:  把地上的杨花花序扫成一堆,

在资源管理器的文件栏中,文件夹是按照__关系来组织的

在资源管理器的文件栏中,文件夹是按照_____关系来组织的。A、图形B、树形C、时间D、名称答案:B解析:在资源管理器的文件栏中,文件夹是按照树形关系来组织的。