Newsgroup: it.comp.lang.visual-basic
Titolo: Cluster size

Buongiorno,
come faccio a sapere il cluster size di un determinato disco ?
Ho scoperto che per i dischi > 2GB la funzione GetDiskFreeSpace non è 
affidabile e che la nuova GetDiskFreeSpaceEx non ha questa informazione.
Ho anche scoperto che esiste la possibilità di usare l'interrupt 21 ma ho 
trovato solo un esempio in C++, qualcuno potrebbe fare una DLL da questo 
esempio o dirmi quali metodi alternativi ci sono ?
Grazie mille
	Paolo

 affidabile e che la nuova GetDiskFreeSpaceEx non ha questa informazione.
Volevo solo avvisarti che la GetDiskFreeSpaceEx si può usare solo a partire
dal Windows 95 OSR2, perchè prima non era supportata.
Ti consiglio in ogni caso di fare una funzione che chiami prima la
GetDiskFreeSpaceEx  e in caso di errore chiami la
GetDiskFreeSpace per essere compatibile con tutti i sistemi operativi
In ogni caso per sapere quanto effettivamente occupa un file una volta
salvato su disco devi sapere il tipo di formattazione che è stata usata. Dai
un occhio qui:
http://support.microsoft.com/directory/article.asp?ID=KB;EN-US;q140365
Se vuoi un sistema empirico, puoi chiamare la funzione che restituisce
quanto spazio libero hai sul disco, poi salvi un file lungo zero, richiami
la funzione che ti restituisce lo spazio libero, e con una semplice
sottrazione sai quanto occupa (cioè l'equivalente di un cluster).
Ciao
*Roby*

Dalla documentazione in mio possesso (Win32.hlp preso da Delphi 4) pare 
che con l'avvento dei nuovi sistemi, la vecchia GetDiskFreeSpace sia 
inaffidabile sia per volumi > 2GB che per quelli inferiori !!
La soluzione che tu proponi non č attuabile in quanto altri processi 
potrebbero scrivere sul disco nello stesso momento e falsare 
l'informazione cercata...
Possibile che non abbiano previsto una tale funzione ??
Analizzare il tipo di formattazione potrebbe andare bene nella maggior 
parte dei casi, ma se qualcuno poi usa Partition Magic e cambia il 
cluster size, sono fregato !
Grazie
	Paolo
ps: scusa se ti č arrivata una mail, ma ho cannato pulsante per la 
risposta...

 risposta...
Nessun problema.
Ciao
*Roby*

>> BONK ! <<<<
....
NON SONO JAVA, SONO PAL !
J E' SVENUTA PER IL "TORNARE" TRANSITIVO
la stavo abituando cosi' bene...
manco "ritorni", ci eravamo assuefatti. "torni" !
UN PO' DI RIGUARDO ! E' CONVALESCENTE !
quoque tu robi,ola mia... :)
ciao, a.

 quoque tu robi,ola mia... :)
Pussa via, Osella del malaugurio! :-)
Ciao
*Roby*

Fat32, NTFS, DriveSpace e quant'altro non ne esci più.
Infatti e' un po' un mezzo casino.
Ho trovato questo articolo, corredato di codice di esempio (l' ho provato
con win2000: funziona):
http://www.codeguru.com/system/clustersize.shtml
hth, hal
p.s.
naturalmente, non e' vb ...

 
http://www.codeguru.com/system/clustersize.shtml
Fantastico! Devi chiamare il vecchio int 21 come si faceva 10 anni fa sotto
Dos.
Grazie comunque, ottima dritta. Anche se, come dicevi tu, con VB non di puň
fare.
Ciao
*Roby*

