《电脑编程技巧与维护》2000年第二期中的一篇文章,希望对你有帮助。
用Delphi实现Windows文件夹管理树............................ 李鹏 薛志东(2.29)
以下:
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;
TForm1 = class(TForm)
TreeView1: TTreeView;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure TreeView1Expanding(Sender: TObject; Node: TTreeNode;
var AllowExpansion: Boolean);
private
{ Private declarations }
FItemList:TList;
procedure SetTreeViewImageList;
procedure FillTreeView(Folder:IShellFolder;FullPIDL:PItemIDList;ParentNode:TTreeNode);
public
{ Public declarations }
end;
var
Form1: TForm1;
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:=0;
if Assigned(ID) then
begin
result:=sizeof(ID^.mkid.cb);
while ID^.mkid.cb <> 0 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,0);
finally
end;
end;
function ConcatPIDLs(ID1,ID2:PItemIDList):PItemIDList;
var
cb1,cb2:Integer;
begin
if Assigned(ID1) then
cb1:=GetPIDLSize(ID1)-sizeof(ID1^.mkid.cb )
else
cb1:=0;
cb2:=GetPIDLSize(ID2);
result:=CreatePIDL(cb1+cb2);
if Assigned(Result) then
begin
if Assigned(ID1) then
CopyMemory(Result,ID1,cb1);
CopyMemory(PChar(Result)+cb1,ID2,cb2);
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,StrLen(StrRet.cStr));
STRRET_OFFSET:
begin
P:=@PIDL.mkid.abID[StrRet.uOffset-sizeof(PIDL.mkid.cb)];
SetString(Result,P,PIDL.mkid.cb-StrRet.UOffset);
end;
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),0,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 TForm1.SetTreeViewImageList;
var
imagelist:thandle;
fileinfo:tshfileinfo;
begin
imagelist:=shgetfileinfo(Pchar('c:\'),0,fileinfo,sizeof(tshfileinfo),shgfi_sysiconindex or shgfi_smallicon);
if imagelist<>0 then
treeview_setimagelist(treeview1.handle,imagelist,0);
end;
//生成文件夹管理树
procedure TForm1.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(1,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:=TreeView1.Items.AddChildObject(ParentNode,GetDisplayName(Folder,PIDLs,False),TreeViewItem);
GetItemIcons(FullItemPIDL,ChildNode);
Attr:=SFGAO_HASSUBFOLDER or SFGAO_FOLDER;
Folder.GetAttributesOf (1,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 TForm1.FormDestroy(Sender: TObject);
var
I:Integer;
begin
try
for I:=0 to FItemList.Count-1 do
begin
DisposePIDL(PTreeViewItem(FItemList[i]).PIDL);
DisposePIDL(PTreeViewItem(FItemList[i]).FullPIDL);
end;
FItemList.Clear;
FItemList.Free;
except
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Folder:IshellFolder;
begin
SetTreeViewImageList;
OLECheck(ShGetDesktopFolder(Folder));
FItemList:=Tlist.Create;
FillTreeView(folder,nil,nil);
end;
procedure TForm1.TreeView1Expanding(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;
end;
end.