Ecriture de fichier structuré en vb.net 2008 [Résolu]

Signaler
Messages postés
577
Date d'inscription
vendredi 26 septembre 2008
Statut
Membre
Dernière intervention
20 novembre 2010
-
Messages postés
577
Date d'inscription
vendredi 26 septembre 2008
Statut
Membre
Dernière intervention
20 novembre 2010
-
bonjour


Voila, je suis newbie en vb.NET 2008, et j'ai un souci pour écrire des fichiers structurés en binaire. D'après ce que j'ai vu sur le forum, le moins compliqué  est d'utiliser les méthodes Marshal. J'ai donc voulu créer un fichier bitmap windows, mais ça ne donne pas les résultats espérés.


Voici le code ; pour l'alléger, j'ai tronqué le fichier à la structure bitmapFileHeader :



Option Strict On
Option Explicit
Imports System.Runtime.InteropServices



Public Class Form1



   Public Structure bitmapFileHeader
       <MarshalAs(UnmanagedType.ByValTstr, sizeconst:=2)> _
       Dim bftype As String            ' 2 bytes
       Dim bfsize As Integer           ' 4 bytes
       Dim bfReserved1 As Short    ' 2 bytes
       Dim bfReserved2 As Short    ' 2 bytes
       Dim bfOffBits As Integer       ' 4 bytes
    End Structure



    Private Sub Essai()
       Dim entete As New bitmapFileHeader
       Dim rep As String = My.Computer.FileSystem.CurrentDirectory & "\test.bmp"
       Dim f As New IO.FileStream(rep, IO.FileMode.Create)
       With entete
          .bftype = "BM"
          .bfsize = 10000
          .bfReserved1 = 0
          .bfReserved2 = 0
          .bfOffBits = 1078
       End With
       Try
          Dim Data(Marshal.SizeOf(entete)) As Byte
          Dim Handle As GCHandle = GCHandle.Alloc(Data, GCHandleType.Pinned)
          Dim Pointer As IntPtr = Handle.AddrOfPinnedObject()
          Marshal.StructureToPtr(entete, Pointer, False)
          Handle.Free()
          f.Write(Data, 0, Data.Length)
       Finally
          f.Close()
       End Try
    End Sub



End Class


Après exécution, je m'attendais à trouver ça dans mon fichier :



42 4D 10 27 00 00 00 00 00 00 36 04 00 00


Au lieu de ça, mon fichier, il est tout pourri :



42 00 00 00 10 27 00 00 00 00 00 00 36 04 00 00 00


Est-ce que quelqu'un peut m'éclairer, car pour le moment, je marche à l'ombre (Marshal.ombre )


Au passage, mes remerciements à picpic10, ebartsoft et us_30 sans lesquels je me serais déjà suicidé au gaz ou par tout autre moyen propice à abréger mes souffrances.


Amicalement
A voir également:

12 réponses

Messages postés
14799
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
6 juin 2021
155
Bonjour,

Je ne vois pas de problème de codage, c'est assez bien commenté.
Je garde ça au chaud en cas de besoin.

http://nhen0039.chez-alice.fr/index.php
Messages postés
14799
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
6 juin 2021
155
Bonjour,

Quelles sont les données que tu veux structurées, car tu ne le précise pas (ou alors, c'est le fichier bitmap, mais bon) ?

http://nhen0039.chez-alice.fr/index.php
Messages postés
577
Date d'inscription
vendredi 26 septembre 2008
Statut
Membre
Dernière intervention
20 novembre 2010
4
Bonjour NHenry et merci pour ta réponse

La donnée à structurer est entete, du type bmpFileHeader.
Je souhaite l'écrire dans un fichier, comme je l'aurais fait en VBA avec PUT numeroFichier, 0, entete.

Amicalement
Messages postés
14799
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
6 juin 2021
155
Bonjour,

Question idiote (sans doute), si j'ai bien compris, tu veux enregistrer un fichier Bitmap avec ton application ? Dans ce cas, il existe une méthode intégrée au framwork .NET TonImage.SaveToFile (ou un truc du genre).

Sinon, tu peux aussi forcer la taille des données dans ta structure (jamais testé pour écrire un fichier). Ou alors tu enregistre tous tes champs "à la main".

http://nhen0039.chez-alice.fr/index.php
Messages postés
577
Date d'inscription
vendredi 26 septembre 2008
Statut
Membre
Dernière intervention
20 novembre 2010
4
Non, ta question est pertinente. En fait je souhaite pouvoir maîtriser l'écriture et la lecture d'un fichier binaire à la main, rien qu'à partir des spécifications de l'éditeur.

Je voudrais par exemple être en mesure de faire en .net ce que j'ai fait sous Excel (voir mon 2e source), c'est à dire visualiser les structures d'un fichier GIF en partant de rien (si ce n'est des spécifications de Compuserve).

Apparemment, en .net c'est un peu plus compliqué qu'un PUT ou qu'un GET, mais si c'est possible, c'est le principal.

