none
Marshal PtrtoStructure RRS feed

  • Question

  • Bonjour à tous,

    je nage un peu dans le code d'un collègue qui nous a quitté.Dans une méthode (que j'ai simplifié pour le post), il fais tout un tas de choses (que j'avoue ne pas bien comprendre) avec Marshal (qui est bien obscur pour moi). Bref, la méthode me renvoie une erreur type "Tentative de lecture ou d'écriture de mémoire protégée" à la ligne ou il appel la méthode Marshal.PtrToStructure.

    Voici la méthode en question :

     Public Function ReadFile(ByVal File As String) As Boolean
            Dim flag As Boolean = False
            Dim [structure] As New MyStruct()
            Dim myfile As FileStream = New FileStream(File, FileMode.Open, FileAccess.Read)
            While myfile.Position < myfile.Length
                Dim numArray As Byte() = New Byte(Marshal.SizeOf([structure]) - 1) {}
                Dim num As Integer = myfile.Read(numArray, 0, Marshal.SizeOf([structure]))
                If num < Marshal.SizeOf([structure]) Then
                    Exit While
                End If
                Dim gCHandle__1 As GCHandle = GCHandle.Alloc(numArray, GCHandleType.Pinned)
                Dim intPtr As IntPtr = gCHandle__1.AddrOfPinnedObject()
                [structure] = DirectCast(Marshal.PtrToStructure(intPtr, GetType(MyStruct)), MyStruct)
                gCHandle__1.Free()
                MsgBox("coucou")
            End While
            myfile.Close()
            Return flag
        End Function
        Friend Structure MyStruct
            Public one As Byte()
            Public Two As Byte()
        End Structure

    Ne connaissant pas du tout l'ami Marshal, quelqu'un a-t-il une idée pour régler le problème?

    Merci d'avance pour vos réponse !

    lundi 23 juillet 2012 14:04

Réponses

  • Il semble que le problème venais de la définition de la structure!

    en la déclarant comme ceci :

    <StructLayout(LayoutKind.Sequential)> _ Friend Structure MyStruct <MarshalAs(UnmanagedType.ByValArray)> _ Public One As Byte() <MarshalAs(UnmanagedType.ByValArray)> _ Public Two As Byte()

    End Structure

    cela semble fonctionner !

    Je refais des essais en début d'aprèm et vous tiens courant.




    • Marqué comme réponse bobertin mardi 24 juillet 2012 13:05
    • Modifié bobertin mardi 24 juillet 2012 13:06
    mardi 24 juillet 2012 10:56

Toutes les réponses

  • Bonjour,

    Votre collègue a bien fait de partir car il ne devait pas avoir les compétences nécessaires pour faire du .NET et il du chercher bêtement comment écrire une structure dans un fichier et faire un copier/coller du premier code trouvé sur internet. Son code met en oeuvre des fonctions qui manipule de la mémoire managée / non managée (qui en plus peut provoquer des fuites mémoire lors de la levée d'une exception dans ce code...).

    Voici une version beaucoup plus simple qui répond parfaitement à votre besoin (le but est de lire les octets dans un tableau et les mettre dans votre structure) :

     Public Function ReadFile(ByVal File As String) As Boolean
            Dim myStructsLues As List(Of MyStruct) = New List(Of MyStruct)
    
            Dim flag As Boolean = False
            Dim tab(2) As Byte
    
            Dim myfile As FileStream = New FileStream(File, FileMode.Open, FileAccess.Read)
            While myfile.Position < myfile.Length
    
                ' Lire dans le tableau de deux octets
                Dim num As Integer = myfile.Read(tab, 0, 2)
                If num < 2 Then
                    Exit While
                End If
    
                ' construire une instance de la classe
                Dim temp As MyStruct
                temp = New MyStruct()
                temp.one = tab(0)
                temp.Two = tab(1)
    
                ' Ajouter une instance dans la liste
                myStructsLues.AddRange(temp)
    
                MsgBox("coucou")
            End While
            myfile.Close()
    
            Return flag
        End Function
        Friend Class MyStruct
            Public one As Byte
            Public Two As Byte
        End Class

    C'est plus simple, ca utilise des fonctions 100% .NET.

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance
    Blog : http://gilles.tourreau.fr
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0

    lundi 23 juillet 2012 16:39
    Modérateur
  • Bonjour, d'abord merci pour votre réponse.

    Il est vrai que l'ex collègue nous a fais un truc un peu tirer par les cheveux, mais après pas mal de recherche, sa méthode semble très usités quand même.

    Votre méthode semble effectivement fonctionner mais notre ami Marshal est utilisé un peu partout dans l'appli. Je préférerais donc rester avec lui même s'il c'est un ami un peu pénible :!).

    Si j'ai bien compris, la mémoire est alloué manuellement. Cela fonctionne très bien lorsque l'objet pour lequel il faut allouer la mémoire contient des variables "simples". Cela ne fonctionne plus dés que l'objet contient un ou des tableaux.

    Concrétement, si j'utilise cette structure :

     Friend Structure MyStruct
            Public one As Byte
            Public Two As Byte
        End Structure

    cela fonctionne très bien, si j'utilise celle-ci :

     Friend Structure MyStruct
            Public one As Byte()
            Public Two As Byte()
     End Structure

    je rentre dans l'erreur.

    Ce que je trouve bizarre, c'est que la valeur de numarray (donc la taille de l'objet si j'ai bien compris) semble cohérente et que c'est cette valeur que j'alloue.

    Voili voilou, je ne sais plus trop de quel côté partir (list et lecture simple ou array et problème de taille de mémoire...)...

    Si d'autres suggestions vous vienne à l'esprit, je suis preneur !

    mardi 24 juillet 2012 10:24
  • Il semble que le problème venais de la définition de la structure!

    en la déclarant comme ceci :

    <StructLayout(LayoutKind.Sequential)> _ Friend Structure MyStruct <MarshalAs(UnmanagedType.ByValArray)> _ Public One As Byte() <MarshalAs(UnmanagedType.ByValArray)> _ Public Two As Byte()

    End Structure

    cela semble fonctionner !

    Je refais des essais en début d'aprèm et vous tiens courant.




    • Marqué comme réponse bobertin mardi 24 juillet 2012 13:05
    • Modifié bobertin mardi 24 juillet 2012 13:06
    mardi 24 juillet 2012 10:56