fare.
Invece ho scoperto che si puo' :-)
Sara' che leggere i post di Hyperion mi ha fortemente minato la sanita' mentale,
ma, dato che oggi sono a csa, ho provato a portare in vb il codice C++
dell' articolo.
E ... almeno con win2K funziona !
Sotto la firma il codice completo.
ciao, hal
p.s.
Se trovate errori o miglioramenti da fare non esistate a comunicarlo:
il codice viene postato free (senza garanzia di nulla: se vi perdete i dati
sono affari vostri ;-) solo se puo' essere utile a tutti per
imparare. Gli approfittatori _non_ sono graditi.
---------------------------------------------------
Aprire un nuovo progetto, senza form, con un bas e un cls.
Chiamare il cls come CClusterSize.cls.
--- Nel bas:
Option Explicit
Public Sub Main()
    Dim cs As CClusterSize
 
    Set cs = New CClusterSize
 
    If cs.SetDrive("C:\") Then
        MsgBox "The cluster size of the disk C: is " & _
                        CStr(cs.GetClusterSize()), _
                vbInformation
    End If
    Set cs = Nothing
End Sub
-- nel cls:
Option Explicit
' --------- costanti
Private Const FILE_FLAG_DELETE_ON_CLOSE = &H4000000
Private Const VER_PLATFORM_WIN32_WINDOWS = 1
Private Const VWIN32_DIOC_DOS_DRIVEINFO = 6
' --------- strutture
Private Type OSVERSIONINFO
    dwOSVersionInfoSize As Long
    dwMajorVersion As Long
    dwMinorVersion As Long
    dwBuildNumber As Long
    dwPlatformId As Long
    szCSDVersion As String * 128      '  Maintenance string for PSS usage
End Type
'// holds the register values before and after the call to get the cluster size
Private Type tagDIOC_REGISTERS
    reg_EBX As Long
    reg_EDX As Long
    reg_ECX As Long
    reg_EAX As Long
    reg_EDI As Long
    reg_ESI As Long
    reg_Flags As Long
End Type
'// the structure returned by VWIN32_DIOC_DOS_DRIVEINFO
Private Type tagExtGetDskFreSpcStruc
    ExtFree_Size As Long
    ExtFree_Level As Long
    ExtFree_SectorsPerCluster As Long
    ExtFree_BytesPerSector As Long
    ExtFree_AvailableClusters As Long
    ExtFree_TotalClusters As Long
    ExtFree_AvailablePhysSectors As Long
    ExtFree_TotalPhysSectors As Long
    ExtFree_AvailableAllocationUnits As Long
    ExtFree_TotalAllocationUnits As Long
    ExtFree_Rsvd(0 To 1) As Long
End Type
' --------- funzioni API Win32
Private Declare Function CloseHandle Lib "kernel32" ( _
                        ByVal hObject As Long _
                        ) As Long
Private Declare Sub memcpy Lib "kernel32" Alias "RtlMoveMemory" ( _
                        ByRef dst As Any, ByRef src As Any, ByVal size As Long)
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" ( _
                        ByVal lpFileName As String, _
                        ByVal dwDesiredAccess As Long, _
                        ByVal dwShareMode As Long, _
                        ByRef lpSecurityAttributes As Any, _
                        ByVal dwCreationDisposition As Long, _
                        ByVal dwFlagsAndAttributes As Long, _
                        ByVal hTemplateFile As Long) As Long
 
Private Declare Function DeviceIoControl Lib "kernel32" ( _
                        ByVal hDevice As Long, _
                        ByVal dwIoControlCode As Long, _
                        ByRef lpInBuffer As Any, _
                        ByVal nInBufferSize As Long, _
                        ByRef lpOutBuffer As Any, _
                        ByVal nOutBufferSize As Long, _
                        ByRef lpBytesReturned As Long, _
                        ByRef lpOverlapped As Any) As Long
Private Declare Function GetDiskFreeSpace Lib "kernel32" Alias "GetDiskFreeSpaceA" ( _
                        ByVal lpRootPathName As String, _
                        ByRef lpSectorsPerCluster As Long, _
                        ByRef lpBytesPerSector As Long, _
                        ByRef lpNumberOfFreeClusters As Long, _
                        ByRef lpTotalNumberOfClusters As Long _
                        ) As Long
Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" ( _
                        ByRef lpVersionInformation As OSVERSIONINFO _
                        ) As Long
