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

Langage Delphi Discussion :

EAccessViolation dans appli MDI


Sujet :

Langage Delphi

  1. #1
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Août 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 13
    Points : 10
    Points
    10
    Par défaut EAccessViolation dans appli MDI
    Salut,

    j'ai un pb qui commence à m'énerver... depuis plus d'un mois j'essaie de modifier mon appli en appli MDI (avant elle était en mode normal, avec des fiches modales). Je suis sous Delphi6 personnel.

    J'ai un Eaccessviolation dans le OnCreate de la fiche Child, à la première instruction qui utilise un objet graphique sur la fiche.

    J'ai ajouté une autre fiche Child avec deux ou 3 controles graphiques et celle là fonctionne bien...

    Par contre, toujours pas moyen de faire tourner la fiche qui pose problème, il y a presque une centaine d'objets graphiques sur des page control, le tout avec près de 5000 lignes de code et j'ai pas envie de tout ré-écrire...

    Une dée ?

    Merci.

  2. #2
    Membre éclairé Avatar de DOLPat®
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2003
    Messages
    426
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 426
    Points : 790
    Points
    790
    Par défaut
    Bonjour

    Je ne pense pas que ce soit la fiche en elle-même qui te pose problème.
    Tu dois accéder à quelque pars dans ton code à un objet pas encore créé ou à de la mémoire pas encore allouée.

    Tu dis "J'ai un Eaccessviolation dans le OnCreate de la fiche Child, à la première instruction". C'est quoi cette instruction ? Poste le bout de code en question.

  3. #3
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Août 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 13
    Points : 10
    Points
    10
    Par défaut
    Bonjour,


    Code de lancement de la fiche enfant (j'ai désactivé le traitement car je pensais que le pb venait de là) par le form1 qui est de type fsMDIForm :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    procedure TForm1.Ouvre_fichier_photometrie(fichier:string);
    begin
     
      with Tfm_photo.Create(Application) do
        begin
          //PHOTO_lire_tiff(fichier);
        end;
    end;
     
    procedure TForm1.ESTA9Execute(Sender: TObject);
    begin
        // dialogue ouverture fichier
      with form1.OpenDialog1 do
        begin
          CleanupInstance;
          Filter:='Fichier Tiff Tagged Image File Format (*.TIF)|*.TIF';
          InitialDir:=rep_photo;
     
          // si un fichier a été sélectionné
          if execute then Ouvre_fichier_photometrie(FileName);
     
        end;
     
    end;
    Code OnCreate de la fiche enfant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    procedure Tfm_photo.FormCreate(Sender: TObject);
    begin
      DoubleBuffered:=true;      // evite le scintillement du formulaire avec des affichages video dynamiques
     
      // ProgressBar dans la StatusBar
      ProgressBar1.Parent:=StatusBar1;//pour que le ProgressBar se place sur le StatuBar
      // le placement de la ProgressBar se fait maintenant par rapport au StatusBar
      ProgressBar1.SetBounds(0, 2, StatusBar1.Panels[0].Width, StatusBar1.Height-2);
      Progressbar1.Visible:=false;
     
      // creation des vecteurs "energie radiale"
      esta_rad:=TVector.Create(nil);   esta_rad_nbre:=TVector.Create(nil);    esta_rad_cumul:=TVector.Create(nil);
     
      // création des bitmaps
      bmp_ref:=TBitmap.Create;
     
      // créations et initialisations des variables de calcul de photométrie
      tiff_x:=0; tiff_y:=0;  fichier:='NONAME';
      PHOTO_cree_data;                                                              // remplit la zone de descrition de la manip de mesure
      mat_nrj:=TMatrix.Create(nil);         mat_nrj_sauve:=TMatrix.Create(nil);     // création de la matrice d'énergie et de sa sauvegarde
      mat_coupe_H:=TMatrix.Create(nil);     mat_coupe_V:=TMatrix.Create(nil);       // création des matrices de stockage des coupes faisceau
     
    end;
    Le debugger s'arrête à l'entérieur de PHOTO_cree_data :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    //  la première fois, il faut bien pré-formatter une entête vierge dans le champ de saisie opérateur
    procedure PHOTO_cree_data();
    begin
      fm_photo.Memo_proj.Lines.LoadFromFile(form1.fichier_photo);   // ouverture du fichier type de description de la manip
    end;
    Evidemment, si je shunte l'instruction LoadFromFile, l'erreur a lieu à la prochaine instruction qui référence un objet graphique sur la form, pas les objets non graphiques comme les TMatrix par exemple.

    Je rappelle qu'une autre fiche enfant fonctionne sans problèmes...

    Je sèche !

    @+

  4. #4
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 871
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 871
    Points : 11 361
    Points
    11 361
    Billets dans le blog
    6
    Par défaut
    ton pb viendrait-il de l'appel à la variable fm_photo à laquelle ne serait jamais affectée la référence à la fiche lors de sa création : with Tfm_photo.Create(Application) do ?

    Auquel cas, elle vaut nil d'où l'EAV...

  5. #5
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Août 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 13
    Points : 10
    Points
    10
    Par défaut
    Citation Envoyé par tourlourou Voir le message
    ton pb viendrait-il de l'appel à la variable fm_photo à laquelle ne serait jamais affectée la référence à la fiche lors de sa création : with Tfm_photo.Create(Application) do ?

    Auquel cas, elle vaut nil d'où l'EAV...
    Tu as raison, quand je mets un point d'arrêt avant la ligne qui coince, la variable fm_photo vaut nil

    J'ai donc essayé de déclarer une variable dans la procédure qui crée une instance de la fiche fille, mais ça ne change rien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    var fm_photo:Tfm_photo;
    ...
      fm_photo:=Tfm_photo.Create(application);
    ...
    et puis quand je fais une autre fiche toute bête avec trois fois rien dessus ça marche, en l'appelant comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure TForm1.MDI1Click(Sender: TObject);
    begin
      with Tfm_child.Create(application) do
        begin
          caption:=DateToStr(now)+' '+TimeToStr(now);
        end;
    end;
    J'ai donc déplacé la ligne qui pose problème directement dans le OnCreate (et donc au lieu d'être dans la procedure PHOTO_cree_data) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // créations et initialisations des variables de calcul de photométrie
      tiff_x:=0; tiff_y:=0;  fichier:='NONAME';
      //PHOTO_cree_data;                                                              // remplit la zone de descrition de la manip de mesure
      fm_photo.Memo_proj.Lines.LoadFromFile(form1.fichier_photo);   // ouverture du fichier type de description de la manip
     
      mat_nrj:=TMatrix.Create(nil);         mat_nrj_sauve:=TMatrix.Create(nil);     // création de la matrice d'énergie et de sa sauvegarde
      mat_coupe_H:=TMatrix.Create(nil);     mat_coupe_V:=TMatrix.Create(nil);       // création des matrices de stockage des coupes faisceau
    Mais ça plantait toujours. J'ai alors essayé de référencer le memo en laissant le compilateur trouver le propriétaire de l'objet (facile dans un OnCreate !) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Memo_proj.Lines.LoadFromFile(form1.fichier_photo);   // ouverture du fichier type de description de la manip
    Et là c'est passé... jusqu'au même Access Violation dans le OnShow !!!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    procedure Tfm_photo.FormShow(Sender: TObject);
    begin
      // affichage des onglets par défaut
      TS_Bitmap.Show;   TB_bitmap.Down:=true;
      TS_calibration.Show;   TB_source.Down:=true;
    end;
    Et pourtant, dans ce OnShow, les TS_xxxx (des TabSheet) ne sont pas référencés par fm_photo.TS_xxxx !
    Le pire c'est que si j'ouvre la fiche en mode modal (avec les fiches MDI et fille en mode fsNormal), tout fonctionne à merveille. En quoi les mécanismes d'instanciation d'une fiche diffèrent-ils entre les modes SDI et MDI ???

    Que peut avoir ma fiche fm_photo de si particulier pour qu'elle ne soit pas compatible avec une instanciation en tant que fsMDIChild ????

  6. #6
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Août 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 13
    Points : 10
    Points
    10
    Par défaut
    Bonjour à tous,

    je progresse... car maintenant j'arrive à faire planter de la même manière ma fiche de test toute simple, ce n'est donc pas un problème qui viendrait de ma fiche fm_photo.

    Tout se passe bien sur la fiche simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    unit essaiMDI;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, Menus, SDL_rchart, ComCtrls;
     
    type
      Tfm_child = class(TForm)
        MainMenu1: TMainMenu;
        Fichier1: TMenuItem;
        Quitter1: TMenuItem;
        PageControl1: TPageControl;
        TabSheet1: TTabSheet;
        TabSheet2: TTabSheet;
        TabSheet3: TTabSheet;
        RChart1: TRChart;
        procedure Quitter1Click(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
    var
      fm_child: Tfm_child;
     
    implementation
     
    {$R *.dfm}
     
    procedure Tfm_child.Quitter1Click(Sender: TObject);
    begin
      close;
    end;
     
    procedure Tfm_child.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      RChart1.ClearGraf;
      Action:=caFree;
    end;
     
    end.
    Mais si je change la ligne 41 en :
    fm_child.RChart1.ClearGraph;

    là j'ai un access violation...

    Donc celà voudrait dire que je ne peux pas utiliser des objets enfants de ma fiche en dehors des méthodes liées à cette fiche ? Je programme depuis 15 ans en Delphi, mais ayant commencé en turbo pascal 3.0, j'ai un peu de mal avec la programmation objet... et donc j'ai une foultitude de procedure du genre procedure truc(var machin:Tchose); qu'il faudrait toutes transformer en Tfm_photo.truc(var machin:Tchose); en virant toutes les références à fm_photo dedans ???

    @+

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    dans une une application à fiches modales, on a, pour chaque fiche, une variable globale (en rouge ci dessous) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    type
      TForm1 = class(TForm)
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
    
    var
      Form1: TForm1;
    Ce n'est pas le cas pour une appli en MDI !
    une seule variable globale n'est pas utilisable vue que chaque fiche peut être créée plusieurs fois !

    donc dans le code cité si tu peut ouvrir plusieurs Tfm_photo
    la variable fm_photo représente laquelle des fiches ?

    bref en MDI pas question d'utiliser la variable globale fm_photo !
    une solution simple est d'initialiser la fiche au moment de sa création :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    procedure TForm1.CreateFM_PHOTO(const aPhotoFile: string);
    var fm_photo:Tfm_photo; // << variable locale !
    begin
      fm_photo:=Tfm_photo.Create(application);
      if fileexists(aPhotoFile) then begin
        fm_photo.Memo_proj.Lines.LoadFromFile(aPhotoFile);
      end;
    
    end;

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    pour en revenir à ta dernière question

    et donc j'ai une foultitude de procedure du genre procedure truc(var machin:Tchose); qu'il faudrait toutes transformer en Tfm_photo.truc(var machin:Tchose); en virant toutes les références à fm_photo dedans ???
    oui, est c'est logique, puisque en MDI on peut avoir plusieurs fiches fm_photo, il faut bien indiquer quelque part sur laquelle on veut travailler.

    une autre solution (peut être moins lourd dans un premier temps) est de tranformer

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    procedure truc(var machin:Tchose);
    en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    procedure truc(fm_photo:Tfm_photo;var machin:Tchose);
    begin
      // et là on peut utiliser tranquillement la bonne fiche 
      // en utilisant la variable fm_photo
    end;

  9. #9
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Août 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 13
    Points : 10
    Points
    10
    Par défaut
    Merci pour ces explications, ça commence à rentrer doucement...

    Pour les dernières nouvelles du front : j'ai changé toutes les déclarations de procédures et fonctions et maintenant je sais à quoi sert la section Private dans les unités Delphi !

    Donc les fiches se lancent, je peux en ouvrir le nombre voulu, tout fonctionne à merveille... sauf que j'ai de nouveau un Access Violation.

    Cet AV a lieu à la seconde fermeture d'une des fiches MDI. J'ai tracé le code et je m'aperçois qu'à la première fermeture, des composants comme des TcomPort qui sont normalement dans d'autres fiches (modales) se voient notifier un 'op_remove'.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure TCustomComTerminal.Notification(AComponent: TComponent;
      Operation: TOperation);
    begin
      inherited Notification(AComponent, Operation);
      if (AComponent = FComPort) and (Operation = opRemove) then
        ComPort := nil;
    end;
    Dans le composant PiconeBarreTache aussi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    procedure TPiconeBarreTache.Notification(AComponent: TComponent; Operation: TOperation);
    begin
          inherited Notification(AComponent, Operation);
          if Operation = opRemove then
          begin
              if AComponent = FMenuPop   then MenuPop   := nil;
              if AComponent = FImageList then ImageList := nil;
          end;
    end;
    Je ne sais pas si ça plante à la seconde fermeture d'une autre fiche MDI, car il n'y a plus rien à remover ?

    Par contre, si je n'ai qu'une seule fenêtre MDI ouverte, je peux la fermer et la rouvrir sans soucis et ceci à l'infini.

    C'est grave Docteur ?

    Encore merci pour votre support.
    @+

  10. #10
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Août 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 13
    Points : 10
    Points
    10
    Par défaut
    Bonjour,

    qu'est-ce qu'on peut raconter comme conneries quand on est débutant... Oubliez les opRemove car elles ne sont pas effectuées puisque les procédures en déduisent qu'elles ne sont pas concernées (if AComponent= ...).

    Je me suis aperçu que ça plantait dans mes libérations d'objets créés dynamiquement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure Tfm_photo.FormDestroy(Sender: TObject);
    begin
      // libération des ressources
      esta_rad.Free;        esta_rad_nbre.free;     esta_rad_cumul.Free;
      bmp_ref.free;
      mat_nrj.free;         mat_nrj_sauve.Free;
      mat_coupe_H.Free;     mat_coupe_V.Free; 
    end;
    J'ai essayé de mettre les libératons dans la section OnClose juste avant le "Action:=caFree;" mais ça ne change rien.

    Par contre, si je ne libère rien, il n'y a plus de plantage... mais quand on a 17 Create, on doit bien retrouver 17 Free dans le source, non ? Sinon il va y avoir de la fuite mémoire (au fait, comment on fait pour traquer la fuite mémoire en Delphi 6 perso ?).

    Ou alors mes objets sont considérés comme ayant la fiche comme Owner et ils sont libérés par le caFree ?

    @+

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    si ça plante à la seconde fermeture :
    grande probabilité qu'il y ait une ressource qui soit libérée dès la première fermeture et qui tente de l'être aussi à la seconde.

    il faut proscrire les variables globales uniques pour les ressources utilisées par la fiche en MDI (sinon on a le même problème que ce que j'ai expliqué pour fm_photo)

  12. #12
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Août 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 13
    Points : 10
    Points
    10
    Par défaut
    Eureka

    j'ai mis toutes mes variables "globales" de la fiche en propriétés privées ou publiques selon leur utilisation.

    Du coup, je n'ai plus aucune erreur d'access violation.

    J'ai ramé pour comprendre et le boulot de réécriture a été assez considérable, mais ça en vaut la peine ! Quel plaisir de voir les menus se fusionner, les Toolbar se coller ensemble, la statusbar afficher les infos de la fiche fille active, etc...

    Bien sur, il me reste l'ensemble des autres fiches et unités à transformer selon le même modèle, mais je suis motivé par ce succès.

    Encore merci à tous pour votre support. La programmation n'est pas mon métier et je l'utilise pour développer des outils de laboratoire, donc je me suis toujours contenté de quelques notions de base (malgré une maitrise à un tout autre niveau de l'assembleur sur micro-contrôleurs).

    Ca a été aussi l'occasion de découvrir ce forum qui est une mine d'information que je vais m'empresser de lire en profondeur.

    @+

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

Discussions similaires

  1. Variables globales dans appli MDI
    Par sp2308 dans le forum Débuter
    Réponses: 4
    Dernier message: 26/06/2009, 22h05
  2. [D2007WIN32]MergeMenu dans appli MDI
    Par SLE dans le forum Composants VCL
    Réponses: 0
    Dernier message: 31/12/2007, 13h44
  3. Imprimer le document actif dans une appli MDI
    Par Kemanke dans le forum MFC
    Réponses: 2
    Dernier message: 15/05/2007, 12h03
  4. Réponses: 7
    Dernier message: 13/03/2006, 08h56
  5. enregistrer dans un fichier avec une appli mdi
    Par ferrari dans le forum C++Builder
    Réponses: 4
    Dernier message: 05/05/2002, 15h17

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