Newsgroup: it.comp.lang.delphi
Titolo: Filexists e PC lenti

Via ShellExecAndWait presente nella libreria Jcl eseguo un file .bat che 
tramite la libreria OpenSSL toglie la firma da un file della fattura 
elettronica trasformandolo in un file .xml in chiaro.
 
Subito dopo eseguo una verifica dell'esistenza del file in chiaro:
 
if FileExists(fe.xml) then ...
 
ma su alcuni vecchi pc, lenti, la funzione restituisce false anche se il 
file viene effettivamente creato solo che dal filesystem sembra essere 
rilevato in ritardo.
 
Ho provato anche a mettere una pausa di un secondo (sleep(1000)) prima 
della chiamata a FileExists ma non risolvo.
 
Qualche suggerimento?
 
Grazie.

Ciao,
sembra che l'applicazione non attenda il completamento del processo batch che viene eseguito.
Potrebbe essere un problema del file batch?
 
Alessandro


Magari il batch lancia in "modo asincrono" il programma che toglie la 
firma?
 
Ciao, Mario

Per prima  cosa, quando dici "ma su alcuni vecchi pc, lenti", cosa intendi? Questi pc hanno dischi SSD?
Poi, succede su TUTTI questi "vecchi" pc? E sta cosa è SISTEMATICA o capita a capa di kaz?
Ancora, sarebbe utile che tu condividessi il contenuto del file batch...
Poi, hai verificato che quel particolare uso di OpenSSL non abbia un qualche parametro che indichi se l'esecuzione deve essere sincrona  etc etc?
*** Nota: Magari c'è una opzione che imposta degli attributi una volta generato il file in chiaro...? ***
 
Su 2 piedi mi vengono in mente 3 cose:
 
1) invece di usare fileexists provare ad usare ShellApi.
Non sai cosa è e/o come si usa? Google rulez!
 
2) invece di usare fileexists usare un hook legato ad eventi del file system. Non ho approfondito ma magari c'è qualche evento che  puoi usare.
https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shchangenotifyregister
 
https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shchangenotify
 
*** C'è di sicuro un evento legato alla modifica degli attributi di un file. ***
 
3) Mollare il batch e usare quanto descritto qua...è in c# ma, trattandosi di una chiamata al sistema operativo,  la conversione in delphi è semplice:
 
https://www.fluxbytes.com/csharp/remove-digital-signature-from-a-file-using-c/
 
 
A.
 
 

 
Questo il codice del file .bat:
 
copy %1 %3
set OPENSSL_CONF=OpenSSL102q\openssl.cfg
set OPENSSL_DIR=OpenSSL102q\
Openssl102q\openssl cms -verify -in %1 -noverify -inform DER -out %2
 
if exist %2 goto FINE
 
:FILE64
copy %3 %1
del %3
Openssl102q\openssl enc -d -A -base64 -in %1 -out %3
Openssl102q\openssl smime -verify -in %3 -noverify -inform DER -out %2
 
:FINE
del %3
 
Il file .bat funziona perfettamente sia su PC prestanti che su PC lenti.
 
La successiva chiamata a FileExists su PC prestanti restituisce True sui 
PC lenti a seconda del carico di lavoro restituisce False.
 
Grazie.

Questo è il codice della funzione presente nella libreria Jcl:
 
function ShellExecAndWait(const FileName: string; const Parameters: string;
   const Verb: string; CmdShow: Integer; const Directory: string): Boolean;
var
   Sei: TShellExecuteInfo;
   Res: LongBool;
   Msg: tagMSG;
begin
   ResetMemory(Sei, SizeOf(Sei));
   Sei.cbSize := SizeOf(Sei);
   Sei.fMask := SEE_MASK_DOENVSUBST  or SEE_MASK_FLAG_NO_UI  or 
