foldertree.pas
来自「功能强大的报表生成和管理工具」· PAS 代码 · 共 1,285 行 · 第 1/3 页
PAS
1,285 行
unit FolderTree;
// Change log
// 12/14/1999 -- Moved allocation of TStringList in FindPath routine
// to fix a memory leak.
// 03/15/2000 -- Exposed OnDblClick.
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ComCtrls, ShlObj, ShellAPI, OLE2;
const
WM_DIRCHANGE = WM_USER + 0;
WM_SHOWDESKTOP = WM_USER + 1;
(* Events of WM_DEVICECHANGE (wParam) *)
DBT_DEVICEARRIVAL = $8000; (* system detected a new device *)
DBT_DEVICEQUERYREMOVE = $8001; (* wants to remove, may fail *)
DBT_DEVICEQUERYREMOVEFAILED = $8002; (* removal aborted *)
DBT_DEVICEREMOVEPENDING = $8003; (* about to remove, still avail *)
DBT_DEVICEREMOVECOMPLETE = $8004; (* device is gone *)
DBT_DEVICETYPESPECIFIC = $8005; (* type specific event *)
DBT_CONFIGCHANGED = $0018;
(* type of device in DEV_BROADCAST_HDR *)
DBT_DEVTYP_OEM = $00000000; (* OEM- or IHV-defined *)
DBT_DEVTYP_DEVNODE = $00000001; (* Devnode number *)
DBT_DEVTYP_VOLUME = $00000002; (* Logical volume *)
DBT_DEVTYP_PORT = $00000003; (* Port (serial or parallel *)
DBT_DEVTYP_NET = $00000004; (* Network resource *)
(* media types in DBT_DEVTYP_VOLUME *)
DBTF_MEDIA = $0001;
DBTF_NET = $0002; (* logical volume is network volume *)
type
PDEV_BROADCAST_HDR = ^TDEV_BROADCAST_HDR;
TDEV_BROADCAST_HDR = packed record
dbch_size : DWORD;
dbch_devicetype : DWORD;
dbch_reserved : DWORD;
end;
PDEV_BROADCAST_VOLUME = ^TDEV_BROADCAST_VOLUME;
TDEV_BROADCAST_VOLUME = packed record
dbcv_size : DWORD;
dbcv_devicetype : DWORD;
dbcv_reserved : DWORD;
dbcv_unitmask : DWORD;
dbcv_flags : WORD;
end;
TWMDeviceChange = record
Msg : Cardinal;
Event : UINT;
dwData : Pointer;
Result : LongInt;
end;
TWM_DIRCHANGE = record
Msg : word; { first is the message ID }
fill : integer; { unused }
Node : TTreeNode; { Node whose structure changed }
result : longint;
end;
TWM_SHOWDESKTOP = record
Msg : word; { first is the message ID }
fill1 : word; { unused }
fill2 : longint; { unused }
result : longint;
end;
type
TPathInfo = record
Path : string;
Text : string;
IconIndex : uInt;
SelectedIndex : uInt;
Pid : PItemIdList;
end;
type
TDisplayMode = (dmAsis,dmUppercase,dmLowercase);
TFilePathList = record
Normal : string;
ForParsing : string;
InFolder : string;
end;
TFolderType = (ftFolder,ftNetworkNeighborhood,ftRecycleBin,ftMyComputer,ftDesktop,
ftNetNode,ftNone);
SFolderTypes = set of TFolderType;
TFolderOption = (foNetworkNeighborhood,foRecycleBin);
SFolderOption = set of TFolderOption;
type
TFolderTree = class(TCustomTreeView)
private
DesktopNode : TTreeNode;
MyComputerNode : TTreeNode;
NetHoodNode : TTreeNode;
BitBucketNode : TTreeNode;
SysImageList : TImageList;
fDesktopPath : string;
fNetHoodPath : string;
fMessageHandle : hWnd;
fDisplayMode : TDisplayMode;
fFolderOptions : SFolderOption;
AllocInterface : IMalloc;
function fGetNetHood : TPathInfo;
function fGetSpecialFolder(nFolder : integer) : TPathInfo;
function CreateFolderNode(PidList : PItemIdList;
parent : TTreeNode;
virtualok : boolean) : TTreeNode;
procedure RetrieveSysImageList;
procedure ShowDesktop;
function GetLongFilePath(const Pid : PItemIdList;
ShellFolder : IShellFolder)
: TFilePathList;
function GetPathName(const Pid : PItemIdList; Flags : dword;
ShellFolder : IShellFolder) : string;
function AttachFolders(var Node : TTreeNode) : boolean;
function GetVol_Ser (drive : string) : longint;
function FindPath(path : string) : TTreeNode;
procedure MessageProc(Var Message : TMessage);
procedure StartChangeThread(Node : TTreeNode);
procedure FreePidl(pidl : PItemIdList);
procedure FreeChildren(Node : TTreeNode);
procedure FreeNode(Node : TTreeNode);
procedure DriveChanged(Sender: TObject; FirstDriveLetter: Char);
procedure TFolderTreeExpanding(Sender: TObject; Node: TTreeNode;
var AllowExpansion: Boolean);
procedure TFolderTreeClick(Sender: TObject);
function GetDirectory : string;
function GetFirstDriveLetter(unitmask:longint):char;
procedure WMDeviceChange(var Msg : TWMDeviceChange); dynamic;
{ Private declarations }
protected
{ Protected declarations }
public
property Items;
property Selected;
property Directory : string read GetDirectory;
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
function SetDirectory(path : string) : TTreeNode;
function GetPath (Node : TTreeNode) : string;
function NodeShellFolder (Node : TTreeNode) : IShellFolder;
function NodeType (Node : TTreeNode) : TFolderType;
function NodeItemIdList (Node : TTreeNode) : PItemIdList;
{ Public declarations }
published
property FolderOptions : SFolderOption read fFolderOptions
write fFolderOptions;
property OnChange;
property OnDblClick;
property OnDragOver;
property OnDragDrop;
property DisplayMode : TDisplayMode read fDisplayMode write fDisplayMode
default dmAsis;
property ShowButtons;
property ShowLines;
property ShowRoot;
property HideSelection;
property Align;
property BorderStyle;
property Color;
property Ctl3D;
property DragCursor;
property DragMode;
property Enabled;
property Font;
property Indent;
property OnEnter;
property OnExit;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property ShowHint;
property TabOrder;
property TabStop default True;
property Visible;
{ Published declarations }
end;
type
TThDirChange = class(TThread)
private
protected
procedure Execute; override;
private
procedure DoOnChange;
public
Node : TTreeNode;
FolderTree : TFolderTree;
msghandle : hwnd;
end;
type
TFolderNode = record
FN_Path : string;
FN_Has_Parent : boolean;
FN_Change_Thread : TThDirChange;
FN_Vol_Ser : longint;
FN_ShellFolder : IShellFolder;
FN_Type : TFolderType;
FN_PidLen : word;
FN_PidList : PItemIdList;
end;
procedure Register;
implementation
const
VirtualFolders = [ftNetworkNeighborhood,ftNetNode,ftRecycleBin,ftMyComputer];
constructor TFolderTree.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
fFolderOptions := [];
fDisplayMode := dmAsis;
CoGetMalloc(MEMCTX_TASK, AllocInterface);
self.parent := (AOwner as TForm);
fMessageHandle := AllocateHWnd(MessageProc);
self.OnExpanding := TFolderTreeExpanding;
self.OnClick := TFolderTreeClick;
self.ReadOnly := true;
// Get the system image list.
RetrieveSysImageList;
with SysImageList do begin
masked := false;
shareimages := true;
end;
self.Images := SysImageList;
PostMessage(fMessageHandle,WM_SHOWDESKTOP,0,0);
end;
// ShowDesktop is performed when Create posts a WM_SHOWDESKTOP
// message, so we see the correct value of fFolderOptions.
procedure TFolderTree.ShowDesktop;
var
i : byte;
nodeptr : ^TFolderNode;
pathinfo : TPathInfo;
displayname : string;
drivenode : TTreeNode;
foldernode : ^TFolderNode;
path : string;
AllowExpansion : boolean;
FilePath : TFilePathList;
ShellFolder : IShellFolder;
begin
Items.BeginUpdate;
// Establish the node for the Desktop.
pathinfo := fGetSpecialFolder(CSIDL_DESKTOP);
fDesktopPath := pathinfo.path;
DesktopNode := CreateFolderNode(pathinfo.pid,nil,true); // Create a node for the Desktop
foldernode := DesktopNode.data;
FilePath := GetLongFilePath(pathinfo.pid,foldernode^.FN_ShellFolder);
with DesktopNode do begin
text := FilePath.Normal;
// Set FN_Path to the path name of the desktop, and indicate
// it is the desktop.
foldernode := data;
with foldernode^ do begin
FN_Path := fDesktopPath;
FN_Type := ftDesktop;
end;
end;
// Add real folders on the desktop to the Desktop node, then
// alphabetize.
AttachFolders(DesktopNode);
// Establish the node for the Recycle Bin, if so desired.
if not (csDesigning in ComponentState) then begin
if foRecycleBin in fFolderOptions then begin
pathinfo := fGetSpecialFolder(CSIDL_BITBUCKET);
BitBucketNode := CreateFolderNode(pathinfo.pid,DesktopNode,true); // Create a node for the BitBucket
foldernode := DesktopNode.data;
FilePath := GetLongFilePath(pathinfo.pid,foldernode^.FN_ShellFolder);
with BitBucketNode do begin
text := FilePath.Normal;
// Set FN_Path null, and indicate it is the BitBucket.
foldernode := data;
with foldernode^ do begin
FN_Path := '';
FN_Type := ftRecycleBin;
end;
end;
end;
end;
// Establish the node for the NetHood if so desired.
if not (csDesigning in ComponentState) then begin
if foNetworkNeighborhood in fFolderOptions then begin
pathinfo := fGetNetHood;
fNetHoodPath := pathinfo.path;
NetHoodNode := CreateFolderNode(pathinfo.pid,DesktopNode,true); // Create a node for the NetHood
with NetHoodNode do begin
text := pathinfo.text;
// Set FN_Path to \\, which is the root of Network
// Neighborhood, and set FN_Type to shows it is the NetHood.
foldernode := data;
with foldernode^ do begin
FN_Path := '\\';
FN_Type := ftNetworkNeighborhood;
end;
end;
end;
end;
// Attach the MyComputer node to the Desktop node.
pathinfo := fGetSpecialFolder(CSIDL_DRIVES);
MyComputerNode := CreateFolderNode(pathinfo.pid,DesktopNode,true); // Create a node for the Desktop
foldernode := DesktopNode.data;
FilePath := GetLongFilePath(pathinfo.pid, foldernode^.FN_ShellFolder);
with MyComputerNode do begin
text := FilePath.Normal;
// Set FN_Path to a null string, and the type to ftMyComputer.
foldernode := data;
with foldernode^ do begin
FN_Path := '';
FN_Type := ftMyComputer;
end;
end;
// Expand the Desktop node.
DesktopNode.expand(false);
Items.EndUpdate;
end;
function TFolderTree.fGetNetHood : TPathInfo;
var
pi : TPathInfo;
FilePath : TFilePathList;
begin
result := fGetSpecialFolder(CSIDL_NETWORK);
FilePath := GetLongFilePath(result.pid,nil);
result.text := FilePath.Normal;
end;
function TFolderTree.fGetSpecialFolder(nFolder : integer) : TPathInfo;
var
aPidl: PItemIDList;
TC : TComponent;
fLinkDir : string;
FileInfo : TSHFileInfo;
r : boolean;
begin
// Get the folder location (as a PItemIDList)
if SUCCEEDED(SHGetSpecialFolderLocation(self.parent.handle, nFolder, aPidl))
then begin
result.Pid := aPidl;
// Get the actual path of the directory from the PItemIDList
SetLength(fLinkDir, MAX_PATH); // SHGetPathFromIDList assumes MAX_PATH buffer
SHGetPathFromIDList(aPidl, PChar(fLinkDir)); // Do it
SetLength(fLinkDir, StrLen(PChar(fLinkDir)));
Result.Path := fLinkDir;
SHGetFileInfo(Pointer(aPidl),SFGAO_SHARE, FileInfo, sizeof(FileInfo),
SHGFI_PIDL or SHGFI_SYSICONINDEX );
Result.IconIndex:=FileInfo.iIcon;
SHGetFileInfo(Pointer(aPidl),SFGAO_SHARE, FileInfo, sizeof(FileInfo),
SHGFI_PIDL or SHGFI_SYSICONINDEX or SHGFI_OPENICON);
Result.SelectedIndex:=FileInfo.iIcon;
end;
end;
// CreateFolderNode creates a Folder_Node and inserts it under
// the "parent" node (if any), using the last of the path
// string as the Name, and setting the new node's text
// property to match.
function TFolderTree.CreateFolderNode(PidList : PItemIdList;
parent : TTreeNode;
virtualok : boolean) : TTreeNode;
var
filename : string;
path : string;
NewNodeData : ^TFolderNode;
ParentNodeData : ^TFolderNode;
DesktopNodeData : ^TFolderNode;
FileInfo : TSHFileInfo;
ImageIndex: Uint;
SelectedIndex : Uint;
newnode : TTreeNode;
pidl : PItemIdList;
parentfolder : IShellFolder;
ShellFolder : IShellFolder;
Attributes : uint;
FilePath : TFilePathList;
virtualfolder : boolean;
pidlen : word;
parentpidlen : word;
parentpidbuf : PItemIdList;
pidbuf : PItemIdList;
itemid : TSHItemID;
begin
result := nil;
try
// Get the Long File Path for the PidList passed.
if assigned(parent)
then begin
ParentNodeData := parent.data;
FilePath := GetLongFilePath(PidList,ParentNodeData^.FN_ShellFolder);
end
else
FilePath := GetLongFilePath(PidList,nil);
filename := FilePath.InFolder;
path := FilePath.ForParsing;
// Get the attributes we're interested in for this folder.
Attributes := SFGAO_SHARE or SFGAO_FILESYSTEM
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?