![]() |
FindFirstFileEx liefert Error Falscher Parameter?
Ich habe gerade ein seltsames Phänomen. Eben habe ich eine Prozedur von FindFirst/FindNext auf FindFirstFileEx/FindNextFile umgeschrieben. Sie hat funktioniert!
Wenn ich diese Funktion jetzt aber aufrufe, gibt es den Fehler "Falscher Parameter". Die lief doch vorhin noch :roll: Das hat mit FindFirst/FindNext immer funktioniert. Was ist intern an FindFirstFileEx anders? Darf man FindFirstFileEx nicht so schnell hintereinander aufrufen? So rufe ich es auf, der Rest (Prüfen auf . und .. ist Standard. Aber es geht nicht über invalid handle value hinaus.
Delphi-Quellcode:
Bei meinen ersten Tests habe ich immer Resultate bekommen. Mittlerweile bekomme ich gar nichts mehr zurück.
var
lhFoundFile: THandle; lIndexInfoLevels: FINDEX_INFO_LEVELS; lfdStruct: TWin32FindData; lIndexSearchOps: TFindexSearchOps; begin // ParentFolder: C:\Projekte\Logdateien\ // Mask : *.log lhFoundFile := THandle(Winapi.Windows.FindFirstFileEx(PWideChar(ParentFolder + Mask), lIndexInfoLevels, @lfdStruct, lIndexSearchOps, nil, 0)); if (lhFoundFile <> INVALID_HANDLE_VALUE) then begin |
AW: FindFirstFileEx liefert Error Falscher Parameter?
Hallo,
je nach dem was du eigentlich vorhast gibt's evtl. auch einen Lösungsansatz in System.IOUtils? Grüße TurboMagic |
AW: FindFirstFileEx liefert Error Falscher Parameter?
Die dortigen Lösungen sind alle zu ineffizient.
Mittlerweile funktionierts wohl wieder, neuer Aufruf, keine leeren Variablen mehr
Delphi-Quellcode:
var
lhFoundFile: THandle; lfdStruct: TWin32FindData; Index: Integer; begin lhFoundFile := THandle(Winapi.Windows.FindFirstFileEx(PWideChar(ParentFolder + Mask), _FINDEX_INFO_LEVELS.FindExInfoBasic, @lfdStruct, _FINDEX_SEARCH_OPS.FindExSearchNameMatch, nil, 0)); if (lhFoundFile <> INVALID_HANDLE_VALUE) then begin |
AW: FindFirstFileEx liefert Error Falscher Parameter?
Wieso hattest du im ersten Post nicht alle nötigen Variablen initialisiert?
Wenn dir dann jemand um die Ohren wirft, dass es falsch ist, dann hat er bestimmt Recht. Und ich möchte fast wetten, dass der Compiler das dir auch versucht hatte zu sagen, also warum höst du nicht auf ihn? Das Result ist bereits THandle. :stupid:
Delphi-Quellcode:
lhFoundFile := FindFirstFileEx(PChar(ParentFolder + Mask), FindExInfoBasic, @lfdStruct, FindExSearchNameMatch, nil, 0);
_FINDEX_SEARCH_OPS ist nicht unbedingt nötig, zumindestens nicht, wenn es nicht mit {$ScopedEnums ON} deklariert wurde. Man mischt NIEMALS statische und compilerabhängige Deklarationen. ParentFolder und Mask sind bestimmt String. (kein AnsiString oder WideString/UnicodeString) FindFirstFileEx ist ebenso dynnamisch, gegenüber FindFirstFileExA und FindFirstFileExW. PWideChar ist fest, ebenso wie PAnsiChar, aber gegenüber dem dynamischen PChar. Rate mal, warum 2009 so viel Knallte, als Delphi plötzlich von ANSI zu Unicode wechselte. String -> PChar -> TWin32FindData -> FindFirstFileEx AnsiString -> PAnsiChar -> TWin32FindDataA -> FindFirstFileExA WideString oder UnicodeString -> PWideChar -> TWin32FindDataW -> FindFirstFileExW |
AW: FindFirstFileEx liefert Error Falscher Parameter?
Da steht sehr viel, aber verstanden habe ich nicht was du meinst.
Soll das so sein?
Delphi-Quellcode:
lhFoundFile := FindFirstFileEx(PChar(ParentFolder + Mask), FindExInfoBasic, @lfdStruct, FindExSearchNameMatch, nil, 0);
|
AW: FindFirstFileEx liefert Error Falscher Parameter?
Delphi-Quellcode:
Dein Code aus Post #1:
lIndexInfoLevels := FindExInfoBasic;
lIndexSearchOps := FindExSearchNameMatch; lhFoundFile := FindFirstFileEx(PChar(ParentFolder + Mask), lIndexInfoLevels, @lfdStruct, lIndexSearchOps, nil, 0); Verboten sind Variablen nicht, aber man sollte ihnen auch etwas zuweisen. Und genau das sollte der Compiler dir auch gesagt haben, Zitat:
|
AW: FindFirstFileEx liefert Error Falscher Parameter?
Vielleicht ist das hilfreich für andere die nach FindFirstFileEx suchen:
(mit FPC/Lazarus geschrieben, aber das gröbste sollte identisch sein)
Delphi-Quellcode:
Ziel war es, eine Suche durchzuführen in der man 3 Parameter eingibt,
unit Unit1;
{$mode objfpc}{$H+} interface uses Windows, Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls; type TStrArr = array of string; { TForm1 } TForm1 = class(TForm) Button1: TButton; Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; ListBox1: TListBox; Panel1: TPanel; procedure Button1Click(Sender: TObject); private function MySearch(const BasePath, BaseFolder: string; const FileMask: string = '*.*'): TStrArr; public end; var Form1: TForm1; implementation {$R *.lfm} procedure AddStrArr(var AArr: TStrArr; const AString: string); var i: Integer; begin i := Length(AArr); SetLength(AArr, Succ(i)); AArr[i] := AString; end; function GetAllFolders(const BasePath: string; const IncludeSubFolders: Boolean = False): TStrArr; var FindExHandle : THandle; Win32FindData : TWin32FindData; FindExInfoLevels: TFINDEX_INFO_LEVELS; FindExSearchOps : TFINDEX_SEARCH_OPS; AdditionalFlags : DWORD; i, ii : Integer; tmp : TStrArr; begin SetLength(Result, 0); FindExInfoLevels := FindExInfoBasic; FindExSearchOps := FindExSearchLimitToDirectories; AdditionalFlags := 0; FindExHandle := Windows.FindFirstFileEx(PChar(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, IncludeTrailingBackslash(BasePath) + Win32FindData.cFileName); until not Windows.FindNextFile(FindExHandle, Win32FindData); Windows.FindClose(FindExHandle); if IncludeSubFolders then for i := Low(Result) to High(Result) do begin tmp := GetAllFolders(Result[i], IncludeSubFolders); for ii := Low(tmp) to High(tmp) do AddStrArr(Result, tmp[ii]); end; SetLength(tmp, 0); end; function GetAllFiles(const BaseFolder: string; const FileMask: string = '*.*'): TStrArr; var FindExHandle : THandle; Win32FindData : TWin32FindData; FindExInfoLevels: TFINDEX_INFO_LEVELS; FindExSearchOps : TFINDEX_SEARCH_OPS; AdditionalFlags : DWORD; begin SetLength(Result, 0); FindExInfoLevels := FindExInfoBasic; FindExSearchOps := FindExSearchLimitToDirectories; AdditionalFlags := 0; FindExHandle := Windows.FindFirstFileEx(PChar(IncludeTrailingBackslash(BaseFolder) + FileMask) ,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, IncludeTrailingBackslash(BaseFolder) + Win32FindData.cFileName); until not Windows.FindNextFile(FindExHandle, Win32FindData); Windows.FindClose(FindExHandle); end; { TForm1 } function TForm1.MySearch(const BasePath, BaseFolder: string; const FileMask: string = '*.*'): TStrArr; var tmp, Folders, Files: TStrArr; i,ii: Integer; begin SetLength(tmp, 0); SetLength(Folders, 0); SetLength(Files, 0); tmp := GetAllFolders(BasePath, True); // sieve out folders that match criteria for i := Low(tmp) to High(tmp) do if (Pos(UpperCase(BaseFolder), UpperCase(tmp[i])) <> 0) then AddStrArr(Folders, tmp[i]); SetLength(tmp, 0); // get files that matching criteria for i := Low(Folders) to High(Folders) do begin tmp := GetAllFiles(Folders[i], FileMask); 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; procedure TForm1.Button1Click(Sender: TObject); var i: Integer; List: TStrArr; begin List := MySearch(Edit1.Text, Edit2.Text, Edit3.Text); ListBox1.Items.BeginUpdate; ListBox1.Clear; for i := Low(List) to High(List) do ListBox1.Items.Add(List[i]); ListBox1.Items.EndUpdate; end; end. 1er Parameter = Ein Basisverzeichnis (zBsp: C:\Users) 2er Parameter = Ein Verzeichnis worin gesucht werden soll (zBps: Documents) 3er Parameter = Eine Datei-Maske (zBsp: *.pas) |
AW: FindFirstFileEx liefert Error Falscher Parameter?
Falls ich mich jetzt nicht verschrieben hab
Delphi-Quellcode:
wobei :stupid:
uses
StrUtils, IOUtils; procedure TForm11.Button1Click(Sender: TObject); var List: TArray<string>; begin // GetAllFiles -> TDirectory.GetDirectories // GetAllFolders -> TDirectory.GetFiles for var Path in TDirectory.GetDirectories(BasePath.Text, TSearchOption.soAllDirectories {oder .soTopDirectoryOnly}, function(const Path: string; const SearchRec: TSearchRec): Boolean begin Result := ContainsText(TPath.Combine(Path, SearchRec.Name), BaseFolder.Text); end) do begin // AddStrArr(List, S); -> List := List + [S]; (schade, dass List += S; "noch" nicht geht) List := List + TDirectory.GetFiles(Path, Filter.Text, TSearchOption.soTopDirectoryOnly); end; ListBox1.Items.Clear; ListBox1.Items.AddStrings(List); end;
Delphi-Quellcode:
begin
List := TDirectory.GetFiles(BasePath.Text, Filter.Text, TSearchOption.soAllDirectories, function(const Path: string; const SearchRec: TSearchRec): Boolean begin Result := ContainsText(Path, BaseFolder.Text); end); ListBox1.Items.Clear; ListBox1.Items.AddStrings(List); end; |
AW: FindFirstFileEx liefert Error Falscher Parameter?
Hmmm ich kann meine Post nicht bearbeiten, wollte noch mein update dazu nachliefern.
Delphi-Quellcode:
Wohlgemerkt, geschrieben mit Lazarus und da ist ein String noch ein AnsiString, deswegen die casts.
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. ( 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. |
AW: FindFirstFileEx liefert Error Falscher Parameter?
Nja, da könnte man auch direkt Assembler schreiben, wenn man die vorhandenen einfacheren Lösungen nicht nimmt.
Die lokalen TStrArr sollten doch auch im FPC zu Beginn immer Length 0 sein und am Ende auch automatisch freigegeben werden, oder nicht? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:33 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz