none
[VB.NET] Access Violation Exception RRS feed

  • Question

  • Bonjour tou(te)s

    J'ai volontairement omis le contexte de l'erreur parce que je cherche depuis un bon moment à résoudre cette erreur.

    Il résulte que cette erreur ne concerne pas l'API , tout les postes que j'ai trouvé pour cette erreur parle tous d'API différentes, j'en conclu donc que cela a à voir avec Windows.

    Pour ce poste ce sera l'API GetSystemPowerStatus

    Sur ce même PC, j'ai fais un module de classe  en VB6 qui  fonctionne parfaitement 

    J'ai transcode ce code en VB2010 aussi sur un module de classe... l'erreur signalée est générée.

    J'ai supprimer la classe et travaillé directement sur le module de la forme.. toujours même erreur.

    Je ne sais plus à quel Saint me voué.. 

    Auriez-vous trouvés l'origine de ce problème ?

    Merci d'avance.

    Cordialement.

    Note : sur ce forum j'ai trouvé entre autre Ce lien

    jeudi 25 octobre 2012 12:55

Réponses

  • Mais voila le code que j'emploi.

    Module Module1
    
        Public Structure SYSTEM_POWER_STATUS
            Public ACLineStatus As Int32
            Public BatteryFlag As Int32
            Public BatteryLifePercent As Byte
            Public Reserved1 As Byte
            Public BatteryLifeTime As Int32
            Public BatteryFullLifeTime As Int32
        End Structure
    
    
        Public Declare Auto Function GetSystemPowerStatus Lib "kernel32" _
           (ByVal lpSystemPowerStatus As SYSTEM_POWER_STATUS) As Int32
    End Module

    Si l'on se réfère à la description de la structure SYSTEM_POWER_STATUS  :

    ACStatusLine est de type BYTE, ainsi que BatteryFlag,tu les déclares en Int32, ce qui a pour effet qu'au lieu d'avoir une taille de structure de 12 octets : 1+1+1+1+4+4, tu as une taille de 18 octets : 4+4+1+1+4+4.

    Comme de plus tu passes ce paramètre 'ByVal' (passage de la structure, donc 18 octets) au lieu de 'ByRef' (passage de l'adresse de la structure, donc 4 octets en 32 bits), cela génère l'erreur indiquée : Access Violation Exception (qui est un classique dans les appels des APIs) : tu écris dans des zones mémoire non autorisées.Rien qu'en changeant ce 'ByVal' par 'ByRef' tu ne devrais plus avoir d'erreur, mais les données récupérées dans la structure seront inexactes du fait d'un décalage entre la taille/alignement de ta structure, et celle que s'attend de recevoir l'API. En modifiant ACStatusLine et BatteryFlag en Byte,ce sera OK.

    NB : à fin de vérification de la taille des structure, tu peux utiliser :

    • Len en VB
    • SizeOf en C

    en sachant que en C tu a une directive de compilation '#Pragma Pack (n)' qui permet d'aligner les éléments d'une structure sur un multiple de n, afin d'optimiser les accès mémoire. Cela semble ici sans alignement : #Pragma Pack(1), donc sans conséquences entre VB et C


    Cordialement, Jacques

    • Marqué comme réponse LeForestier jeudi 25 octobre 2012 16:25
    jeudi 25 octobre 2012 15:44

Toutes les réponses

  • Bonjour,

    VB6 et VB .NET ne fonctionnent plus de la même manière. Surtout en Interopérabilité. Pouvez-vous nous fournir la déclaration d'appel de l'API, puis le code qui appel la déclaration de la fonction SVP ?

    En regle générale c'est qu'il y a eu soit un dépacement de capacité, soit un mauvais paramètre.

     

    Cordialement


    Merci de valider par "Proposer comme réponse" si celle-ci répond à votre demande !

    jeudi 25 octobre 2012 13:50
  • Bonjour LeForestier,

    Un petit bout de code n'aurait pas fait de mal :-)

    Celui-ci

    Public Class Form1
        Structure SYSTEM_POWER_STATUS
            Dim ACLineStatus As Byte
            Dim BatteryFlag As Byte
            Dim BatteryLifePercent As Byte
            Dim Reserved1 As Byte
            Dim BatteryLifeTime As Int32
            Dim BatteryFullLifeTime As Int32
        End Structure
    
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            Dim Result As Integer
            Dim PS As SYSTEM_POWER_STATUS
    
            Result = GetSystemPowerStatus(PS)
            If Result > 0 Then
                MessageBox.Show(PS.ACLineStatus & vbCrLf & _
                                PS.BatteryFlag & vbCrLf & _
                                PS.BatteryLifePercent & vbCrLf & _
                                PS.BatteryLifeTime)
            End If
        End Sub
    
        Private Declare Function GetSystemPowerStatus Lib "kernel32" Alias "GetSystemPowerStatus" _
                                 (ByRef lpSystemPowerStatus As SYSTEM_POWER_STATUS) As Int32
    
    End Class
    

    Fonctionne correctement chez moi.

    A savoir : lors d'un passage de code VB6 à VB.Net il y a quelques adaptation à effectuer sur les types des paramètres :

    VB6          VB.Net

    Integer    Int16

    Long        Integer ou Int32


    Cordialement, Jacques

    jeudi 25 octobre 2012 13:51
  • Bonjour et merci de vos réponses,

    Je n'ai pas mis de code parce que justement je pense que ça ne provient pas de l'emploi d'une API quelconque

    Mais voila le code que j'emploi.

    Module Module1
    
        Public Structure SYSTEM_POWER_STATUS
            Public ACLineStatus As Int32
            Public BatteryFlag As Int32
            Public BatteryLifePercent As Byte
            Public Reserved1 As Byte
            Public BatteryLifeTime As Int32
            Public BatteryFullLifeTime As Int32
        End Structure
    
    
        Public Declare Auto Function GetSystemPowerStatus Lib "kernel32" _
           (ByVal lpSystemPowerStatus As SYSTEM_POWER_STATUS) As Int32
    End Module


    Et dans la forme

    .

    Public Class Form1
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            'Si PC Portable renvoi les données batterie
            ' Dim TchekBatt = New LN_TcheckBatt
            ' Dim SiBatterie As Boolean = TchekBatt.Portable
            ' If SiBatterie Then
            ' TchekBatt.Enabled = True 'valide l'événement de données batterie
            '  TchekBatt.Interval = 1 'détermine le temps avant redéclenchement de l'événement
            ' EtatBat.Text = TchekBatt.EtatBatterie
            'End If
            Dim Batterie As New SYSTEM_POWER_STATUS
    
            GetSystemPowerStatus(Batterie)
            ' Dim Restant As Integer = Batterie.BatteryLifePercent
    
        End Sub
    End Class

    C'est la première fois que je met du code sur le forum et pas de possibilité de voir l’aperçu !! donc peut-être pas fort réaliste !!

    J'ai laissé les lignes quand je me sert de la classe.

    Mais ça ressemble furieusement à la démo de Jacques93 :D

    Comme dis dans ma question, je ne pense pas que ça provient de l'appel à l'API (j'aurais alors une autre erreur) mais à un  critère de Windows, config  qu'il faudrait trouver.

    Cdlt.

    Note : les ligne faisant appel à la classe sont précédées d'un apostrophe ce qui n'est pas réaliser dans la transcription sur le forum.


    jeudi 25 octobre 2012 14:13
  • Alors d'une part le paramètre de fonction doit être en ByRef et non ByVal.

    Ensuite d'après la doc http://msdn.microsoft.com/en-us/library/windows/desktop/aa373232(v=vs.85).aspx

    La structure est comme suit :

    <StructLayout(LayoutKind.Sequential)> _

    Public Structure SYSTEM_POWER_STATUS Public ACLineStatus As Byte Public BatteryFlag As Byte Public BatteryLifePercent As Byte Public Reserved1 As Byte Public BatteryLifeTime As Int32 Public BatteryFullLifeTime As Int32 End Structure

    Déclaration de la fonction :

    <DllImport("kernel32.dll")> _
    Function GetSystemPowerStatus(ByRef syspowerstats as SYSTEM_POWER_STATUS) As Boolean
    End Function

    Utilisation :

    Dim SysInfoPower as SYSTEM_POWER_STATUS = New SYSTEM_POWER_STATUS()
    GetSystemPowerStatus(SysInfoPower)
    'continuer l'affichage, etc...
     
    Cordialement

    Merci de valider par "Proposer comme réponse" si celle-ci répond à votre demande !

    • Proposé comme réponse Lyamine jeudi 25 octobre 2012 17:49
    • Non proposé comme réponse Lyamine vendredi 26 octobre 2012 06:19
    jeudi 25 octobre 2012 15:41
  • Mais voila le code que j'emploi.

    Module Module1
    
        Public Structure SYSTEM_POWER_STATUS
            Public ACLineStatus As Int32
            Public BatteryFlag As Int32
            Public BatteryLifePercent As Byte
            Public Reserved1 As Byte
            Public BatteryLifeTime As Int32
            Public BatteryFullLifeTime As Int32
        End Structure
    
    
        Public Declare Auto Function GetSystemPowerStatus Lib "kernel32" _
           (ByVal lpSystemPowerStatus As SYSTEM_POWER_STATUS) As Int32
    End Module

    Si l'on se réfère à la description de la structure SYSTEM_POWER_STATUS  :

    ACStatusLine est de type BYTE, ainsi que BatteryFlag,tu les déclares en Int32, ce qui a pour effet qu'au lieu d'avoir une taille de structure de 12 octets : 1+1+1+1+4+4, tu as une taille de 18 octets : 4+4+1+1+4+4.

    Comme de plus tu passes ce paramètre 'ByVal' (passage de la structure, donc 18 octets) au lieu de 'ByRef' (passage de l'adresse de la structure, donc 4 octets en 32 bits), cela génère l'erreur indiquée : Access Violation Exception (qui est un classique dans les appels des APIs) : tu écris dans des zones mémoire non autorisées.Rien qu'en changeant ce 'ByVal' par 'ByRef' tu ne devrais plus avoir d'erreur, mais les données récupérées dans la structure seront inexactes du fait d'un décalage entre la taille/alignement de ta structure, et celle que s'attend de recevoir l'API. En modifiant ACStatusLine et BatteryFlag en Byte,ce sera OK.

    NB : à fin de vérification de la taille des structure, tu peux utiliser :

    • Len en VB
    • SizeOf en C

    en sachant que en C tu a une directive de compilation '#Pragma Pack (n)' qui permet d'aligner les éléments d'une structure sur un multiple de n, afin d'optimiser les accès mémoire. Cela semble ici sans alignement : #Pragma Pack(1), donc sans conséquences entre VB et C


    Cordialement, Jacques

    • Marqué comme réponse LeForestier jeudi 25 octobre 2012 16:25
    jeudi 25 octobre 2012 15:44
  • Re,

    Ma structure est convenablement déclarée, c'est en voulant la simplifier pour la poster que je me suis trompé.

    (J'avais mis des Enum)

    J'ai mis  marquer comme réponse et mon poste n'est pas passer.

    Drôle de forum.

    Enfin soit,

    Merci à Jacque93.

    Le fait de modifier ByVal par ByRef à résolu le problème.

    Je pense que ce fil va servir à beaucoup d'autre.

    Encore merci à vous deux.

    Cordialement.


    jeudi 25 octobre 2012 16:30