' ---------- variabili interne
Private m_strDrive As String
' ============================================================================
Private Function LoWord(DWord As Long) As Integer
   If DWord And &H8000& Then ' &H8000& = &H00008000
      LoWord = DWord Or &HFFFF0000
   Else
      LoWord = DWord And &HFFFF&
   End If
End Function    '// LoWord
'/////////////////////////////////////////////////////////////////////////////
'// SetDrive
'// --------
'// Sets the current drive to strDrive.  strDrive should be in the form of
'// C:\ for the class to get the cluster size on drive C.  In order to get the
'// cluster size of the drive, you should either pass the drive to the constructor
'// or call this function before calling GetClusterSize().
'//
'// Returns: true if the string is a valid path format (does not check to see
'// if the drive is valid), otherwise false.
'/////////////////////////////////////////////////////////////////////////////
Public Function SetDrive(ByVal strDrive As String) As Boolean
    If (Len(strDrive) <> 3) Then Exit Function
    If (False = (Mid$(strDrive, 1, 1) Like "[A-Z]")) Then Exit Function
    If (Mid$(strDrive, 2, 1) <> ":") Then Exit Function
    If (Mid$(strDrive, 3, 1) <> "\") Then Exit Function
    m_strDrive = strDrive
    SetDrive = True
End Function    '// SetDrive
'/////////////////////////////////////////////////////////////////////////////
'// GetClusterSize
'// --------------
'// Determines the cluster size for the current drive, which is set either using
'// SetDrive or the second constructor.  It uses the DeviceIoControl to set and
'// poll the registers to execute Int 21h Function 7303h which is only valid
'// if the system is running OSR2 or greater.
'/////////////////////////////////////////////////////////////////////////////
Public Function GetClusterSize() As Long
    If (Len(m_strDrive) = 0) Then Exit Function
 
    Dim OSR2 As Boolean  '//Running OSR2 or not
    Dim os As OSVERSIONINFO
    Dim SectorsPerCluster As Long
    Dim BytesPerSector As Long
 
    '// determine the OS version
    os.dwOSVersionInfoSize = Len(os)
    GetVersionEx os
    If (os.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS) Then
        If (LoWord(os.dwBuildNumber) > 1000) Then    '// is it OSR2 or newer?
            OSR2 = True
        End If
    End If
 
    '//If it's not OSR2, this is easy
    If (Not OSR2) Then
        GetDiskFreeSpace m_strDrive, SectorsPerCluster, _
                        BytesPerSector, ByVal 0&, ByVal 0&
        GetClusterSize = SectorsPerCluster * BytesPerSector
        Exit Function
    End If
 
    '// otherwise, use the int 21h function
    Dim hDevice As Long
    Dim reg As tagDIOC_REGISTERS
    Dim spcstruc As tagExtGetDskFreSpcStruc
    Dim bResult As Long
    Dim cb As Long
    Dim sz(0 To 3) As Byte ', strAscii As String * 4
 
    'strAscii = StrConv(m_strDrive, vbFromUnicode) & vbNullChar
    'sz() = strAscii
    memcpy sz(0), ByVal m_strDrive, UBound(sz()) + 1
    spcstruc.ExtFree_Level = 0   '//Must initialize before using the structure
    hDevice = CreateFile("\\\\.\\vwin32", 0&, 0&, ByVal 0&, 0&, FILE_FLAG_DELETE_ON_CLOSE, 0&)
 
    '// initialize the registers to call the correct function
    reg.reg_EDI = VarPtr(spcstruc)
    reg.reg_ECX = Len(spcstruc)
    reg.reg_EDX = StrPtr(m_strDrive)
    reg.reg_EAX = &H7303
    reg.reg_Flags = &H1
    '// copies the structure into the registers, performs the function,
    '// and returns the new registers in the structure
    bResult = DeviceIoControl(hDevice, VWIN32_DIOC_DOS_DRIVEINFO, _
                            reg, Len(reg), reg, Len(reg), cb, ByVal 0&)
    CloseHandle hDevice
    '// check the error status
    If ((False = bResult) Or (reg.reg_Flags & &H1)) Then
        Exit Function
    End If
 
    GetClusterSize = spcstruc.ExtFree_SectorsPerCluster * spcstruc.ExtFree_BytesPerSector
 
End Function '// GetClusterSize

 Sara' che leggere i post di Hyperion mi ha fortemente minato la sanita'
mentale,
Si, sei un pazzo! L'ho capito di per certo quando ho visto che nome di file
hai passato alla CreateFile ;-)
Il  codice è notevole, anche se non sono ancora riuscito a capirlo tutto.
Però posso darti immediatamente una brutta notizia: sotto Win98, dice che il
mio disco C ha un cluster grande 0.
Improbabile e avvilente :-(
Se trovo il tempo, provo a vedere se ci capisco qualche cosa in più.
Ciao
*Roby*
P.S.
Breve indagine: ritorna -1 proprio la CreateFile. Il problema però al
momento non mi è chiaro.

Ok, grazie al codice C di Mark Russinovich (sysinternals), all' msdn
e ad un sito tedesco dove ho recuperato il prototipo di NtFsControlFile,
ho tradotto in vb la lettura della dimensione dei cluster su volume NTFS.
Il codice e' stato provato con Win2000 Pro sp2.
Chissa', se ne potrebbe fare un progettino per il SC ...
ciao, hal
-----------------------------------------------------------------------------------------------------------
Per semplicita' il codice e' tutto in un modulo .bas
e, una volta lanciato, mostra una messagebox
con il valore cercato.
-----------------------------------------------------------------------------------------------------------
Option Explicit
Private Const GENERIC_READ = &H80000000
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Const OPEN_EXISTING = 3
Private Const INVALID_HANDLE_VALUE = -1
'//
'// File System Control command for getting NTFS information
'//
Private Const FSCTL_GET_VOLUME_INFORMATION = &H90064
Private Type LARGE_INTEGER
    lowpart As Long
    highpart As Long
End Type
'//
'// Io Status block (see NTDDK.H)
'//
Private Enum NTSTATUS
    STATUS_SUCCESS = &H0&
    STATUS_BUFFER_OVERFLOW = &H80000005
    STATUS_INVALID_PARAMETER = &HC000000D
    STATUS_BUFFER_TOO_SMALL = &HC0000023
    STATUS_ALREADY_COMMITTED = &HC0000021
    STATUS_INVALID_DEVICE_REQUEST = &HC0000010
End Enum
Private Type IO_STATUS_BLOCK
    status As NTSTATUS
    Information As Long
End Type
'//
'// NTFS volume information
'//
Private Type NTFS_VOLUME_DATA_BUFFER
    SerialNumber As LARGE_INTEGER
    NumberOfSectors As LARGE_INTEGER
    TotalClusters As LARGE_INTEGER
    FreeClusters As LARGE_INTEGER
    Reserved As LARGE_INTEGER
    BytesPerSector As Long
    BytesPerCluster As Long
    BytesPerMFTRecord As Long
    ClustersPerMFTRecord As Long
    MFTLength As LARGE_INTEGER
    MFTStart As LARGE_INTEGER
    MFTMirrorStart As LARGE_INTEGER
    MFTZoneStart As LARGE_INTEGER
    MFTZoneEnd As LARGE_INTEGER
End Type
' --------- funzioni API Win32
Private Declare Function CloseHandle Lib "kernel32" ( _
                        ByVal hObject As Long _
                        ) As Long
Private Declare Sub memcpy Lib "kernel32" Alias "RtlMoveMemory" ( _
                        ByRef dst As Any, ByRef src As Any, ByVal size As Long)
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" ( _
                        ByVal lpFileName As String, _
                        ByVal dwDesiredAccess As Long, _
                        ByVal dwShareMode As Long, _
                        ByRef lpSecurityAttributes As Any, _
                        ByVal dwCreationDisposition As Long, _
                        ByVal dwFlagsAndAttributes As Long, _
                        ByVal hTemplateFile As Long _
                        ) As Long
 
