unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Windows,
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls;
type
{ TForm1 }
TForm1 =
class(TForm)
Button1: TButton;
CheckBox1: TCheckBox;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
ListBox1: TListBox;
Panel1: TPanel;
procedure Button1Click(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
type
// My variant of an "StringList"
TStrArr =
array of WideString;
// Small helper to add strings in my "StringList"
procedure AddStrArr(
var AArr: TStrArr;
const AString: WideString);
var
i: Integer;
begin
i := Length(AArr);
SetLength(AArr, Succ(i));
AArr[i] := AString;
end;
// This method will crawl thru a folder and collect their names
// IncludeSubFolders switch will get every folder, False by default
// Based upon very fast FindEx Api (Windows)
// The result will contain full path
function FindExFolders(
const BasePath: WideString;
const IncludeSubFolders: Boolean = False): TStrArr;
var
FindExHandle : THandle;
Win32FindData : TWin32FindDataW;
FindExInfoLevels: TFINDEX_INFO_LEVELS;
FindExSearchOps : TFINDEX_SEARCH_OPS;
AdditionalFlags : DWORD;
i, ii : Integer;
tmp : TStrArr;
begin
SetLength(Result
{%H-}, 0);
FindExInfoLevels := FindExInfoBasic;
FindExSearchOps := FindExSearchLimitToDirectories;
AdditionalFlags := 0;
FindExHandle := Windows.FindFirstFileExW(
PWideChar(IncludeTrailingBackslash(BasePath) + '
*.*')
,FindExInfoLevels, @Win32FindData, FindExSearchOps,
nil
,AdditionalFlags);
if (FindExHandle <> INVALID_HANDLE_VALUE)
then
repeat
if ((Win32FindData.cFileName <> '
.')
and (Win32FindData.cFileName <> '
..')
and (0 <> (Win32FindData.dwFileAttributes
and FILE_ATTRIBUTE_DIRECTORY)))
then
AddStrArr(Result
{%H-}, IncludeTrailingBackslash(BasePath) + Win32FindData.cFileName);
until not Windows.FindNextFileW(FindExHandle, Win32FindData);
Windows.FindClose(FindExHandle);
if IncludeSubFolders
then
for i := Low(Result)
to High(Result)
do
begin
tmp := FindExFolders(Result[i], IncludeSubFolders);
for ii := Low(tmp)
to High(tmp)
do
AddStrArr(Result, tmp[ii]);
end;
SetLength(tmp, 0);
end;
// This method will crawl thru a folder and collect their filenames
// IncludeSubFolders switch will get every filename, False by default
// Based upon very fast FindEx Api (Windows)
// The result will contain full path + filename
function FindExFiles(
const BasePath: WideString;
const FileMask: WideString = '
*.*';
const IncludeSubFolders: Boolean = False): TStrArr;
var
FindExHandle : THandle;
Win32FindData : TWin32FindDataW;
FindExInfoLevels: TFINDEX_INFO_LEVELS;
FindExSearchOps : TFINDEX_SEARCH_OPS;
AdditionalFlags : DWORD;
tmp, Folders : TStrArr;
i, ii : Integer;
begin
SetLength(Result
{%H-}, 0);
SetLength(Folders
{%H-}, 0);
SetLength(tmp
{%H-}, 0);
FindExInfoLevels := FindExInfoBasic;
FindExSearchOps := FindExSearchLimitToDirectories;
AdditionalFlags := 0;
FindExHandle := Windows.FindFirstFileExW(
PWideChar(IncludeTrailingBackslash(BasePath) + FileMask)
,FindExInfoLevels, @Win32FindData, FindExSearchOps,
nil
,AdditionalFlags);
if (FindExHandle <> INVALID_HANDLE_VALUE)
then
repeat
if ((Win32FindData.cFileName <> '
.')
and (Win32FindData.cFileName <> '
..'))
then
begin
if (0 = (Win32FindData.dwFileAttributes
and FILE_ATTRIBUTE_DIRECTORY))
then
AddStrArr(Result, IncludeTrailingBackslash(BasePath) + Win32FindData.cFileName);
if (IncludeSubFolders
and
(0 <> (Win32FindData.dwFileAttributes
and FILE_ATTRIBUTE_DIRECTORY)))
then
AddStrArr(Folders, IncludeTrailingBackslash(BasePath) + Win32FindData.cFileName);
end;
until not Windows.FindNextFileW(FindExHandle, Win32FindData);
Windows.FindClose(FindExHandle);
if IncludeSubFolders
then
for i := Low(Folders)
to High(Folders)
do
begin
tmp := FindExFiles(Folders[i], FileMask, IncludeSubFolders);
for ii := Low(tmp)
to High(tmp)
do
AddStrArr(Result, tmp[ii]);
end;
SetLength(Folders, 0);
SetLength(tmp, 0);
end;
// My variant of how a file search method can be done for windows systems
// BasePath = where do we start at? eg "C:\Users"
// BaseFolder = what foldername is a must for results? eg "Documents", can be left empty for all
// FileMask = what files you hunt for? eg "*.pas"
// IncludeSubFolders = yes or no, you choose. False by default
// based upon my "FindExFolders" and "FindExFiles" methods
function FindEx(
const BasePath: WideString;
const BaseFolder: WideString = '
';
const FileMask: WideString = '
*.*';
const IncludeSubFolders: Boolean = False): TStrArr;
var
tmp, Folders, Files: TStrArr;
i,ii: Integer;
begin
SetLength(tmp
{%H-}, 0);
SetLength(Folders
{%H-}, 0);
SetLength(Files
{%H-}, 0);
// collect folder(s) to work on
if IncludeSubFolders
then
tmp := FindExFolders(BasePath, IncludeSubFolders)
else
AddStrArr(tmp, BasePath);
// sieve out folders that match criteria
if (BaseFolder <> '
')
then
begin
for i := Low(tmp)
to High(tmp)
do
if (0 <> Pos(UpperCase(BaseFolder), UpperCase(tmp[i])))
then
AddStrArr(Folders, tmp[i]);
end
else
Folders := tmp;
SetLength(tmp, 0);
// get files that matching the criteria
for i := Low(Folders)
to High(Folders)
do
begin
tmp := FindExFiles(Folders[i], FileMask);
// do not enable the IncludeSubFolders switch here (!)
for ii := Low(tmp)
to High(tmp)
do
AddStrArr(Files, tmp[ii]);
end;
Result := Files;
SetLength(tmp, 0);
SetLength(Folders, 0);
SetLength(Files, 0);
end;
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
List: TStrArr;
begin
List := FindEx(WideString(Edit1.Text), WideString(Edit2.Text), WideString(Edit3.Text), CheckBox1.Checked);
ListBox1.Items.BeginUpdate;
ListBox1.Clear;
for i := Low(List)
to High(List)
do
ListBox1.Items.Add(AnsiString(List[i]));
ListBox1.Items.EndUpdate;
end;
end.