Newsgroup: it.comp.lang.visual-basic
Titolo: VB6 Funzioni LOF e FileLen troppo limitate ?

Salutoni al tutto il NG, mi sono imbattuto in un problema di non poco conto 
e che mi ha lasciato costernato, ho creato una mia funzione per convertire 
la dimensione di un file (size) nelle relative unità di misura, ovvero KB, 
MB ,GB e TB, alla mia funzione io passo come parametro LOF(X) e la mia 
funzione si chiama ''CalcSize''.
Questa funzione prende il valore in byte ritornato da LOF è restituisce una 
stringa di questo tipo ''12,3 MB" e devo dire che sembrava tutto perfetto 
fino a quando non ho testato la funzione aprendo un file da 2,05 Giga, con 
mia sorpresa la funzione mi ha ritornato un valore di stringa nulla, ma il 
problema non era nella mia funzione ma in LOF, che a quanto pare ritorna un 
valore con segno meno, infatti la dimensione reale in byte è 2.210.605.565 
da proprietà in risorse del computer, indovinate invece che valore ritorna 
LOF di questo stesso file ? un valore con segno negativo, questo -
2084361731
 
che è sta roba ? LOF non dovrebbe ritornare la dimensione in byte, e cioè 
questa 2.210.605.565 ? Lo stesso problema l'ho riscontrato anche con 
FileLen("NomeFile")
Adesso che devo pensare di quel segno meno forse LOF e FileLen si fermano a 
LONG come dimensioni visualizzabili in byte e poi complementa a 2 con la 
comparsa del bit del segno ?
Spero che alla fine io non sia costretto a scomodare le API per leggere le 
dimensioni di un file, in quanto come principiante di VB6 con le funzioni di 
libreria mi trovo alquanto sperduto
Attendo Vostri preziosi ed illuminanti consigli :-)

 Attendo Vostri preziosi ed illuminanti consigli :-)
F1 ---> cerca "LOF" .
ciao, roby

 Attendo Vostri preziosi ed illuminanti consigli :-)
F1 ---> cerca "LOF" . Leggi bene!
ciao, roby

 libreria mi trovo alquanto sperduto
Le API sono l'unica cosa che non fa parte di VB6, ma che sono comuni a 
tutto il mondo windows, qualunque linguaggio tu sia abituato a 
utilizzare. Non è quindi un problema di essere "principianti di VB6".
-- 
Si è visto di meglio,
ma si è scopato di peggio,
qualche volta a pago
e non erano neanche sempre donne
[Paolo]

 ha scritto nel messaggio 
news:435cdccc$1...@x-privat.org...


Vedi Albe V problema è in LOF stesso questo ritorna comunque numeri long 
anche se assegnassi il risultato ad una variabile currency il segno non 
credo che sparirebbe, tuttavia modifico e ci provo subito. 

 che sparirebbe
Questo è evidente.
Ma se tu hai un long, e sai (correttamente) che è un canchero a 4 byte, 
non è che ci voglia Rambo a splittarlo in 4 sottostringhe Hex (Hex$ + 
String + Len + Mid$) da un byte ciascuna, e poi a ricomporlo (Val + 
CCur + moltiplicazione) in un Currency.
Lo so che non è roba frequente in VB6, ma siccome hai detto di essere 
"principiante di VB6", immaginavo tu avessi già utilizzato qualche 
altro ambiente, dove queste cose sono abbastanza frequenti.
Ciao
Alberto


Precisazione, avrei voluto evitare di dover postare il codice, ma forse così 
verrà meglio compreso il perchè sia necessario passare a questa funzione 
obbligatoriamente un numero intero senza segno, e nelle mie capacità di 
principiante autodidatta non ho per ora avuto idee migliori di questa.
Questa funzione pubblica si trova in Modulo1.bas:
Public Function CalcSize(ByVal FileSize As Currency)
Dim Counter As Integer
Dim Result As Currency
Dim PesoBinario(5) As Currency
Dim UnitaMisura(5) As String
PesoBinario(0) = 1                             'Byte
PesoBinario(1) = 1024                       'Kilobyte
PesoBinario(2) = 1048576                 'MegaByte
PesoBinario(3) = 1073741824           'GigaByte
PesoBinario(4) = 1099511628000#   'TeraByte
UnitaMisura(0) = ""
UnitaMisura(1) = "KB"
UnitaMisura(2) = "MB"
UnitaMisura(3) = "GB"
UnitaMisura(4) = "TB"
For Counter = 4 To 0 Step -1
Result = FileSize / PesoBinario(Counter) ' Divido il numero in byte fino a 
trovare il corretto range quando il risultato sara compreso tra 1 e 999
If Result >= 1 And Result <= 999 Then CalcSize = Format(Result, "###.#0") & 
" " & UnitaMisura(Counter): Exit For ' quindi esco dal ciclo
Next
End Function
Per chiamare la funzione dalla mia Form procedo così:
Dim StringaRitornata As String
StringaRitornata = CalcSize(FileLen("NomeFile"))
MsgBox StringaRitornata
Che Faccio a questo punto?
1) Evito LOF e FileLen ed utilizzo le API ? (spero di evitare questo a meno 
che non sia la soluzione che richieda meno codice.)
2) Modifico la funzione in modo che possa lavorare con segno ? (ma il 
problema è che non saprei comunque come farlo, no ho idee in merito.)
3) Converto questo numero con segno in un intero senza segno ? e se 
possibile come ? (Questa sarebbe la mia soluzione ottimale se richiede poco 
codice)
4) Se utilizzassi le API invece, otterrei un intero senza segno ? o sarei 
punto a capo ?
La soluzione alla domanda 3 per le mie capacità sembra la più fattibile ma 
come ?
Ivan.

 MsgBox StringaRitornata