' ------------ API di NT
Private Declare Function NtFsControlFile Lib "ntdll" ( _
                        ByVal FileHandle As Long, _
                        ByVal hEvent As Long, _
                        ByRef UserApcRoutine As Any, _
                        ByRef UserApcContext As Any, _
                        ByRef UserIoStatus As IO_STATUS_BLOCK, _
                        ByVal FsControlCode As Long, _
                        ByRef InputBuffer As Any, _
                        ByVal InputBufferLength As Long, _
                        ByRef OutputBuffer As Any, _
                        ByVal OutputBufferLength As Long _
                        ) As NTSTATUS
' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 
Private Function GetNTFSInfo(ByVal DriveLetter As String, _
                            ByRef VolumeInfo As NTFS_VOLUME_DATA_BUFFER _
                            ) As Boolean
    Dim volumeName As String: volumeName = "\\.\A:"
    Dim volumeHandle As Long
    Dim ioStatus As IO_STATUS_BLOCK
    Dim status As NTSTATUS
'    //
'    // open the volume
'    //
    Mid(volumeName, 5, 1) = DriveLetter
    volumeHandle = CreateFile(volumeName, GENERIC_READ, _
                    FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, _
                    ByVal 0&, ByVal 0&)
    If (volumeHandle = INVALID_HANDLE_VALUE) Then
        Exit Function
    End If
