Newsgroup: it.comp.lang.delphi
Titolo: FindFirst Next Close e try ... finally

Buongiorno a tutti;
a proposito delle funzioni per la ricerca di file messe a disposizione
da Delphi noto che alcuno (non ultimo lo stesso help di D: quindi a dire
il vero quasi tutti) usa un costrutto come (dall'example di D,
adattato):
if FindFirst(mask, attrs, sr) = 0 then
begin
  repeat
    if (sr.Attr and attr) = sr.Attr then
    begin
      UseSearchRec(sr);
    end;
  until FindNext(sr) <> 0;
  FindClose(sr);
end;
solo che l'help termina con: "Note: FindFirst allocates resources
(memory) which must be released by calling FindClose."
Ora, se e' vero quel che dice la nota, nel caso non si trovino file
(FindFirst <> 0) si ha un memory leak, dato che FindClose non viene
eseguito.
Se la nota dice il vero, una ricerca di file dovrebbe essere fatta come
segue:
try
  if FindFirst(mask, attr, SR) = 0 then begin
    repeat
      UseSearchRec(SR);
    until FindNext(SR) <> 0;
  end;
finally
  FindClose(SR);
end;
a maggior ragione se UseSearchRec ha la minima possibilita' di sollevare
un'eccezione.
E' ben vero che win32.hlp dice a proposito di FindFirstFile: "_If the
function succeeds_, the return value is a search handle used in a
subsequent call to FindNextFile or FindClose" (il corsivo e' mio). Ma
allora il senso della nota nell'help di Delphi e' completamente fasullo
(o, quasi peggio, vero solo in alcuni casi).
Se, allora, FindFirst si comporta come FindFirstFile, si dovrebbe
scrivere:
if FindFirst(mask, attr, SR) = 0 then
try
  repeat
    UseSearchRec(SR);
  until FindNext(SR) <> 0;
finally
  FindClose(SR);
end;
Opinioni, suggerimenti etc ben accetti.
btw, che ne pensate del SysUtils.FindMatchingFile chiamato in FindFirst?
e perche' il campo ExcludeAttr di TSearchRec non e' documentato?
Saluti
Paolo Arosio

un'eccezione.
Io uso FindClose al di fuori del blocco try/finally, solo se sono
sicuro che non vi sono istruzioni, tra FindFirst e FindClose, che
sollevino eccezioni (tieni presente che l'uso del costrutto try/...
aggiunge un certo overhead al programma).
-- 
Andrea Laforgia
"God is dead." -- Nietzsche
"Nietzsche is dead." -- God

 La FindClose va *comunque* chiamata.
Sembra proprio di no, invece (cioe', la nota sbaglia e findfirst si
comporta come findfirstfile):
Quanto segue e' stato provato con MemProof 
http://www.automatedqa.com
(consigliato)
e ritorna 1 solo unfreed resource, ovviamente se MakeLeaks e'
undefined(provocato dal GetStdHandle dovuto ai writeln: pare che delphi
non chiuda lo stdio al termine del programma).
Saluti
Paolo Arosio
program FindFirstNextClose;
{$APPTYPE CONSOLE}
{. $DEFINE MakeLeaks}
uses
  Windows,
  SysUtils;
procedure ScanDir(const p, f: TFilename; attr: integer;
  var dir, cnt: integer);
var msk: TFilename;
    SR: TSearchRec;
begin
  msk := IncludeTrailingPathDelimiter(p) + f;
  inc(dir);
  OutputDebugString(PChar('Searching ' + msk));
  if FindFirst(msk, attr, SR) = 0 then
  begin
    repeat
      inc(cnt);
      OutputDebugString(PChar(SR.Name));
    until FindNext(SR) <> 0;
    FindClose(SR);
  end;
end;
procedure ScanSubTree(const p, f: TFilename; attr: integer;
  var dir, cnt: integer);
var msk: TFilename;
    SR: TSearchRec;
begin
  OutputDebugString(PChar('Scanning subtree ' + p));
  msk := IncludeTrailingPathDelimiter(p) + '*.*';
  if FindFirst(msk, faDirectory, SR) = 0 then
  begin
    repeat
      if (SR.Name[1] <> '.') and
        ((SR.Attr and faDirectory) = faDirectory) then
        ScanSubTree(IncludeTrailingPathDelimiter(p) + SR.Name,
          f, attr, dir, cnt);
    until FindNext(SR) <> 0;
    {$IFDEF MakeLeaks}
    if odd(dir) then
    {$ENDIF}
    FindClose(SR);
  end;
  ScanDir(p, f, attr, dir, cnt);
end;
procedure CercaFileInesistente(var dir, cnt: integer);
begin
  ScanSubtree('C:\', '*.file', faAnyfile, dir, cnt);
end;
var
  DirSearched, Hit: integer;
  Start, Stop: Cardinal;
begin
  Start := GetTickCount;
  CercaFileInesistente(dirSearched, Hit);
  Stop := GetTickCount;
  writeln('');
  writeln('Time elapsed ', Stop-Start, ' ms;');
  writeln('Searched ', dirSearched, ' directories;');
  writeln('Found ', hit, ' files.');
end.

comporta come findfirstfile):
Non ho tempo di guarda il codice, ma ho dato una scorsa veloce al
codice assembly di FindFirst e non è altro che una wrapper per
FindFirstFile, quindi (se è una wrapper fedele) dovrebbe, come dici,
comportarsi allo stesso modo.  In ogni caso mi riprometto di vedere
meglio come funziona internamente.  Credo, comunque, che una chiamata
a FindClose sia innocua anche quando non serve (nel senso che non
produce danni come la liberazione di un oggetto già deallocato per
esempio).
