[.net2] représentation graphique des clusters d'un volume

Description

Pour faire simple, c'est une classe qui donne une représentation visuelle des clusters d'un volume.
Et mis à part que je me suis battu avec les fonctions graphiques :), il montre l'utilisation et la manipulation des espaces/accès mémoires non managés avec la classe marshal et GCHandle.
J'ai essayé de commenter en partie le code pour simplifier la compréhension de cette source.

Pour plus d'infos:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/deviceiocontrol.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/fsctl_get_volume_bitmap.asp

Utilisation de la classe: 2 lignes et vous obtenez ce qu'il y a en capture :)

Dim cDriveBmp as New DriveBitmap
If cDriveBmp.GetMapVolume("c:") then cDriveBmp.DrawMap(VotrePictureBox,CouleurClustersOccupés,CouleurClustersLibre)

Remarque: J'ai mis le code ci-dessous pour ceux qui ne travaille pas avec la version 2 du framework

Source / Exemple :


Imports System.Runtime.InteropServices

Public Class DriveBitmap

#Region "Variables"

    Private m_MapArray As Byte()
    Private m_StartingLcn As Int64
    Private m_BitmapSize As Decimal

#End Region

#Region "Api"

    Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Integer, ByVal dwShareMode As UInteger, ByVal lpSecurityAttributes As IntPtr, ByVal dwCreationDisposition As UInteger, ByVal dwFlagsAndAttributes As UInteger, ByVal hTemplateFile As IntPtr) As IntPtr
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As IntPtr) As Boolean
    Private Declare Auto Function DeviceIoControl Lib "kernel32" (ByVal hDevice As IntPtr, ByVal dwIoControlCode As UInt32, ByVal lpInBuffer As IntPtr, ByVal nInBufferSize As UInt32, ByVal lpOutBuffer As IntPtr, ByVal nOutBufferSize As UInt32, ByRef lpBytesReturned As UInt32, ByVal lpOverlapped As IntPtr) As Boolean

#End Region