Bien entendu, j'utiliserai les méthodes intégrées au framework .NET chaque fois qu'elles répondront à mes besoins ; je n'ai quand même pas envie de réinventer ce qui existe déjà .

Amicalement  
Messages postés
14799
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
6 juin 2021
155
Bonjour,

C'est, à mon avis, ton String qui bloque tout (décalage à ce moment). Remplace son type par 2 byte ou un short.

Si ça ne marche pas, je reste à l'écoute.

http://nhen0039.chez-alice.fr/index.php
Messages postés
577
Date d'inscription
vendredi 26 septembre 2008
Statut
Membre
Dernière intervention
20 novembre 2010
4
Oui, Nicolas, tu dois avoir raison. Je vais faire comme tu dis, et je te dirai quoi.
Messages postés
577
Date d'inscription
vendredi 26 septembre 2008
Statut
Membre
Dernière intervention
20 novembre 2010
4
Bonjour Nicolas

J'ai fait pas mal de tests, et je te donnes le résultat :


<hr />


Tests "2 bytes et Short"



J'ai fait les tests que tu m'as suggérés :1) en remplaçant le string par deux bytes, c'est nickel.

2) en remplaçant le string par un entier, c'est ok également (tout au moins en début de structure : voir ci-dessous)

Je suppose qu'il y a un souci dans le code au niveau du MarshalAs, mais comme je suis béotien en la matière, je n'ai pas encore pu déterminer lequel.

<hr />
Alignement des variables

Il semble que Marshal.StructureToPtr récupère les variables de la structure et les aligne selon leur longueur (en octets) avant de les charger dans la table : les variables Short sont en effet "alignées Short" (traduction plus ou moins heureuse de Short-boundary alignment) et les variables Integer sont "alignées Integer". Je suppose que c'est le cas de toutes les autres types de données, mais je ne l'ai pas vérifié.

En effet, j'ai constaté que quelque soit la combinaison de variables de la structure, le flux de caractères du fichier de sortie était arrangé de façon que les variables Short du fichier soient toujours à l'offset 1, 3, ou 5... du fichier, et les variables Long à offset 1, 5, 9..., par l'insertion de caractères nuls de "padding" ou remplissage.Par exemple, si la structure testée commençait par une variable Byte et une Short, le fichier généré commençait par le Byte, suivi d'un zero-byte, suivi du Short.

De même, si la structure commençait par une variable Byte suivi d'une Long, le fichier commençait par le Byte, suivi de trois zero-bytes, suivis du Long.

Ca explique en partie la tête bizarre des 4 premiers caractères de mon fichier bmp.

Je vais donc chercher le paramétrage de Marshal qui supprime l'alignement des variables.

<hr />Null-byte en fin de fichier

Dans tous mes tests, j'ai constaté la présence inexplicable d'un zero-byte en fin de fichier. Cela pourrait être dû à  l'instruction Dim Data(Marshal.SizeOf(entete)) As Byte du code ; en effet, si la limite inférieure des indices de tableaux en .net est 0, cette instruction crée, à mon avis, un tableau trop grand d'un octet.

<hr />Bien entendu, je vais tâcher de régler ces différents problèmes, mais toute aide sera la bienvenue. Je suppose que des membres du forum ont déjà écrit un fichier formaté bmp, mdi, wav ou autre en .net à la main.

Amicalement
Messages postés
14799
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
6 juin 2021
155
Bonjour,

En effet, concernant le tableau, l'erreur est facile à faire, quand tu le dimensionnes, tu donne la borne supérieure, donc, la ligne devrait être :
Dim Data(Marshal.SizeOf(entete)-1) As Byte

Concernant l'alignement, je n'ai pas d'idées, autre que de ne mettre que des Short et de séparer les données à la main, mais cela enlèverait tout intérêt à cette technique :/ .

http://nhen0039.chez-alice.fr/index.php
Messages postés
577
Date d'inscription
vendredi 26 septembre 2008
Statut
Membre
Dernière intervention
20 novembre 2010
4
Bonjour Nicolas


Entièrement d'accord avec toi, soit la structure permet de conserver le format d'origine, soit on passe à une autre technique. Mais je suis sûr que ça doit le faire en vb.net ; suffit de trouver la bonne technique.

A bientôt
Messages postés
577
Date d'inscription
vendredi 26 septembre 2008
Statut
Membre
Dernière intervention
20 novembre 2010
4
Bonjour Nicolas et le forum

Les instructions FilePut / FileGet semblent donner les résultats recherchés et leur utilisation est assez semblable aux instructions Put / Get de vb, facilitant la migration d'applications écrites en vba.

Comme j'avais pris pour exemple la structure bitmapFileHeader, je vous soumets le programme de test d'écriture de fichier bitmap Windows afin que vous puissiez le critiquer, car je suis débutant en vb.net 2008 et je souhaite évidemment démarrer sur de bonnes bases.

Amicalement


<hr />






