IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++/CLI Discussion :

System.AccessViolationException avec c_str


Sujet :

C++/CLI

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Par défaut System.AccessViolationException avec c_str
    Bonjour,

    J'essaie de coder une application pour utiliser une caméra GigE Basler Scout. Pour cela j'utilise visual studio 2008 et le SDK fourni par le fabriquant. L'application est basée sur les windows form en C++/CLI.

    J'ai un problème lorsque j'essaie de récupérer l'adresse IP de la caméra. Le SDK prévoit une méthode GetIPAddress pour cela. Celle-ci me retourne un objet de type Pylon::String_t.

    Ce type permet de faire appel à des fonctions utilisées par les std::string comme c_str. Dans le but d'afficher le résultat dans un label, je cherche à passer le résultat en System::String via :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    System::String ^sIP = gcnew System::String(pBgdi.GetIpAddress().c_str());
    La compilation se passe sans problème mais j'ai une erreur à l'exécution. Je me retrouve avec :

    Une exception non gérée du type 'System.AccessViolationException' s'est produite dans TestPylonNET.exe

    Informations supplémentaires*: Tentative de lecture ou d'écriture de mémoire protégée. Cela indique souvent qu'une autre mémoire est endommagée.
    alors que sIP prend bien la valeur voulue (adresse en XXX.XXX.XXX.XXX)

  2. #2
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 472
    Par défaut
    Vous êtes sûr que "pBgdi.GetIpAddress().c_str()" contient un caractère fin de chaîne correcte ?

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Par défaut
    Comment puis-je être sûr que le caractère en fin de chaine est correct ? Car si j'ai bien compris, le dernier caractère de chaine doit être '\0', mais je n'arrive pas à trouver comment l'obtenir.

  4. #4
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut std::string
    bonjour,
    quand tu dis les std::string,pour les chaines standat en c++ il y a 2 cas du au fourbi qui distingue Ansi(1 octet) et Unicode(widechar=2 octets).
    en utilisant le namespace std et avec la meme chaine on a :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #include <string>
    using namespace std;
    void main()
    {
    	//Ansi String
    	string szAnsiString;
    	szAnsiString = "c:\\Program Files\\Microsoft Visual Studio .Net";
     
    	//Wide Char String
    	wstring wszWCharString;
    	wszWCharString = L"c:\\Program Files\\Microsoft Visual Studio .Net";
    }
    Le "string^ c++/cli " lui c'est de l'unicode.
    Il faudrait caster en widecar peut etre avant de convertir en "string^" de c++/cli.
    bon code...

  5. #5
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 472
    Par défaut
    Moi, je préfère aller à la source.

    Dans le débuggeur de VS (menu Debug de VS), il y a des vues "memory".

    Sélectionnez en une et mettez l'adresse retournée par "pBgdi.GetIpAddress().c_str()". Vous verrez la zone mémoire contenant la chaîne, vous verrez comment elle est encodée et si le caractère de fin de chaîne est bien présent.

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Par défaut
    Les chaînes sont en ANSI. J'ai essayé le cast en wide char, mais je me retrouve avec la même erreur. En utilisant la vue memory pour le résultat de GetIPAddress().c_str(), j'obtiens :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    0x04C97F78  0d f0 ad ba 31 39 32 2e 31 36 38 2e 31 2e 35 00 0d f0 ad ba  .ð*º192.168.1.5..ð*º
    Il y a bien la valeur '00' dans la mémoire allouée à cette chaine, si je ne me trompe pas dans mon interprétation.

    Ce qui est relativement bizarre, c'est que lorsque j'utilise d'autres fonctions de la même classe, me retournant des objet de même type (Pylon::String_t), la conversion en System::String ^ fonctionne; comme par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String ^sVendor = gcnew System::String(pBgdi.GetVendorName().c_str());
    En me servant de la vue mémoire pour cette chaîne classique pBgdi.GetVendorName().c_str(), j'obtiens :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    0x05F10FF0  00 00 00 00 cd cd cd cd 42 61 73 6c 65 72 00 cd cd cd cd cd  ....ÍÍÍÍBasler.ÍÍÍÍÍ
    De plus, lorsque je passe en release, tout fonctionne... L'erreur obtenue en debug est une erreur première chance. Je n'arrive pas à trouver à quoi cela correspond et comment passer outre...

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Par défaut Work around via try{} .. catch {}
    J'ai fini par trouvé un moyen pour faire fonctionner le code en DEBUG. Tout simplement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    		try
    		{
    			sIP = gcnew System::String(pBgdi.GetIpAddress().c_str());
    		}
    		catch(Exception ^)
    		{
    		}

  8. #8
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 472
    Par défaut
    Le DEBUG montre que vous faites des bêtises mais vous lui clouez le bec.
    Ne vous étonnez pas si la machine se venge.

    Vous tripatouillez au mauvais endroit en mémoire, vérifiez votre code.

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Par défaut
    Je me doute bien que ce n'est pas la meilleure façon de gérer le problème. Mais je ne suis jamais arrivé à le résoudre.

    Il y a certainement une règle du C++/CLI qui m'échappe. Si vous pouviez m'indiquer laquelle, je vous en serai très reconnaissant.

  10. #10
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 472
    Par défaut
    AccessViolationException ne vient pas du code managé mais du code natif, qui ne change pas avec C++/CLI.

    Utilisez les techniques de débuggages standards, C++/CLI ne change pas la manière de faire.

    Activez l'arrêt de votre programme via la configuration du débuggeur de VS, lors du lancement de cette exception "AccessViolationException".

    "menu de VS" -> "Debug" -> "Exceptions" -> "Native ..." -> "cochez dans le ligne correspondant AccessViolationException et la colonne "throw".

    Le débuggeur vous montrera le code qui génère cette exception.

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Par défaut
    Dans mon Visual, les AccessViolation Exception sont dans les Win32 Exception. J'ai déjà effectué cette partie du Debug (mais ne suis pas aller beaucoup plus loin faute de connaissances dans le domaine ); Toujours est-il que l'exception est levée à chaque manipulation de chaine données réseau de la caméra ( à savoir : Adresse IP, Default Gateway, Masque sous réseau et adresse Mac). Le problème ne se présente pas avec d'autres données de même type (Pylon::String_t), lui-même dérivant de std::string.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    			try
    			{
    				sMacro = gcnew System::String(pBgdi.GetMacAddress().c_str());
    			}
    Le pointeur d'instructions lors de la levée d'instruction pointe sur l'accolade de fermeture. Les adresses donnée dans la fenêtre sortie sont les suivantes :

    Exception de première chance à 0x007ee138 dans Scout_MultiSpectrale_Beta_v0.01.exe*: 0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x43303329.
    Lorsque je vais voir ces deux adresses (0x007ee138 et 0x43303329), dans la vue mémoire, elles sont vides ( ce qui est peut être normal ...).

    Bref, je ne vois pas trop où chercher...

  12. #12
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 472
    Par défaut
    Avez-vous vérifié dans votre cas, que vous n'étiez pas dans la situation décrite par la troisième phrase de la section "Notes" de la documentation MSDN du constructeur d'une System::String ?

    http://msdn.microsoft.com/fr-fr/library/6y4za026.aspx

  13. #13
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    c_str retourne une chaîne terminée par 0, il n'y a pas le choix.

    Pour transformer des chaînes entre natif et managé, le plus simple je trouve est d'utiliser marshal_as :

    http://msdn.microsoft.com/en-us/library/bb384865.aspx

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #include <marshal_cppstd.h>
     
    using namespace msclr::interop;
     
     
    String^ sMacro = marshal_as<String^>( pBgdi.GetMacAddress() );
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  14. #14
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 472
    Par défaut
    Merci Loïc pour cette réponse concise.
    Mais je crois que justement, si la chaîne est foireuse, c'est le "c_str()" qui plantera.

    Avec le nouveau code, je pense que "marshal_as<String^>" plantera (et heureusement, si la chaîne est foireuse).

    Donc commencez par vérifier la qualité de la chaîne retournée par "pBgdi.GetMacAddress()". J'aurais jamais confiance dans une API qui donne une adresse MAC sous forme de chaîne de caractère, pour moi c'est un entier 48 bits, voir un tableau d'octet, mais pas une string.

  15. #15
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Par défaut
    Voilà ce que j'obtiens dans la vue mémoire à l'adresse où est écrite ma chaine adresse MAC :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    0x04D63078  0d f0 ad ba 30 30 33 30 35 33 30 43 36 35 43 35 00 f0 ad ba  .ð*º0030530C65C5.ð*º
    Si je ne me trompe pas dans la lecture, l'adresse MAC de ma caméra (0030530C65C5) est bien suivi de la valeur 00.

    Cependant tout les symptômes d'une chaîne mal codée que vous décrivez Bacelar sont présents (le marshal_as m'a retourné l'exception).

    Autre fait notable, lorsque je code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Pylon::String_t Mac = pBgdi.GetMacAddress();
    sMacro = gcnew System::String(Mac.c_str());
    Le tout passe mais une exception AccessViolation est levée à la sortie de la fonction.

  16. #16
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 472
    Par défaut
    Bingo.

    MSDN indique qu'il faut fournir un pointeur sur un tableau de caractères Unicode
    http://msdn.microsoft.com/en-us/library/6y4za026.aspx

    Or, votre dump mémoire montre une chaîne de caractère terminé par un simple '\0' (correcte pour une chaîne ASCII) et non le double caractère Unicode '\0\0'.

    Nous sommes en présence d'une chaîne ASCII et non du chaîne UNICODE.

    Il vous reste donc à choisir une solution qui permette de régler ce problème.
    - Utilisez une API type "GetMacAddress" en version Unicode
    - Convertir la chaîne ASCII en chaîne Unicode
    - Utilisez les constructeurs de string ASCII friendly comme http://msdn.microsoft.com/en-us/library/ezh7k8d5.aspx ou encore mieux http://msdn.microsoft.com/en-us/library/9d876whe.aspx
    - etc...

  17. #17
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Par défaut
    Merci pour cette réponse mais il y a encore des choses qui m'échappent. L'API ne fournissant pas de méthode retournant une chaine Unicode, j'ai choisit de faire appel à un constructeur prenant en compte l'encodage d'origine :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    System::Text::Encoding ^ascii = System::Text::Encoding::ASCII;
    size_t size = pBgdi.GetMacAddress().size();
    System::String ^Mac = gcnew System::String(pBgdi.GetMacAddress().c_str(), 0, size, ascii);
    label_MacAdress->Text = "Mac Address :  " + Mac;
    Seulement, à l'appel du constructeur de System::String comme décrit http://msdn.microsoft.com/en-us/library/9d876whe.aspx, j'obtiens toujours la même exception.

    Autre fait étrange, si je souhaite récupérer une autre donnée, comme le nom du vendeur de la caméra, j'obtiens en dump:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    0x060705A0  00 00 00 00 cd cd cd cd 42 61 73 6c 65 72 00 cd cd cd cd cd  ....ÍÍÍÍBasler.ÍÍÍÍÍ
    La chaine se termine donc encore par un '\0'. Mais il n'y a pas de problème si je code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sVendor = gcnew System::String(pBgdi.GetVendorName().c_str())
    Donc encore une fois :

  18. #18
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 472
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    size_t size = pBgdi.GetMacAddress().size();
    Size est égale à combien ?
    Oui, je n'est aucune confiance dans "GetMacAddress()".

    This constructor processes characters from value starting at startIndex and ending at (startIndex + length - 1).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    System::String ^Mac = gcnew System::String(pBgdi.GetMacAddress().c_str(), 0, size, ascii);
    Il vous manquerait pas un "size+1" à la place de "size" ?

    La chaine se termine donc encore par un '\0'.
    Vous ne plantez pas parce que vous avec qu'un '\0' mais parce qu'il n'y a pas de '\0\0' avant la fin de la page mémoire allouée au programme par l'OS.

  19. #19
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Par défaut
    Effectivement, j'avais oublié le size + 1. Mais cela n'a pas résolu l'exception. Après contact avec le constructeur de la caméra et développeur API, il s'avère que cette méthode retournant ne peux être utilisée que lorsque l'objet caméra n'a pas été instancié, point non précisé dans la doc fournit ou, tout du moins, que je n'ai pas vu( et ce n'est pas faute de l'avoir parcouru...). Une fois le device instancié, il convient d'utiliser :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    int64 Mac =pCamera->GevMACAddress();
    int64 IP = pCamera->GevCurrentIPAddress();
    Code retournant un entier, ce qui est bien plus pratique pour l'interprétation et affichage.

  20. #20
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 472
    Par défaut
    Oui, je n'estai aucune confiance dans "GetMacAddress()".
    Dur Dur l'orthographe tard le soir.



    Je l'avais bien dit que cette API ne sentait pas bon du tout.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problème avec l'exception System.AccessViolationException
    Par inter_amine dans le forum Windows Forms
    Réponses: 8
    Dernier message: 08/12/2008, 15h48
  2. [VC++] System TrayIcon avec QT
    Par yelbied dans le forum MFC
    Réponses: 4
    Dernier message: 29/11/2005, 10h46
  3. [Système]communiquer avec un processus externe sous windows
    Par tweety dans le forum Général Java
    Réponses: 4
    Dernier message: 14/11/2005, 17h17
  4. [systeme] - pb avec deux OS Win 98 et WIN XP
    Par rico_49 dans le forum Windows XP
    Réponses: 1
    Dernier message: 24/10/2005, 14h25
  5. Réponses: 13
    Dernier message: 20/06/2005, 14h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo