home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 March / Chip_2002-03_cd1.bin / zkuste / delphi / kompon / d13456 / FINDFILE.ZIP / FindFile.pas < prev    next >
Pascal/Delphi Source File  |  2001-12-26  |  22KB  |  747 lines

  1. {------------------------------------------------------------------------------}
  2. {                                                                              }
  3. {  TFindFile v2.22                                                             }
  4. {  by Kambiz R. Khojasteh                                                      }
  5. {                                                                              }
  6. {  kambiz@delphiarea.com                                                       }
  7. {  http://www.delphiarea.com                                                   }
  8. {                                                                              }
  9. {------------------------------------------------------------------------------}
  10.  
  11. unit FindFile;
  12.  
  13. interface
  14.  
  15. uses
  16.   {$IFDEF WIN32} Windows {$ELSE} WinTypes, WinProcs {$ENDIF}, Messages,
  17.   SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
  18.  
  19. type
  20.  
  21.   EFindFileError = class(Exception);
  22.  
  23.   TFoundEvent = procedure (Sender: TObject; Folder: String;
  24.     var FileInfo: TSearchRec) of object;
  25.  
  26.   TNewFolderEvent = procedure (Sender: TObject; Folder: String;
  27.     var IgnoreFolder: Boolean) of object;
  28.  
  29.   TFileAttribute = (ffArchive, ffReadonly, ffHidden, ffSystem, ffDirectory);
  30.   TFileAttributes = set of TFileAttribute;
  31.  
  32.   {TSearchInfo holds all search parameters. This gives us ability to}
  33.   {change TFinFile properties while it is searching.}
  34.   TSearchInfo = packed record
  35.      IncludeFiles: TStringList;
  36.      ExcludeFiles: TStringList;
  37.      IncSubfolders: Boolean;
  38.      Attr: TFileAttributes;
  39.      ExactAttr: Boolean;
  40.      {$IFDEF WIN32}
  41.      CreatedBefore: TDateTime;
  42.      CreatedAfter: TDateTime;
  43.      AccessedBefore: TDateTime;
  44.      AccessedAfter: TDateTime;
  45.      {$ENDIF}
  46.      ModifiedBefore: TDateTime;
  47.      ModifiedAfter: TDateTime;
  48.      SizeMin: LongInt;
  49.      SizeMax: LongInt;
  50.      Text: PChar;
  51.      IgnoreCase: Boolean;
  52.   end;
  53.  
  54.   TFindFile = class(TComponent)
  55.   private
  56.     fFilename: String;
  57.     fLocation: String;
  58.     fIncludeFiles: TStringList;
  59.     fExcludeFiles: TStringList;
  60.     fSubfolders: Boolean;
  61.     fModifiedBefore: TDateTime;
  62.     fModifiedAfter: TDateTime;
  63.     fSizeMin: LongInt;
  64.     fSizeMax: LongInt;
  65.     fAttributes: TFileAttributes;
  66.     fExactAttr: Boolean;
  67.     {$IFDEF WIN32}
  68.     fCreatedBefore: TDateTime;
  69.     fCreatedAfter: TDateTime;
  70.     fAccessedBefore: TDateTime;
  71.     fAccessedAfter: TDateTime;
  72.     {$ENDIF}
  73.     fContaining: String;
  74.     fIgnoreCase: Boolean;
  75.     fAborted: Boolean;
  76.     fBusy: Boolean;
  77.     fOnFound: TFoundEvent;
  78.     fOnNewFolder: TNewFolderEvent;
  79.     fOnComplete: TNotifyEvent;
  80.     SI: TSearchInfo;
  81.     {$IFDEF WIN32}
  82.     fThread: TThread;
  83.     fThreaded: Boolean;
  84.     fThreadPriority: TThreadPriority;
  85.     procedure ThreadTerminated(Sender: TObject);
  86.     procedure SetThreadPriority(Value: TThreadPriority);
  87.     {$ENDIF}
  88.     procedure SetFilename(Value: String);
  89.     procedure SetLocation(Value: String);
  90.     procedure SetIncludeFiles(Value: TStringList);
  91.     procedure SetExcludeFiles(Value: TStringList);
  92.   protected
  93.     {$IFDEF WIN32}
  94.     procedure DoThreadedSearch; dynamic;
  95.     {$ENDIF}
  96.     procedure DoSearch; dynamic;
  97.     procedure DoFound(Folder: String; var FileInfo: TSearchRec); virtual;
  98.     function DoNewFolder(const Folder: String): Boolean; virtual;
  99.     procedure DoComplete; virtual;
  100.     function AcceptFile(const Folder: String; const SR: TSearchRec): Boolean;
  101.   public
  102.     constructor Create(AOwner: TComponent); override;
  103.     destructor Destroy; override;
  104.     procedure Execute;
  105.     procedure Abort;
  106.     property Busy: Boolean read fBusy;
  107.     property Aborted: Boolean read fAborted;
  108.   published
  109.     property Filename: String read fFilename write SetFilename;
  110.     property Location: String read fLocation write SetLocation;
  111.     property IncludeFiles: TStringList read fIncludeFiles write SetIncludeFiles;
  112.     property ExcludeFiles: TStringList read fExcludeFiles write SetExcludeFiles;
  113.     property Subfolders: Boolean read fSubfolders write fSubfolders default True;
  114.     property Attributes: TFileAttributes read fAttributes write fAttributes default
  115.       [ffArchive, ffReadonly, ffHidden, ffSystem];
  116.     property ExactAttribute: Boolean read fExactAttr write fExactAttr default False;
  117.     property ModifiedBefore: TDateTime read fModifiedBefore write fModifiedBefore;
  118.     property ModifiedAfter: TDateTime read fModifiedAfter write fModifiedAfter;
  119.     {$IFDEF WIN32}
  120.     property CreatedBefore: TDateTime read fCreatedBefore write fCreatedBefore;
  121.     property CreatedAfter: TDateTime read fCreatedAfter write fCreatedAfter;
  122.     property AccessedBefore: TDateTime read fAccessedBefore write fAccessedBefore;
  123.     property AccessedAfter: TDateTime read fAccessedAfter write fAccessedAfter;
  124.     {$ENDIF}
  125.     property SizeMin: LongInt read fSizeMin write fSizeMin default 0;
  126.     property SizeMax: LongInt read fSizeMax write fSizeMax default 0;
  127.     property Containing: String read fContaining write fContaining;
  128.     property IgnoreCase: Boolean read fIgnoreCase write fIgnoreCase default True;
  129.     {$IFDEF WIN32}
  130.     property Threaded: Boolean read fThreaded write fThreaded default False;
  131.     property ThreadPriority: TThreadPriority read fThreadPriority write
  132.       SetThreadPriority default tpNormal;
  133.     {$ENDIF}
  134.     property OnFound: TFoundEvent read fOnFound write fOnFound;
  135.     property OnNewFolder: TNewFolderEvent read fOnNewFolder write fOnNewFolder;
  136.     property OnComplete: TNotifyEvent read fOnComplete write fOnComplete;
  137.   end;
  138.  
  139. procedure Register;
  140.  
  141. function RemoveTrailingBackslash(S: String): String;
  142. function FileMatches(Path, Mask: String): Boolean;
  143.  
  144. implementation
  145.  
  146. {$IFDEF WIN32}
  147.   {$R *.D32}
  148. {$ELSE}
  149.   {$R *.D16}
  150. {$ENDIF}
  151.  
  152. uses
  153.   FileCtrl;
  154.  
  155. const
  156.   BufferSize = 4096;
  157.   PathDelimiter = ';';
  158.   SearchAttr = faAnyFile and not faVolumeID;
  159.   InvalidLocation = '%s' + #10#13 + 'location cannot to be contained wildcards';
  160.   InvalidFilename = '%s' + #10#13 + 'Invalid filename specified';
  161.  
  162. {$IFDEF WIN32}
  163. type
  164.   TSearchThread = class(TThread)
  165.   private
  166.     Ignored: Boolean;
  167.     Folder: String;
  168.     FoundSR: TSearchRec;
  169.     FindFile: TFindFile;
  170.     procedure NewFolderEntered;
  171.     procedure FileFound;
  172.   protected
  173.     constructor Create(AFindFile: TFindFile);
  174.     procedure Execute; override;
  175.   end;
  176. {$ENDIF}
  177.  
  178. procedure Register;
  179. begin
  180.   RegisterComponents('Delphi Area', [TFindFile]);
  181. end;
  182.  
  183. function RemoveTrailingBackslash(S: String): String;
  184. begin
  185.   if (Length(S) > 1) and (S[Length(S)] = '\') and (S[Length(S)-1] <> ':') then
  186.     Result := Copy(S, 1, Length(S)-1)
  187.   else
  188.     Result := S;
  189. end;
  190.  
  191. function FileMatches(Path, Mask: String): Boolean;
  192. var
  193.   Fi, Mi: Integer;
  194.   FilePath, FileName: String;
  195.   MaskPath, MaskName: String;
  196. begin
  197.   Result := False;
  198.   FilePath := UpperCase(ExtractFilePath(Path));
  199.   FileName := UpperCase(ExtractFileName(Path));
  200.   MaskPath := UpperCase(ExtractFilePath(Mask));
  201.   MaskName := UpperCase(ExtractFileName(Mask));
  202.   {Checkes file path part, if mask contains path}
  203.   if Length(MaskPath) > 0 then
  204.   begin
  205.     {Checkes drive, if mask contains drive}
  206.     if (Length(MaskPath) >= 2) and (MaskPath[2] = ':') then
  207.     begin
  208.       if not (MaskPath[1] in ['*','?']) and (MaskPath[1] <> FilePath[1]) then
  209.         Exit; {Not Matched}
  210.       {Removes drive part from the path}
  211.       MaskPath := Copy(MaskPath, 3, Length(MaskPath)-2);
  212.     end;
  213.     {Checkes directory}                  { |-> excludes drive length}
  214.     if Length(MaskPath) > Length(FilePath)-2 then
  215.       Exit {Not Matched, Mask is latger than file path}
  216.     else
  217.     begin
  218.       {we check inner directories}
  219.       FilePath := Copy(FilePath, Length(FilePath)-Length(MaskPath)+1, Length(MaskPath));
  220.       if FilePath <> MaskPath then
  221.         Exit {Not Matched}
  222.     end;
  223.   end;
  224.   {Checkes file name part, if mask contains filename}
  225.   if Length(MaskName) > 0 then
  226.   begin
  227.     Mi := 1;
  228.     Fi := 1;
  229.     while (Mi <= Length(MaskName)) and (Fi <= Length(FileName)) do
  230.     begin
  231.       if (FileName[Fi] = MaskName[Mi]) or ((FileName[Fi] <> '.') and (MaskName[Mi] = '?')) then
  232.       begin
  233.         Inc(Mi);
  234.         Inc(Fi);
  235.       end
  236.       else if FileName[Fi] = '.' then
  237.         if MaskName[Mi] = '?' then
  238.           Inc(Mi)
  239.         else if MaskName[Mi] = '*' then
  240.           while (Mi <= Length(MaskName)) and (MaskName[Mi] <> '.') do
  241.             Inc(Mi)
  242.         else
  243.           Exit {Not matched}
  244.       else if MaskName[Mi] = '*' then
  245.         Inc(Fi)
  246.       else
  247.         Exit; {Not matched}
  248.     end;
  249.     while (Mi <= Length(MaskName)) and (MaskName[Mi] in ['?', '*']) do
  250.      Inc(Mi);
  251.     if (Mi > Length(MaskName)) and (Fi > Length(FileName)) then
  252.       Result := True; {Matched}
  253.   end
  254.   else
  255.     Result := True; {Matched}
  256. end;
  257.  
  258. constructor TFindFile.Create(AOwner: TComponent);
  259. begin
  260.   inherited Create(AOwner);
  261.   fAttributes := [ffArchive, ffReadonly, ffHidden, ffSystem];
  262.   fExactAttr := False;
  263.   fFilename := '*.*';
  264.   fIncludeFiles := TStringList.Create;
  265.   fExcludeFiles := TStringList.Create;
  266.   fSubfolders := True;
  267.   fIgnoreCase := True;
  268.   fBusy := False;
  269.   {$IFDEF WIN32}
  270.   fThread := nil;
  271.   fThreaded := False;
  272.   fThreadPriority := tpNormal;
  273.   {$ENDIF}
  274. end;
  275.  
  276. destructor TFindFile.Destroy;
  277. begin
  278.   {$IFDEF WIN32}
  279.   if Assigned(fThread) then
  280.   begin
  281.     fThread.Terminate;
  282.     fThread.WaitFor;
  283.   end;
  284.   {$ENDIF}
  285.   fIncludeFiles.Free;
  286.   fExcludeFiles.Free;
  287.   inherited Destroy;
  288. end;
  289.  
  290. procedure TFindFile.SetFilename(Value: String);
  291. begin
  292.   if ExtractFileName(Value) = Value then
  293.     fFilename := Value
  294.   else
  295.     raise EFindFileError.CreateFmt(InvalidFilename, [Value]);
  296. end;
  297.  
  298. procedure TFindFile.SetLocation(Value: String);
  299. begin
  300.   if (Pos('*', Value) = 0) and (Pos('?', Value) = 0) then
  301.     fLocation := Value
  302.   else
  303.     raise EFindFileError.CreateFmt(InvalidLocation, [Value]);
  304. end;
  305.  
  306. procedure TFindFile.SetIncludeFiles(Value: TStringList);
  307. begin
  308.   if Assigned(Value) then
  309.     fIncludeFiles.Assign(Value)
  310.   else
  311.     fIncludeFiles.Clear;
  312. end;
  313.  
  314. procedure TFindFile.SetExcludeFiles(Value: TStringList);
  315. begin
  316.   if Assigned(Value) then
  317.     fExcludeFiles.Assign(Value)
  318.   else
  319.     fExcludeFiles.Clear;
  320. end;
  321.  
  322. {$IFDEF WIN32}
  323. procedure TFindFile.SetThreadPriority(Value: TThreadPriority);
  324. begin
  325.   fThreadPriority := Value;
  326.   if Assigned(fThread) then
  327.     fThread.Priority := Value;
  328. end;
  329. {$ENDIF}
  330.  
  331. procedure TFindFile.Execute;
  332.  
  333.   procedure AddToIncludeList(Loc, Filename: String);
  334.   var
  335.     Path: String;
  336.     P, I: Integer;
  337.     Duplicated: Boolean;
  338.   begin
  339.     if fFilename = '' then
  340.       Filename := '*.*'
  341.     else if Pos('.', Filename) = 0 then
  342.       Filename := Filename + '.*';
  343.     repeat
  344.       P := Pos(PathDelimiter, Loc);
  345.       if P > 0 then
  346.       begin
  347.         Path := Copy(Loc, 1, P-1);
  348.         Delete(Loc, 1, P);
  349.       end
  350.       else
  351.       begin
  352.         Path := Loc;
  353.         Loc := '';
  354.       end;
  355.       if Path = '' then
  356.         Path := ExpandFileName('.')
  357.       else
  358.         Path := ExpandFileName(Path);
  359.       if Path[Length(Path)] <> '\' then
  360.         Path := Path + '\';
  361.       Path := Path + Filename;
  362.       Duplicated := False;
  363.       for I := 0 to SI.IncludeFiles.Count-1 do
  364.         if CompareText(SI.IncludeFiles[I], Path) = 0 then
  365.         begin
  366.           Duplicated := True;
  367.           Break;
  368.         end;
  369.       if not Duplicated then
  370.         SI.IncludeFiles.Add(Path);
  371.     until (Length(Loc) = 0) or (Loc = PathDelimiter);
  372.   end;
  373.  
  374. begin
  375.   if fBusy then Exit;
  376.   fBusy := True;
  377.   {Sets file attributes}
  378.   SI.Attr := fAttributes;
  379.   SI.ExactAttr := fExactAttr;
  380.   {Sets included files}
  381.   SI.IncludeFiles := TStringList.Create;
  382.   if fIncludeFiles.Count > 0 then
  383.     SI.IncludeFiles.Assign(fIncludeFiles)
  384.   else {Addes filename and location to included files}
  385.     AddToIncludeList(fLocation, fFileName);
  386.   SI.IncSubfolders := fSubfolders;
  387.   {Sets excluded files}
  388.   SI.ExcludeFiles := TStringList.Create;
  389.   SI.ExcludeFiles.Assign(fExcludeFiles);
  390.   {Sets date ranges}
  391.   {$IFDEF WIN32}
  392.   SI.AccessedBefore := fAccessedBefore;
  393.   SI.AccessedAfter := fAccessedAfter;
  394.   SI.CreatedBefore := fCreatedBefore;
  395.   SI.CreatedAfter := fCreatedAfter;
  396.   {$ENDIF}
  397.   SI.ModifiedBefore := fModifiedBefore;
  398.   SI.ModifiedAfter := fModifiedAfter;
  399.   {Sets files size ranges}
  400.   SI.SizeMin := fSizeMin;
  401.   SI.SizeMax := fSizeMax;
  402.   {Sets containing text}
  403.   if fContaining <> '' then
  404.   begin
  405.     SI.IgnoreCase := fIgnoreCase;
  406.     GetMem(SI.Text, Length(fContaining)+1);
  407.     StrPCopy(SI.Text, fContaining);
  408.   end;
  409.   {Starts search}
  410.   fAborted := False;
  411.   {$IFDEF WIN32}
  412.   if fThreaded then
  413.     DoThreadedSearch
  414.   else
  415.   {$ENDIF}
  416.     DoSearch;
  417. end;
  418.  
  419. procedure TFindFile.Abort;
  420. begin
  421.   fAborted := True;
  422.   {$IFDEF WIN32}
  423.   if Assigned(fThread) then
  424.   begin
  425.     fThread.Terminate;
  426.     repeat
  427.       Application.ProcessMessages
  428.     until not Busy;
  429.   end;
  430.   {$ENDIF}
  431. end;
  432.  
  433. var
  434.  Buffer: array[0..BufferSize-1] of Char;
  435.  
  436. function TFindFile.AcceptFile(const Folder: String; const SR: TSearchRec): Boolean;
  437.  
  438.   function ValidFileAttr: Boolean;
  439.   var
  440.     FileAttr: TFileAttributes;
  441.   begin
  442.     Result := False;
  443.     FileAttr := [];
  444.     if (SR.Attr and faArchive) <> 0 then Include(FileAttr, ffArchive);
  445.     if (SR.Attr and faReadonly) <> 0 then Include(FileAttr, ffReadonly);
  446.     if (SR.Attr and faHidden) <> 0 then Include(FileAttr, ffHidden);
  447.     if (SR.Attr and faSysFile) <> 0 then Include(FileAttr, ffSystem);
  448.     if (SR.Attr and faDirectory) <> 0 then Include(FileAttr, ffDirectory);
  449.     if SI.ExactAttr then
  450.     begin
  451.       if FileAttr = SI.Attr then
  452.         Result := True;
  453.     end
  454.     else if (FileAttr = []) or ((FileAttr * SI.Attr) <> []) then
  455.       Result := True;
  456.   end;
  457.  
  458.   function DateBetween(aDate, Before, After: TDateTime): Boolean;
  459.   begin
  460.     Result := True;
  461.     if Before <> 0 then
  462.       if Frac(Before) = 0 then      { Checks date only }
  463.         Result := Result and (Int(aDate) <= Before)
  464.       else if Int(Before) = 0 then  { Checks time only }
  465.         Result := Result and (Frac(aDate) <= Before)
  466.       else                          { Checks date and time }
  467.         Result := Result and (aDate <= Before);
  468.     if After <> 0 then
  469.       if Frac(After) = 0 then       { Checks date only }
  470.         Result := Result and (Int(aDate) >= After)
  471.       else if Int(After) = 0 then   { Checks time only }
  472.         Result := Result and (Frac(aDate) >= After)
  473.       else                          { Checks date and time }
  474.         Result := Result and (aDate >= After);
  475.   end;
  476.  
  477.   function FileContainsText: Boolean;
  478.   var
  479.     Stream: TFileStream;
  480.     I, TextLen, ReadLen: LongInt;
  481.     {$IFDEF WIN32}
  482.     Compare: function(const Str1, Str2: PChar; MaxLen: Cardinal): Integer;
  483.     {$ELSE}
  484.     Compare: function(Str1, Str2: PChar; MaxLen: Word): Integer;
  485.     {$ENDIF}
  486.   begin
  487.     Result := False;
  488.     {$IFDEF WIN32}
  489.     if SI.IgnoreCase then Compare := @StrLIComp else Compare := @StrLComp;
  490.     {$ELSE}
  491.     if SI.IgnoreCase then Compare := StrLIComp else Compare := StrLComp;
  492.     {$ENDIF}
  493.     TextLen := StrLen(SI.Text);
  494.     Stream := TFileStream.Create(Folder + SR.Name, fmOpenRead or fmShareDenyNone);
  495.     try try
  496.       repeat
  497.         ReadLen := Stream.Read(Buffer, BufferSize);
  498.         for I := 0 to ReadLen - TextLen do
  499.           if Compare(SI.Text, @Buffer[I], TextLen) = 0 then
  500.           begin
  501.             Result := True;
  502.             Break;
  503.           end;
  504.       until Stream.Position >= Stream.Size;
  505.     except
  506.       {Ignores exceptions}
  507.     end;
  508.     finally
  509.       Stream.Free;
  510.     end;
  511.   end;
  512.  
  513. var
  514.   I: Integer;
  515.   TheDate: TDateTime;
  516.   {$IFDEF WIN32}
  517.   SystemTime: TSystemTime;
  518.   FileTime: TFileTime;
  519.   {$ENDIF}
  520. begin
  521.   Result := False;
  522.   {Checkes file attributes}
  523.   if not ValidFileAttr then Exit;
  524.   {Checkes file size ranges}
  525.   if (SR.Attr and faDirectory) = 0 then
  526.   begin
  527.     if (SI.SizeMin <> 0) and (SR.Size < SI.SizeMin) then Exit;
  528.     if (SI.SizeMax <> 0) and (SR.Size > SI.SizeMax) then Exit;
  529.   end;
  530.   {Checkes file date ranges}
  531.   {$IFDEF WIN32}
  532.   if (SI.CreatedBefore <> 0) or (SI.CreatedAfter <> 0) then
  533.   begin
  534.     FileTimeToLocalFileTime(SR.FindData.ftCreationTime, FileTime);
  535.     FileTimeToSystemTime(FileTime, SystemTime);
  536.     TheDate := SystemTimeToDateTime(SystemTime);
  537.     if not DateBetween(TheDate, SI.CreatedBefore, SI.CreatedAfter) then Exit;
  538.   end;
  539.   if (SI.ModifiedBefore <> 0) or (SI.ModifiedAfter <> 0) then
  540.   begin
  541.     FileTimeToLocalFileTime(SR.FindData.ftLastWriteTime, FileTime);
  542.     FileTimeToSystemTime(FileTime, SystemTime);
  543.     TheDate := SystemTimeToDateTime(SystemTime);
  544.     if not DateBetween(TheDate, SI.ModifiedBefore, SI.ModifiedAfter) then Exit;
  545.   end;
  546.   if (SI.AccessedBefore <> 0) or (SI.AccessedAfter <> 0) then
  547.   begin
  548.     FileTimeToLocalFileTime(SR.FindData.ftLastAccessTime, FileTime);
  549.     FileTimeToSystemTime(FileTime, SystemTime);
  550.     TheDate := SystemTimeToDateTime(SystemTime);
  551.     if not DateBetween(TheDate, SI.AccessedBefore, SI.AccessedAfter) then Exit;
  552.   end;
  553.   {$ELSE}
  554.   if (SI.ModifiedBefore <> 0) or (SI.ModifiedAfter <> 0) then
  555.   begin
  556.     TheDate := FileDateToDateTime(SR.Time);
  557.     if not DateBetween(TheDate, SI.ModifiedBefore, SI.ModifiedAfter) then Exit;
  558.   end;
  559.   {$ENDIF}
  560.   {Checkes exclude file list}
  561.   for I := 0 to SI.ExcludeFiles.Count-1 do
  562.     if FileMatches(Folder + SR.Name, SI.ExcludeFiles[I]) then Exit;
  563.   {Checkes containing text}
  564.   if (SI.Text <> nil) and ((SR.Attr and faDirectory) = 0) then
  565.     Result := FileContainsText
  566.   else
  567.     Result := True;
  568. end;
  569.  
  570. procedure TFindFile.DoFound(Folder: String; var FileInfo: TSearchRec);
  571. begin
  572.   if Assigned(fOnFound) and not (csDestroying in ComponentState) then
  573.     fOnFound(Self, RemoveTrailingBackslash(Folder), FileInfo);
  574. end;
  575.  
  576. function TFindFile.DoNewFolder(const Folder: String): Boolean;
  577. var
  578.   Ignored: Boolean;
  579. begin
  580.   Ignored := False;
  581.   if Assigned(fOnNewFolder) and not (csDestroying in ComponentState) then
  582.     fOnNewFolder(Self, RemoveTrailingBackslash(Folder), Ignored);
  583.   Result := not Ignored;
  584. end;
  585.  
  586. procedure TFindFile.DoComplete;
  587. begin
  588.   if SI.IncludeFiles <> nil then
  589.   begin
  590.     SI.IncludeFiles.Free;
  591.     SI.IncludeFiles := nil;
  592.   end;
  593.   if SI.ExcludeFiles <> nil then
  594.   begin
  595.     SI.ExcludeFiles.Free;
  596.     SI.ExcludeFiles := nil;
  597.   end;
  598.   if SI.Text <> nil then
  599.   begin
  600.     FreeMem(SI.Text, StrLen(SI.Text)+1);
  601.     SI.Text := nil;
  602.   end;
  603.   fBusy := False;
  604.   if Assigned(fOnComplete) and not (csDestroying in ComponentState) then
  605.     fOnComplete(Self);
  606. end;
  607.  
  608. procedure TFindFile.DoSearch;
  609.  
  610.   procedure SearchIn(Loc: String; var FileMask: String);
  611.   var
  612.     SR: TSearchRec;
  613.     Path: String;
  614.   begin
  615.     if not DoNewFolder(Loc) then Exit;
  616.     Path := Loc + FileMask;
  617.     {Searches current folder}
  618.     if not fAborted and (FindFirst(Path, SearchAttr, SR) = 0) then
  619.       repeat
  620.         if (SR.Name[1] <> '.') and AcceptFile(Loc, SR) then
  621.           DoFound(Loc, SR);
  622.       until Aborted or (FindNext(SR) <> 0);
  623.     FindClose(SR);
  624.     {Scans sub folders}
  625.     if not Aborted and SI.IncSubfolders then
  626.     begin
  627.       Path := Loc + '*.*';
  628.       if not Aborted and (FindFirst(Path, SearchAttr, SR) = 0) then
  629.         repeat
  630.           if ((SR.Attr and faDirectory) <> 0) and (SR.Name[1] <> '.') then
  631.             SearchIn(Loc + SR.Name + '\', FileMask);
  632.         until Aborted or (FindNext(SR) <> 0);
  633.       FindClose(SR);
  634.     end;
  635.   end;
  636.  
  637. var
  638.   I: Integer;
  639.   Folder, Filename: String;
  640.  
  641. begin
  642.   try
  643.     try
  644.       for I := 0 to SI.IncludeFiles.Count-1 do
  645.       begin
  646.         Folder := ExpandFileName(ExtractFilePath(SI.IncludeFiles[I]));
  647.         Filename := ExtractFileName(SI.IncludeFiles[I]);
  648.         SearchIn(Folder, Filename);
  649.         if fAborted then Break;
  650.       end;
  651.     except
  652.       fAborted := True;
  653.     end;
  654.   finally
  655.     DoComplete;
  656.   end;
  657. end;
  658.  
  659. {$IFDEF WIN32}
  660.  
  661. procedure TFindFile.DoThreadedSearch;
  662. begin
  663.   fThread := TSearchThread.Create(Self);
  664. end;
  665.  
  666. procedure TFindFile.ThreadTerminated(Sender: TObject);
  667. begin
  668.   fThread := nil;
  669.   DoComplete;
  670. end;
  671.  
  672. constructor TSearchThread.Create(AFindFile: TFindFile);
  673. begin
  674.   FindFile := AFindFile;
  675.   OnTerminate := FindFile.ThreadTerminated;
  676.   FreeOnTerminate := True;
  677.   inherited Create(False);
  678. end;
  679.  
  680. procedure TSearchThread.NewFolderEntered;
  681. begin
  682.   Ignored := not FindFile.DoNewFolder(Folder);
  683. end;
  684.  
  685. procedure TSearchThread.FileFound;
  686. begin
  687.   FindFile.DoFound(Folder, FoundSR);
  688. end;
  689.  
  690. procedure TSearchThread.Execute;
  691.  
  692.   procedure SearchIn(Loc: String; var FileMask: String);
  693.   var
  694.     SR: TSearchRec;
  695.     Path: String;
  696.   begin
  697.     Folder := Loc;
  698.     Synchronize(NewFolderEntered);
  699.     if Ignored then Exit;
  700.     Path := Loc + FileMask;
  701.     {Searches current folder}
  702.     if not Terminated and (FindFirst(Path, SearchAttr, SR) = 0) then
  703.       repeat
  704.         if (SR.Name[1] <> '.') and FindFile.AcceptFile(Loc, SR) then
  705.         begin
  706.           Folder := Loc;
  707.           FoundSR := SR;
  708.           Synchronize(FileFound);
  709.         end;
  710.       until Terminated or (FindNext(SR) <> 0);
  711.     FindClose(SR);
  712.     {Scans sub folders}
  713.     if not Terminated and FindFile.SI.IncSubfolders then
  714.     begin
  715.       Path := Loc + '*.*';
  716.       if not Terminated and (FindFirst(Path, SearchAttr, SR) = 0) then
  717.         repeat
  718.           if ((SR.Attr and faDirectory) <> 0) and (SR.Name[1] <> '.') then
  719.             SearchIn(Loc + SR.Name + '\', FileMask);
  720.         until Terminated or (FindNext(SR) <> 0);
  721.       FindClose(SR);
  722.     end;
  723.   end;
  724.  
  725. var
  726.   I: Integer;
  727.   Folder, Filename: String;
  728.  
  729. begin
  730.   try
  731.     for I := 0 to FindFile.SI.IncludeFiles.Count-1 do
  732.     begin
  733.       Folder := ExpandFileName(ExtractFilePath(FindFile.SI.IncludeFiles[I]));
  734.       Filename := ExtractFileName(FindFile.SI.IncludeFiles[I]);
  735.       SearchIn(Folder, Filename);
  736.       if FindFile.fAborted then Break;
  737.     end;
  738.   except
  739.     FindFile.fAborted := True;
  740.   end;
  741. end;
  742.  
  743. {$ENDIF}
  744.  
  745. end.
  746.  
  747.