#Region "Constantes"

    ''' <summary>Constante de CreateFile</summary>
    Const GENERIC_READ = &H80000000
    Const GENERIC_WRITE = &H40000000
    Const FILE_SHARE_READ = &H1
    Const FILE_SHARE_WRITE = &H2
    Const OPEN_EXISTING = 3

    ''' <summary>Constante de validité d'un handle</summary>
    Const INVALID_HANDLE_VALUE = -1

    ''' <summary>Utilisé pour récupérer les clusters occupés/libre d'un volume</summary>
    Const FSCTL_GET_VOLUME_BITMAP = &H9006F

#End Region

#Region "Méthodes"

    ''' <summary>Récupère la map des clusters du volume</summary>
    ''' <param name="drive">Lettre du lecteur. Exemple "c:"</param>
    ''' <returns>True si réussi; False en cas d'échec</returns>
    Function GetMapVolume(ByVal drive As String) As Boolean

        Dim bret As Boolean = False         'valeur de retour

        Try

            'Création d'un handle vers le lecteur
            Dim hwndDevice As IntPtr = CreateFile("\\.\" & drive, GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero)

            'Si handle est valide on fonce...
            If hwndDevice <> INVALID_HANDLE_VALUE Then

                Dim lAlloc As Int64 = 0
                Dim pAlloc As IntPtr = IntPtr.Zero

                Dim unmngedAlloc As GCHandle = GCHandle.Alloc(lAlloc, GCHandleType.Pinned)      'Accès à un espace mémoire non managée
                Dim pBuff As IntPtr = unmngedAlloc.AddrOfPinnedObject                           'Son adresse

                Dim uiSpace As UInt32 = 1024 * 1024 * 64                                        'Représente une taille sufisante pour récupérer les clusters
                Dim uiSize As UInt32 = 0

                pAlloc = Marshal.AllocHGlobal(Convert.ToInt32(uiSpace))                         'Alloue un espace mémoire
                Dim pDest As IntPtr = pAlloc                                                    'Son adresse

                'Appel de la fonction de récupération des clusters libres/occupés
                Dim bDevice As Boolean = DeviceIoControl(hwndDevice, FSCTL_GET_VOLUME_BITMAP, pBuff, Convert.ToUInt32(Marshal.SizeOf(lAlloc)), pDest, uiSpace, uiSize, IntPtr.Zero)

                'Si tout c'est bien passé on fonce...
                If bDevice Then

                    unmngedAlloc.Free()
                    CloseHandle(hwndDevice)             'Libère le handle du volume

                    'Valeur d'entrée du buffer
                    Dim lStartingLcn As Int64 = Convert.ToInt64(Marshal.PtrToStructure(pDest, GetType(Int64)))
                    pDest = CType(pDest.ToInt64 + 8, IntPtr)

                    'Taille du buffer recevant les clusters
                    Dim lBitmapSize As Decimal = Convert.ToDecimal(Marshal.PtrToStructure(pDest, GetType(Int64)))

                    'Taille en bytes
                    Dim iByteSize As Int32 = Convert.ToInt32(lBitmapSize / 8)
                    iByteSize += 1

                    Dim pBitmapBegin As IntPtr = CType(pDest.ToInt64 + 8, IntPtr)

                    'Créer notre tableau de clusters
                    Dim buffer As Byte() = New Byte(iByteSize) {}

                    'Copie des clusters dans notre tableau de clusters (buffer)
                    Marshal.Copy(pBitmapBegin, buffer, 0, iByteSize)

                    Marshal.FreeHGlobal(pAlloc)     'Libère l'espace mémoire alloué

                    'Informations sur la map du volume
                    m_StartingLcn = lStartingLcn
                    m_BitmapSize = lBitmapSize
                    m_MapArray = buffer

                    bret = True     'retourne vrai :)

                End If

            End If

        Catch ex As Exception
            'En cas d'erreur :(
            MessageBox.Show(ex.Message & ControlChars.CrLf & "Représentation annulé")
        End Try

        Return bret

    End Function

    ''' <summary>Dessine la représentation des clusters sur le volume</summary>
    ''' <param name="picture">Objet PictureBox recevant le graphique</param>
    ''' <param name="UsedClustersColor">Couleur des clusters occupés</param>
    ''' <param name="FreeClustersColor">Couleur des clusters non occupés</param>
    Sub DrawMap(ByRef picture As PictureBox, ByVal UsedClustersColor As Color, ByVal FreeClustersColor As Color)

        'Nouveau bitmap
        Dim BmpMap As Bitmap = New Bitmap(picture.Width, picture.Height, Imaging.PixelFormat.Format32bppArgb)
        Dim ObjPen As Pen = Nothing

        'Créer un Graphics est on y associe notre nouvel objet Bitmap
        Dim g As Graphics = Graphics.FromImage(BmpMap)

        g.Clear(Color.White)    'Efface son contenu

        Dim iUsedClusters As Integer
        Dim iFreeClusters As Integer

        'Détermine le nombre de clusters par pixel
        Dim iBytesPerPixel As Integer = m_MapArray.Length / picture.Width

        'Et c'est partis............. :)
        'On dessine dans notre bitmap
        For i As Integer = 0 To picture.ClientSize.Width - 1

            iUsedClusters = 0

            For j As Integer = i * iBytesPerPixel + 1 To (i + 1) * iBytesPerPixel

                '0 = vide
                '255 = cluster occupé

                Select Case m_MapArray(j)
                    Case 0
                    Case 255 : iUsedClusters += 8   'incrémente d'1 oct
                    Case Else
                        For curBit As Short = 0 To 7
                            If GetBit(m_MapArray(j), curBit) Then iUsedClusters += 1 'incrémentation 1bit
                        Next
                End Select

            Next

            'Calcul le nombre de clusters non occupés
            iFreeClusters = iBytesPerPixel * 8 - iUsedClusters

            'Définis la couleur qui sera dessiner
            ObjPen = New Pen(Color.FromArgb(MixColors(UsedClustersColor, FreeClustersColor, iUsedClusters / (iBytesPerPixel * 8))), 1)

            'Point déterminant la position de la ligne
            Dim P1 As New Point(i, 0)
            Dim P2 As New Point(i, picture.Height)

            'Dessine la ligne dans le bitmap
            g.DrawLine(ObjPen, P1, P2)

        Next

        picture.Image = BmpMap      'Et pour finir envois le bitmap final dans notre picturebox :D
        g.Dispose()                 'Libère

    End Sub

    Private Function GetBit(ByVal value As Byte, ByVal bit As Integer) As Boolean

        Return value And 2 ^ bit

    End Function

    ''' <summary>Mix de couleurs</summary>
    ''' <param name="color1">Couleur représentant les clusteurs occupés</param>
    ''' <param name="color2">Couleur représentant les clusteurs libres</param>
    ''' <param name="opacity">Une ligne vertical sur le graph représente une zone de clusters.
    ''' Plus cette zone est blanche est plus il y a de clusters libres que d'occupés</param>
    ''' <returns>La nouvelle couleur mixée</returns>
    Private Function MixColors(ByVal color1 As Color, ByVal color2 As Color, ByVal opacity As Decimal) As Integer

        'Sépare les couleurs de color1
        Dim Red1 As Byte = color1.R
        Dim Green1 As Byte = color1.G
        Dim Blue1 As Byte = color1.B

        'Sépare les couleurs de color2
        Dim Red2 As Byte = color2.R
        Dim Green2 As Byte = color2.G
        Dim Blue2 As Byte = color2.B

        'Mélange.... et voici la nouvelle couleur... :)
        Dim mixCol As Integer = Color.FromArgb((Red1 * opacity + Red2 * (1 - opacity)), (Green1 * opacity + Green2 * (1 - opacity)), (Blue1 * opacity + Blue2 * (1 - opacity))).ToArgb

        Return mixCol

    End Function

#End Region

End Class

Conclusion :


Bonne prog à tous :)

Surtout n'hésitez pas à noter ou mettre un commentaire, un conseil ou autre.
Merci

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.