'    //
'    // Query the volume information
'    //
    status = NtFsControlFile(volumeHandle, ByVal 0&, ByVal 0&, ByVal 0&, ioStatus, _
                        FSCTL_GET_VOLUME_INFORMATION, _
                        ByVal 0&, 0, _
                        VolumeInfo, Len(VolumeInfo))
    GetNTFSInfo = (status = STATUS_SUCCESS)
'    //
'    // Close the volume
'    //
    CloseHandle volumeHandle
End Function '// GetNTFSInfo
Public Function GetNTFSClusterSize(ByVal a_DriveLetter As String) As Long
    Dim VolumeInfo As NTFS_VOLUME_DATA_BUFFER
    If (GetNTFSInfo(a_DriveLetter, VolumeInfo)) Then
        GetNTFSClusterSize = VolumeInfo.BytesPerCluster
    End If
End Function    '// GetNTFSClusterSize
Public Sub Main()
    Dim letter As String: letter = "C"
    MsgBox "The cluster size of the disk " & letter & ": is " & _
                        CStr(GetNTFSClusterSize(letter)), _
                vbInformation
End Sub

momento non mi č chiaro.
Ecco il punto !
Tu che hai win98 (mi par di capire), prova aggiustando il nome del file.
Ho dimenticato che era vb e non c :-(
Sicche' ho erroneamente raddoppiato le backslash :-(
Questa dovrebbe essere la riga giusta:
hDevice = CreateFile("\\.\vwin32", 0&, 0&, ByVal 0&, 0&, _
                        FILE_FLAG_DELETE_ON_CLOSE, 0&)
ciao, hal
(che deve decidersi ad installare il vmware per usare 
contemporaneamente sistemi operativi diversi sulla 
stessa macchina)

 stessa macchina)
Mah, io ho preferito comprare macchine diverse. Tanto ogni tanto un upgrade
è necessario e invece di buttare la vecchia, la tieni e la metti in rete.
Ciao
*Roby*