Einzelnen Beitrag anzeigen

Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: FindFirstFileEx liefert Error Falscher Parameter?

  Alt 8. Sep 2022, 21:21
Hmmm ich kann meine Post nicht bearbeiten, wollte noch mein update dazu nachliefern.
Delphi-Quellcode:
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.
Wohlgemerkt, geschrieben mit Lazarus und da ist ein String noch ein AnsiString, deswegen die casts.
( die {%H-} direktive schaltet in Lazarus Warnungen ab )

@himitsu
Jo, mit Delphi oder Lazarus Bordmitteln geht es natürlich auch, ich war mehr hinter FindFirstFileEx (Threadname) her und dessen Bedienung.
Gruß vom KodeZwerg

Geändert von KodeZwerg ( 8. Sep 2022 um 21:47 Uhr)
  Mit Zitat antworten Zitat