Second, the implementation principle
The implementation of the Windows folder management tree is essentially traversal for Windows Namespaces. Each folder in the name space provides an ISHELLFOLDER interface, and the way to traverse the name is:
1) Call the SHGETDESKTOPFolder function to get the ISHELLFOLDER interface of the desktop folder, the desktop folder is the root node of the folder management tree.
2) The enumobjects member function of the obtained ISHELLFOLDER interface is called to list the child folder.
3) Call the BindtoBject member function of iShellfolder to get the iShellFolder interface of the subfolder.
4) Repeat steps 2), 3) list all subfolders under a folder, only to the obtained ISHELLFOLDER interface as NIL.
The following explains several major functions that will be used, they define in the SHLOBJ unit:
1) Function ShgetDesktopFolder (VAR PPSHF: ishellfolder): HRESULT;
This function gets the ISHELLFOLDER interface of the desktop folder through PPSHF.
2) Function ishellfolder.enumObjects (hwndowner: hwnd; grfflags: dword;
Out enumidlist: ienumidlist): HRESULT;
This function obtains a IEnumIdList interface, which can list the contents of the folder corresponding to the ISHELLFOLDER interface by calling the interface of the interface, and the type of content is specified by grfflags. We need to list the subfolders, so the value of Grfflags is specified as Shcontf_folders. HWndowner is a handle of the main window.
3) Function ishellfolder.bindtoObject (PIDL: PitemidList; PBCReServed: Pointer;
Const riid: tiid; out ppvout: Pointer: hResult;
This function gets an ISHELLFOLDER interface of a subfolder that is returned by PPVout. PIDL is a pointer to the element identifier list, and Windows 95/98 uses an element identifier and an element identifier list to identify objects in the namespace, which are similar to file names and paths. It is necessary to point out that when PIDL is passed to the Shell API function, it must be a member function relative to the ISHELLFOLDER interface relative to the desktop folder, and should be relative to the corresponding folder corresponding to the interface. path. PBCReServed should be specified as NIL, and RIID should be specified as IID_ISHELLFOLDER.
Other functions can be found in "Win32 Programmer's Reference" provided by Delphi.
Third, the program list
The following source code is implemented in Windows 98 and is tested in the Windows2000 beta (shown in Figure 1), and interested readers can rewrite them into Delphi components for common use.
Unit BrowsetreeView;
Interface
Uses
Windows, Messages, Sysutils, Classes, Graphics, Controls, Forms, Dialogs,
SHLOBJ, COMCTRLS;
Type
PTreeViewItem = ^ TtreeViewItem
TTREEVIEWITEM = Record
ParentFolder: iShellFolder; / / The ISHELLFOLDER interface of the parent folder of the corresponding folder
PIDL, FULLPIDL: PitemidList; // The relative and absolute item identity list of the corresponding folder, whether the list isxpanded: Boolean; // Whether the contact is expanded
END;
Figure 1 Program operation results
TFORM1 = Class (TFORM)
TreeView1: TtreeView;
Procedure FormDestroy (Sender: TOBJECT);
Procedure formcreate (Sender: TOBJECT);
Procedure TreeView1expanding (Sender: Tobject; Node: ttreenode;
VAR AllowExpansion: Boolean;
Private
Fitemlist: TLIST;
Procedure settreeViewImageList;
Procedure FillTreeView (Folder: ishellfolder; FullPidl: PitemidList; ParentNode: ttreenode;
END;
VAR
FORM1: TFORM1;
IMPLEMENTATION
{$ R * .dfm}
Uses
ActiveX, Comobj, Shellapi, CommCtrl
// The following is a function of a few of the project identifier
Procedure Disposepidl (ID: PitemidList);
VAR
Malloc: IMALLOC;
Begin
IF id = nil dam
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).
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;
// Convert binary representation of the item identity list into an identifiable project name
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_SYSICIONINDEX 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;
// Get the icon of each folder in the system
Procedure GetItemicons (Fullpidl: PitemidList; Treenode: Ttreenode);
Begin
With treenode do
Begin
ImageIndex: = Geticon (FullPIDL, FALSE);
SELECTEDINDEX: = Geticon (fullpidl, true);
END;
END;
/ / Get the system's icon list
Procedure TFORM1.SETTREEVIEWIMAGELIST;
VAR
ImageList: thandle;
FileInfo: Tshfileinfo; Begin
ImageList: = shGetfileinfo (Pchar ('C: /'), 0, FileInfo,
Sizeof (TshfileInfo), SHGFI_SYSICIONINDEX or SHGFI_SMALLICON;
IF imagelist <> 0 THEN
TreeView_setimagelist (TreeView1.Handle, Imagelist, 0);
END;
/ / Generate a folder management tree
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.getaTributesof (1, PIDLS, ATTR);
if Bool (attr and (sfgao_hassubfolder or sfgao_folder) THEN
if Bool (attr and sfgao_folder)
IF Bool (attr and sfgao_hassubfolder) THEN
Childnode.haschildren: = true;
END;
Except
/ / You can process an exception here
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 the exit;
Olecheck (TVItem.ParentFolder.BindToObject (TVItem ^ .pidl,
NIL, IID_ID_ILLFOLDER, POINTER (SHFOLDER));
FillTreeView (Shfolder, TVItem ^ .FullPidl, Node);
Node.alphas.
TVitem ^ .hasexpanded: = true;
END;
End.