SEE_MASK_NOCLOSEPROCESS or
     SEE_MASK_FLAG_DDEWAIT;
   Sei.lpFile := PChar(FileName);
   Sei.lpParameters := PCharOrNil(Parameters);
   Sei.lpVerb := PCharOrNil(Verb);
   Sei.nShow := CmdShow;
   Sei.lpDirectory := PCharOrNil(Directory);
   {$TYPEDADDRESS ON}
   Result := ShellExecuteEx(@Sei);
   {$IFNDEF TYPEDADDRESS_ON}
   {$TYPEDADDRESS OFF}
   {$ENDIF ~TYPEDADDRESS_ON}
   if Result then
   begin
     WaitForInputIdle(Sei.hProcess, INFINITE);
     while WaitForSingleObject(Sei.hProcess, 10) = WAIT_TIMEOUT do
       repeat
         Msg.hwnd := 0;
         Res := PeekMessage(Msg, Sei.Wnd, 0, 0, PM_REMOVE);
         if Res then
         begin
           TranslateMessage(Msg);
           DispatchMessage(Msg);
         end;
       until not Res;
     CloseHandle(Sei.hProcess);
   end;
end;
 
 
Grazie.

 Il file .bat funziona perfettamente sia su PC prestanti che su PC lenti. 
 
Ancora: 
1) cosa vuol dire "lento"?
2) Perchè non fai un test con shellapi?
 
A.

Io proverei a verificare se quando esci dalla procedura batch il file è disponibile.
Prova ad aggiungere una riga di log alla fine del file, qualcosa tipo
 
DIR  >> filelog.txt
 
Almeno sei sicuro che all'uscita dalla procedura il file esiste o meno


Con questo suggerimento credo di aver individuato il problema:
 
Il file .bat viene chiamato per togliere la firma di una fattura 
elettronica.
 
Il file della fattura elettronica viene consegnato al software facendo 
il drag da Thunderbird ed il codice Delphi utilizzato è questo:
 
FileCount:= DragQueryFile (hDrop , $FFFFFFFF, nil, 0);
 
for I:= 0 to FileCount - 1 do begin
   NameLen:= DragQueryFile(hDrop, I, nil, 0) + 1;
   SetLength(S, NameLen);
   DragQueryFile(hDrop, I, Pointer(S), NameLen);
 
   ImportaXml(S, True);
end;
 
ImportaXml(S, True) è la procedura che chiama il file .bat.
 
Con il suggerimento di Alessandro ho scoperto che il file (S) alla 
chiamata del file .bat non è presente nel filesystem.
 
Come posso forzare/attendere la presenza del file "draggato" nel filesystem?
Ho messo un timeout di 50 secondi sul file .bat ma non risolve.
 
Grazie.

 Ho messo un timeout di 50 secondi sul file .bat ma non risolve. 
 
Potresti mettere un loop che attenda la presenza del file prima di procedere
Per evitare un loop infinito potresti verificare ogni N secondi se il file è presente per un massimo di M tentativi / secondi
(es. ogni 2 secondi per 100 tentativi, quindi 200 secondi massimo)
Ovviamente se il file "compare" prima esci subito dal loop


Se all'inizio del file .bat inserisco queste tre righe:
:INIZIO
if not exist %1 timeout /T 1 /nobreak
if not exist %1 GOTO INIZIO
 
