unit
Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ShellApi, StdCtrls, AlignedEdit, FlatLabel, ComCtrls;
type
TWideCharBuffer =
array
[
0..
MAX_PATH -
1
]
of
WideChar
;
TNodeArray =
array
[
1..
MaxListSize]
of
TTreeNode;
TNodeList =
class
private
FCount:
cardinal
;
FItems: TNodeArray;
procedure
Clear;
function
Add(
const
aNode: TTreeNode):
cardinal
;
public
constructor
Create;
property
Count:
cardinal
read FCount;
property
Items: TNodeArray read FItems;
procedure
Assign(
const
NodeList: TNodeList);
end
;
TfmMain =
class
(TForm)
meDebug: TMemo;
Button1: TButton;
FlatLabel1: TFlatLabel;
AlignedEdit1: TAlignedEdit;
Button2: TButton;
Memo2: TMemo;
twMain: TTreeView;
procedure
Button1Click(Sender: TObject);
procedure
Button2Click(Sender: TObject);
procedure
FormClose(Sender: TObject;
var
Action: TCloseAction);
procedure
FormCreate(Sender: TObject);
private
procedure
Display(s:
string
);
function
faToString(fa:
integer
):
string
;
function
IsDirectory(fa:
Integer
):
boolean
;
function
IsSpecialFile(fa:
Integer
):
boolean
;
function
IsFile(fa:
Integer
):
boolean
;
function
GetFilenameLength(S:
PAnsiChar
):
integer
;
function
InitTree(
const
S:
string
;
const
TreeView: TTreeView): TTreeNode;
function
ProcessDirectoryNode(
const
aNode: TTreeNode;
const
TreeView: TTreeView;
const
NodeList: TNodeList):
cardinal
;
function
GetDirectoryTree(
const
Root:
string
;
const
TreeView: TTreeView):
integer
;
procedure
StringToWidechar(S:
PChar
;
const
Buffer: TWideCharBuffer);
public
end
;
var
fmMain: TfmMain;
Nodes, NewNodes: TNodeList;
NodeCount:
cardinal
;
implementation
{$R *.dfm}
procedure
TfmMain
.
Button1Click(Sender: TObject);
var
S:
String
;
Count:
cardinal
;
begin
meDebug
.
Clear;
S:= AlignedEdit1
.
Text;
Count:=GetDirectoryTree(S,twMain);
Memo2
.
Lines
.
Add(
'Found '
+ IntToStr(Count) +
' sub-directories in '
+ S);
end
;
procedure
TfmMain
.
Display(s:
string
);
begin
meDebug
.
Lines
.
Append(s);
end
;
function
TfmMain
.
IsDirectory(fa:
Integer
):
boolean
;
begin
Result:= (fa
and
faDirectory) = faDirectory;
end
;
function
TfmMain
.
IsFile(fa:
Integer
):
boolean
;
begin
Result:=((fa
and
faAnyFile) = faAnyFile);
end
;
function
TfmMain
.
InitTree(
const
S:
string
;
const
TreeView: TTreeView): TTreeNode;
begin
Result:=
nil
;
if
not
DirectoryExists(S)
then
Exit;
with
TreeView
do
begin
Items
.
Clear;
Result:=Items
.
Add(
nil
,S);
end
;
end
;
procedure
TfmMain
.
FormCreate(Sender: TObject);
begin
Nodes:=TNodeList
.
Create;
NewNodes:=TNodeList
.
Create;
end
;
function
TfmMain
.
ProcessDirectoryNode(
const
aNode: TTreeNode;
const
TreeView: TTreeView;
const
NodeList: TNodeList):
cardinal
;
var
tWDF: WIN32_FIND_DATAW;
h:
Cardinal
;
gwError:
Cardinal
;
Count:
integer
;
found:
boolean
;
s:
string
;
wSearchName:
array
[
0..
MAX_PATH -
1
]
of
WideChar
;
searchName:
PChar
;
foundName:
array
[
0..
MAX_PATH -
1
]
of
Char
;
NewNode: TTreeNode;
Path:
string
;
begin
Result:=
0
;
if
(aNode =
nil
)
or
(NodeList =
nil
)
then
Exit;
Path:=aNode
.
Text;
searchName:=
PChar
(Path +
'\*.*'
);
Count:=
0
;
try
MultiByteToWideChar(CP_UTF8,
0
, searchName, MAX_PATH, wSearchName, MAX_PATH);
except
Display(
'Error in MultiByteToWideChar for '
+ searchName);
end
;
try
h:=FindFirstFileW(wSearchName, tWDF);
except
Display(
'FindFirstFileW error in '
+ wSearchName);
Exit;
end
;
WideCharToMultiByte(CP_UTF8,
0
, tWDF
.
cFileName, MAX_PATH, foundName, MAX_PATH,
nil
,
nil
);
with
tWDF
do
begin
Application
.
ProcessMessages;
if
h = INVALID_HANDLE_VALUE
then
begin
Display(
'INVALID_HANDLE_VALUE for search in '
+Path +
'\*.*'
);
Result:=h;
Windows
.
FindClose(h);
Exit;
end
;
if
cFileName[
0
]<>
'.'
then
begin
if
IsDirectory(dwFileAttributes)
then
begin
NewNode:=TreeView
.
Items
.
AddChild(aNode,Path + '\' + cFileName);
NodeList
.
Add(NewNode);
Inc(Result);
TreeView
.
Update;
end
else
Exit;
end
;
while
true
do
begin
Application
.
ProcessMessages;
try
if
FindNextFileW(h,tWDF)
then
begin
WideCharToMultiByte(CP_UTF8,
0
, tWDF
.
cFileName, MAX_PATH, foundName, MAX_PATH,
nil
,
nil
);
if
cFileName[
0
] <>
'.'
then
begin
if
IsDirectory(dwFileAttributes)
then
begin
NewNode:=TreeView
.
Items
.
AddChild(aNode,Path + '\'+ foundName);
NodeList
.
Add(NewNode);
TreeView
.
Update;
end
else
begin
end
;
end
;
end
else
Break;
except
end
;
end
;
end
;
end
;
function
TfmMain
.
GetDirectoryTree(
const
Root:
string
;
const
TreeView: TTreeView):
integer
;
var
aNode: TTreeNode;
ParentNode: TTreeNode;
Count:
cardinal
;
i:
cardinal
;
DirectoryCount:
cardinal
;
begin
Result:=
0
;
DirectoryCount:=
0
;
if
(Root =
''
)
or
(TreeView =
nil
)
then
Exit;
TreeView
.
Items
.
Clear;
Nodes
.
Clear;
NewNodes
.
Clear;
ParentNode:=InitTree(Root,twMain);
ProcessDirectoryNode(ParentNode,twMain,Nodes);
if
Nodes
.
Count =
0
then
Exit;
Inc(DirectoryCount, Nodes
.
Count);
while
true
do
begin
Count:=Nodes
.
Count;
NewNodes
.
Clear;
for
i:=
1
to
Count
do
begin
ParentNode:=Nodes
.
Items[i];
ProcessDirectoryNode(ParentNode, twMain, NewNodes);
end
;
if
NewNodes
.
Count =
0
then
break;
Inc(DirectoryCount, NewNodes
.
Count);
Nodes
.
Assign(NewNodes);
end
;
Result:=DirectoryCount;
end
;
function
TNodeList
.
Add(
const
aNode: TTreeNode):
cardinal
;
begin
Result:=
0
;
if
aNode =
nil
then
Exit;
Inc(FCount);
FItems[FCount]:=aNode;
end
;
procedure
TNodeList
.
Assign(
const
NodeList: TNodeList);
begin
FItems:=NodeList
.
Items;
FCount:=NodeList
.
Count;
end
;
procedure
TNodeList
.
Clear;
begin
if
FCount =
0
then
Exit;
FCount:=
0
;
end
;
constructor
TNodeList
.
Create;
begin
FCount:=
0
;
end
;
end
.