Ma scusa, hai letto le mie risposte?
Se FileLen è un Long, puoi scancherare finchè vuoi, ma rimarrà 
negativo, e tutto il tuo giochetto (che si basa su divisioni decimali, 
non su ragionamenti Hex) fallisce.
Quindi:
Dim File_Len as Currency
File_Len = SIGNEDLONG_2_UNSIGNEDCURRENCY (Filelen("Nomefile")
StringaRitornata = CalcSize(File_Len)
A questo punto, devi solo scriverti una funzione che converta il Long 
segnato in un Currency non segnato.
Come farlo, te l'ho già scritto nell'altro post (basta sapere cos'è un 
byte e cos'è l'esadecimale, e giochicchiando con le funzioni che ho 
scritto ci metti cinque minuti).
Ciao
Alberto


Soluzione trovata studiandomi a fondo MSDN e senza scomodare le API:
Dim fs, f, sizefile
    Set fs = CreateObject("Scripting.FileSystemObject")
    Set f = fs.GetFile(PathFileName)
    sizefile = f.Size
Questo script è possibile utilizzarlo al posto di LOF e FileLen, ritorna il 
valore intero senza segno sempre espresso in byte anche quando si superano 
le dimensioni contenibili dal formato LONG che è proprio delle funzioni LOF 
e FileLen.
Consiglio a tutti di utilizzarlo al posto di LOF e FileLen per non incorrere 
in ciò che ho dovuto affrontare io evitando coversioni rompicapo !

Ivan scriveva il 25/10/2005 :

Peccato.
Con poche righe di codice avresti risolto usando LOF, ma soprattutto 
avresti imparato una cosa nuova (ossia le gestione dei byte dei tipi).
Se hai ancora voglia di riflettere sull'argomento, ti suggerisco di 
riprovarci, perchè se, come doveroso, ti sei informato su cos'è 
ScriptingRunTime, saprai che:
- Non è presente su tutti i pc
- Non è installabile, ove non presente, se non aggiornando Internet 
Explorer
- Viene bloccata dallo scriptblocking di molti antivirus
LOF e FileLen funzionano sempre.
Vedi tu.


 Consiglio a tutti di utilizzarlo al posto di LOF
Adoperando il FSO in VB farai "drizzare i capelli" a parecchi puristi
e ricordati che se vorrai distribuire l'applicazione avrai piu' di
un problema a seconda del SO e settaggi
(in pratica funzionera' senza problemi su 1 pc ogni 10 ad essere ottimisti)
--
Fosco

 ScriptingRunTime, saprai che:
Azzz .. sono arrivato in ritardo ma non avevo visto
questo post essendo off line  :-(
--
Fosco

(in pratica funzionera' senza problemi su 1 pc ogni 10 ad essere ottimisti)
Concordo, e dire che la soluzione è semplicissima:
Declare Function GetFileSizeEx Lib "kernel32" (ByVal hFile As Long, lpFileSize
As Currency) As Boolean
che ti da già un valore currecy e ti evita il problema con il long.
--
ciao
  Stefano

 che ti da già un valore currecy e ti evita il problema con il long.
Diciamo che l'OP preferiva (e io concordo) evitare le API.
Però dispiace quando vedi uno che aveva già scritto il 99% del codice, 
è ad un passo da completare tutto, e anzichè ascoltare i suggerimenti 
(di chi per certi problemi c'è già passato) inserisce una minchiata nel 
codice.
Comunque, se Ivan un giorno dovrà distribuire l'applicativo, e troverà 
qualche problema, si scornerà e capirà l'importanza di informarsi prima 
di aggiungere riferimenti. E, forse, sarà ancora più didattico...


di aggiungere riferimenti. E, forse, sarà ancora più didattico...
Infatti tra una conversione di tipo o una chiamata a un API e inserire il FSO
con tutti i suoi problemi credo che la scelta sia facile.
--
ciao
  Stefano

A Stefano:
Beh dai, non è troppo tardi, il discorso è questo, non è che io non abbia 
voluto fare la conversione del long per pigrizia, ma quel famoso 99% del 
codice non sono riuscito a comprenderlo. non ho mai dovuto fare 
un'operazione simile prima, io avevo tentato un'altra strada di tipo 
decimale ma le operazioni logiche in VB6 non me lo hanno permesso AND lavora 
anch'essa su un massimo di 32 bit dopodichè OVERFLOW, in ESA (come suggeriva 
Alberto) non sono riuscito a capire proprio nulla ecco perchè non ho messo 
in pratica il suo suggerimento, piu lo guardavo piu mi aumentava l'emicrania 
, inoltre non credevo che fosse giusta al 99% la strada da lui suggerita, si 
vede che provengo dal COMMODORE  64 e AMIGA come programmatore BASIC 
masticare certe conversioni è piu facile algli abitué della programmazione 
Assembler o C forse.
Grazie poi avvermi avvertito in merito agli scripting FSO, non credevo 
potessero crearmi problemi in distribuzione, pertanto faccio un piccolo 
passo indietro ed allora provo subito la funzione delle API da te 
suggeritami, e di cui sono scarso utilizzatore per il momento, sembra 
abbastanza semplice ed intuitiva, credo che basti passare il Path del file 
per avere un risultato in Currency quindi evitando sempre sto problema di 
LOF (Certo che in Microsoft avrebbero potuto far si che anche LOF ritornasse 
il valore in currency no ?) e anche la compatibilità tra versioni OS.
La provo subito e ti faccio sapere se riesco nella chiamata, dato che la 
dichiarazione me l'hai gentilmente offerta tu :-)
A presto !!!
Ivan
 

dichiarazione me l'hai gentilmente offerta tu :-)
Ti copio&incollo l'esempio di API-GUIDE prevedendo che ti possa servire:
Const GENERIC_READ = &H80000000
Const FILE_SHARE_READ = &H1
Const OPEN_EXISTING = 3
Const FILE_TYPE_CHAR = &H2
Const FILE_TYPE_DISK = &H1
Const FILE_TYPE_PIPE = &H3
Const FILE_TYPE_UNKNOWN = &H0
Private Declare Function GetFileType Lib "kernel32" (ByVal hFile As Long) As
Long
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal
lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long,
lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal
dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function GetFileSizeEx Lib "kernel32" (ByVal hFile As Long,
lpFileSize As Currency) As Boolean
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As
Long
Private Sub Form_Paint()
    'KPD-Team 2000
    'URL: 
http://www.allapi.net/
    'E-Mail: 
KPD...@allapi.net
    Dim hFile As Long, nSize As Currency, sSave As String
    'open the file
    hFile = CreateFile("c:\autoexec.bat", GENERIC_READ, FILE_SHARE_READ, ByVal
0&, OPEN_EXISTING, ByVal 0&, ByVal 0&)
    'get the filesize
    GetFileSizeEx hFile, nSize
    'retrieve the file type
    Select Case GetFileType(hFile)
        Case FILE_TYPE_UNKNOWN
            sSave = "The type of the specified file is unknown"
        Case FILE_TYPE_DISK
            sSave = "The specified file is a disk file"
        Case FILE_TYPE_CHAR
            sSave = "The specified file is a character file, typically an LPT
'device or a console"
        Case FILE_TYPE_PIPE
            sSave = "The specified file is either a named or anonymous pipe"
    End Select
    'close the file
    CloseHandle hFile
    MsgBox "File Type: " + sSave + vbCrLf + "Size:" + Str$(nSize * 10000) + "
bytes"
End Sub
--
ciao
  Stefano

Sempre per Stefano:
Ho provato, chiamata fallità, dapprima ho pensato che questa funzione 
restituisse la dimensione del file in base al suo percorso PATH, invece 
guardando meglio i parametri che mi chiede sono 2 ( ByVal hFile As Long, 
lpFileSize As Currency) non sarebbe bastato come avrei voluto io una 
funzione simile?
Cioè (PathFile As String) come parametro e una chiamata del genere come 
sintassi ?
Dim MyFileSize As Currency
MyFileSize = GetFileSize (PathName As String)
Per avere in MyFileSize la dimensione in byte già in currency ? 
evidentemente era troppo bello per essere vero !!!
Ecco perchè tendo a tenermi alla larga dalle API, non sono mai come me le 
aspetto, però voglio vincere stavolta, piuttosto che convertire EOF oppure 
usare gli Scripting FSO di cui non conoscevo le problematiche, ma per 
porterlo fare devo sapere oltre a come chiamare la funzione, anche quali 
parametri passare e come acquisire il risultato:
1) (byval hfile as long) cos'è ?
2) ( lpFileSize As Currency) cosè ?
3) I parametri che passo sono di un file chiuso o di uno aperto magari con 
OPEN ?
Io ho supposto e dimmi se sbaglio, che "LpFileSize As Currency" sia la 
variabile che contiene la dimensione del file ritornata da questa funzione, 
pertanto se avessi ragione io almeno in questo, allora non serve piu il Dim 
MyFileSize As Currency di cui sopra.
Per quanto riguarda invece (ByVal hFile As Long) l'unica cosa che mi è 
venuta logica pensare è che si tratti del numero di un file aperto con [Open 
"pippo.txt" For Input As 1]  ad esempio.
Ed allora ho proceduto cosi:
Open "pippo.txt" For Input As 1
Call GetFileSizeEx (1,LpFileSize As Currency)
MsgBox LpFileSize
Ebbene evidentemente non è così, perchè non ottengo errori RUNTIME ma la 
MessaggeBox produce valore ZERO.
Ora sono tutto occhi Stefano, potresti illuminarmi a riguardo ?
Ivan.

 sono riuscito a capire proprio nulla
Bastava dirlo.
Far finta di niente e proseguire non è produttivo, soprattutto se poi 
si va a finire su scelte rischiose.
Non c'è niente di male nel chiedere chiarimenti.
Ti scrivo a braccio una versione (da verificare) di quella funzione che 
ti dicevo:
Public Function SIGNEDLONG_2_UNSIGNEDCURRENCY(ByVal Valore_Long As 
Long) As Currency
    Dim Parte_Alta1 As Currency
    Dim Parte_Alta2 As Currency
    Dim Parte_Bassa1 As Currency
    Dim Parte_Bassa2 As Currency
    Dim Stringa_Completa As String
    Stringa_Completa = Hex$(Valore_Long)
    Stringa_Completa = String(8 - Len(Stringa_Completa), "0") & 
Stringa_Completa
    Parte_Alta1 = Val("&H" & Mid$(Stringa_Completa, 1, 2))
    Parte_Alta2 = Val("&H" & Mid$(Stringa_Completa, 3, 2))
    Parte_Bassa1 = Val("&H" & Mid$(Stringa_Completa, 5, 2))
    Parte_Bassa2 = Val("&H" & Mid$(Stringa_Completa, 7, 2))
    Parte_Alta1 = Parte_Alta1 * CCur(256)
    Parte_Alta1 = Parte_Alta1 + Parte_Alta2
    Parte_Bassa1 = Parte_Bassa1 * CCur(256)
    Parte_Bassa1 = Parte_Bassa1 + Parte_Bassa2
    SIGNEDLONG_2_UNSIGNEDCURRENCY = Parte_Alta1 * CCur(65536) + 
Parte_Bassa1
End Function


Ora sono tutto occhi Stefano, potresti illuminarmi a riguardo ?
Già fatto, e prima ancora che tu lo chiedessi.
Sarà che con l'età aumenta anche l'esperienza...
--
ciao
  Stefano

Ho testato la tua funzione, tutto perfetto funziona a meraviglia !!!
Grazie per averla realizzata per me, ne farò tesoro, guardandola a colpo 
d'occhio mi rendo conto che da solo non ci sarei mai arrivato, ne ho 
compreso a malappena il funzionamento, dovrei guardarla e studiarla per 
parecchio tempo per comprendere perfettamente come hai compiuto questo 
miracolo.

 passo indietro ed allora provo subito la funzione delle API
scarica API-GUIDE
http://www.mentalis.org/agnet/apiguide.shtml
http://www.mentalis.org/agnet/appdown.shtml
http://www.mentalis.org/index2.shtml
NON so' se i link sono ancora attivi ma comunque dalla home page c'arrivi
--
Fosco

Long) As Currency
La funzione va bene, ma passandogli un Long il formato massimo del file sarà di
soli (sic) 4.294.967.295 bytes, valore che con NTFS si può anche superare.
Invece il currency passato dall' API GetFileSizeEx arriva a:
922.337.203.685.477,5807 *10000 cioè
9.223.372.036.854.775.807, più di 9 milioni di Terabytes
un limite che ancora per qualche anno non si raggiungerà con gli hd.
--
ciao
  Stefano