Public Class form1



    ' Ecriture d'une image noire 1024x100 pixels dans un fichier bitmap 256 couleurs
    ' dans le répertoire de l'application



    Shared Sub Main()
        Dim bfFileHeader As New bitmapFileHeader
        Dim bfInfoHeader As New bitmapInfoHeader
        Dim bfPalette As String
        Dim numFic As Integer = FreeFile()
        Dim hauteur As Integer = 100
        Dim largeur As Integer = 1024
        Dim trailer As Byte = CByte(IIf(largeur Mod 4 <> 0, 4 - largeur Mod 4, 0))
        Dim lgBmpData As Integer = hauteur * (largeur + trailer)
        Dim fichier As String = My.Computer.FileSystem.CurrentDirectory & "\test.bmp"
        Dim bfData As String
        Dim lgFic As Integer = 1078 + lgBmpData
        Try
            My.Computer.FileSystem.DeleteFile(fichier)
        Catch filenotfound As System.IO.FileNotFoundException
        End Try
        FileOpen(numFic, fichier, OpenMode.Binary, _
            OpenAccess.ReadWrite, OpenShare.Shared)



        With bfFileHeader
            .bftype = "BM"
            .bfsize = lgFic
            .bfReserved1 = 0
            .bfReserved2 = 0
            .bfOffBits = 1078
        End With



        With bfInfoHeader
            .biSize = Len(bfInfoHeader)
            .biWidth = largeur
            .biHeight = hauteur
            .biPlanes = 1
            .biBitCount = 8
            .biCompression = 0
            .bisizeimage = lgBmpData
            .biXPelsPerMeter = 0
            .biYPelsPerMeter = 0
            .biClrUsed = 0
            .biClrImportant = 0
        End With



        ' creation d'une palette 256 couleurs (monochrome N & B)
        bfPalette = StrDup(1020, Chr(0)) & StrDup(3, Chr(255)) & Chr(0)



        ' creation d'un raster data (fond noir)
        bfData = StrDup(lgBmpData, Chr(0))




' ecriture de la structure bitmapFileHeader (14 bytes)

        FilePut(numFic, bfFileHeader)      




' méthode alternative d'ecriture de la structure bitmapFileHeader

        ' FilePut(numFic, New bitmapFileHeader("BM", lgFic, 0, 0, 1078))




' ecriture de la structure bitmapInfoHeader (40 bytes)

        FilePut(numFic, bfInfoHeader)       



' ecriture de la palette et du bitmap data (Strings de longeurs variables)

        FilePut(numFic, bfPalette & bfData)



        FileClose(numFic)



    End Sub



    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Main()
    End Sub



    Public Structure bitmapFileHeader



        <VBFixedString(2)> Public bftype As String   ' Type de fichier
        Public bfsize As Integer                                ' Longueur du fichier
        Public bfReserved1 As Short                         ' Reserve
        Public bfReserved2 As Short                         ' Reserve
        Public bfOffBits As Integer                            ' Offset du bitmap data depuis le debut du fichier



        Public Sub New(ByVal new_bftype As String, ByVal new_bfsize As Integer, _
            ByVal new_bfReserved1 As Short, ByVal new_bfReserved2 As Short, ByVal new_bfOffbits As Integer)
            bftype = new_bftype
            bfsize = new_bfsize
            bfReserved1 = new_bfReserved1
            bfReserved2 = new_bfReserved2
            bfOffBits = new_bfOffbits
        End Sub



    End Structure



    Public Structure bitmapInfoHeader
        Public biSize As Integer                  ' Longueur de la structure de données bitmapInfoHeader
        Public biWidth As Integer                ' Largeur de l'image en pixels
        Public biHeight As Integer               ' Hauteur de l'image en pixels
        Public biPlanes As Short                ' Nombre de plans du target device
        Public biBitCount As Short              ' Nombre de bits par pixels = controle 'couleurs
        Public biCompression As Integer      ' Type de compression
        Public bisizeimage As Integer          ' Taille de l'image data
        Public biXPelsPerMeter As Integer   ' Pixels par metres du target device (horizontal)
        Public biYPelsPerMeter As Integer   ' Pixels par metres du target device (vertical)
        Public biClrUsed As Integer              ' Nombre de couleurs utilise dans le bitmap
        Public biClrImportant As Integer        ' Nombre de couleurs importantes



    End Structure

End Class





<hr />
Messages postés
577
Date d'inscription
vendredi 26 septembre 2008
Statut
Membre
Dernière intervention
20 novembre 2010
4
Bonjour Nicolas


Merci pour ton message !

En marge de cette discussion, si tu as des réserves ou suggestions sur mon choix de vb.net 2008, n'hésite pas à m'en faire part. Ca m'a paru assez logique comme choix puisque je codais principalement en vba. Mais comme ta fiche indique que tu maîtrises tous les langages de Visual Studio je suis preneur de tous tes conseils. Je maîtrise bien php et perl, assez proche du c.

Amicalement