non esce più :(
 
Se dall'interno del codice Delphi metto:
 
While Not FileExists(AFile) do
begin
   sleep(1000);
end;
 
Esce immediatamente perché il file AFile, che è il file del DragDrop da 
Thunderbird, risulta esistere (FileExists restituisce True) anche se 
nella cartella Temp non c'è :(
 
Grazie.

forse ho letto male, ma mi sembrava che il codice della chiamata
  ImportaXml(S, True);
non fosse codice script/batch
 
Non conosco la logica del tuo programma, ma se hai questo tipo di problema devi cercare dove puoi fare i test che ti servono.
Lato batch è un po' complesso (anche se credo si possa possa fare)
 
Forse è più semplice spezzare in due il batch, in uno estrai il file da Thunderbird (o quello che sarà l'origine), nel secondo lanci la rimozione della firma
In mezzo, con codice Delphi, puoi inserire i controlli che ti servono
 
Alessandro

 Forse è più semplice spezzare in due il batch, in uno estrai il file da Thunderbird 
 
Il file da Thunederbird non viene estratto dal file .bat ma da Delphi 
con il DragQueryFile poi il file estratto viene dato in pasto alla 
procedura ImportaXml(S) che se firmato tramite il file .bat rimuove la 
firma e lo elabora.
 
Il file .bat, infatti, si occupa solo di rimuovere la firma e di 
convertire il file se codificato in base64.
 
Grazie.
 
 

 
Questo mi pare strano...
Puoi provare con una alternativa per vedere se il file esiste, utilizzando TSearchRec
 


Appena provato ed è lo stesso :(
 
Se il PC è carico di lavoro FindFirst restituisce Zero ma il file nel 
filesystem non c'è :(
 
Grazie.

 filesystem non c'è :(
 
 
Invece di fare la findfirst, priva così: allì'intreno di una try ... 
except, fai come se dovessi aprire quel file come un file di testo in sola 
lettura, con una assign ed una reset.
Se riesce ad aprirlo, il file esiste (lo chiudi subito), se non ci riesce, 
va nella "except".
 
Quello che ho scritto sopra, lo metti in un ciclo, da dove esce solo 
quando è riuscito ad aprire e richiudere il file
Ora puoi lanciare il tuo bat
 
Ciao, Mario
 
 


Fatto così:
for I:= 0 to FileCount - 1 do begin
     NameLen:= DragQueryFile(hDrop, I, nil, 0) + 1;
     SetLength(S, NameLen);
     DragQueryFile(hDrop, I, Pointer(S), NameLen);
 
     try
       InFile := Trim(s);
       AssignFile(F, InFile);
       Reset(F);
       CloseFile(F);
 
       ImportaXml(S, True);
     except
       Showmessage('Apertura Fallita: Il File Non esiste');
     end;
       DragFinish(hDrop);
end;
 
Non risolve il problema sui PC lenti, il software si comporta 
esattamente come con il FileExists. :(
 
PC lento = PC con AMD Athlon di circa 11 anni fa che riproduce due video 
da RaiPlay mentre eseguo il test.
Lo stesso PC lento se scarico di lavoro non presenta il problema.
Ho anche indagato l'eventuale "intrusione" dell'antivirus Bitdefender 
disattivandolo ma non risolve il problema :(
 
Grazie.

Quel tuo codice è scritto piuttosto male. Parti dal presupposto che l'unico probolema possa essere che il file non esiste e nascondi i messaggi delle eccezioni.
L'informazione piu' importante di un software è l'errore. Quindi, comincia da qua:
 
mostri i messaggifa abbastanza
 
 
var
  allow: boolean;
 
 
.................
 
 
InFile := Trim(s); 
allow := true;
try 
  AssignFile(F, InFile); 
  try
    Reset(F); 
 
 
 except
  on E:Exception do begin
     allow := false;
   ShowMessage('ERROR ON READING FILE:' + Infile + ' ' + E.ClassName + ' ' + E.Message);
 end;
 
finally
  closefile(f);
end;
 
if (allow) then begin
 try
  ImportaXml(infile, True); 
 
  except 
     on E:Exception do begin
   ShowMessage('ERROR IMPORTING FILE:' + Infile + ' ' + E.ClassName + ' ' + E.Message);
 end;
 
......
 
 
A parte che per sapere cosa vuol dire "pc lento" ci sono voluti almeno 10 post....  credi che a forza di insistere con queste strategie alla fine risolverai?
Ti ho suggerito alcune alternative: le hai provate o no? Se no, PERCHE?
 
A.
 
 

Forse ho trovato il problema: Thunderbird.
 
Sembra che Thunderbird sia affetto da uno o più bug sul Drag&Drop sia in 
uscita che in ingresso :( Forse risolti.
 
Ma a causa di problemi con la gestione delle PEC questo Thunderbird, 
attualmente in versione 60.9.1 non verrà aggiornato e non potrò 
verificare se effettivamente il problema scomparirà.
 
Grazie.

 
 
Domanda scema: i "PC veloci" e quelli "lenti" hanno lo stesso file system? 
Magari il problema è lì !
 
Ciao, Mario
 

 Magari il problema è lì !
 
Lo avevo già testato e no, non dipende da questo :(
 
Normalmente hanno NTFS ma anche in presenza di FAT32 il problema si 
presenta in entrambi i casi :(
 
Grazie.