UserControl et gestion des erreurs [Résolu]

Signaler
Messages postés
18
Date d'inscription
mercredi 19 juillet 2006
Statut
Membre
Dernière intervention
10 avril 2008
-
Messages postés
18
Date d'inscription
mercredi 19 juillet 2006
Statut
Membre
Dernière intervention
10 avril 2008
-
Bonjour,

Je développe un controle activex en VB6 qui défini des fonctions publiques, et je l'utilise ces fonctions depuis le VBA dans le code des userform (ou depuis une form d'une application VB6) qui possèdent mon controle.

Mon problème, c'est que je n'arrive pas à trouver comment gérer proprement les erreurs qui peuvent arriver lors de l'exécutions des fonctions que je fournis dans mon control activex.

Par exemple, je fais un groupe de projet avec 2 projets. Dans le 1er projet, je définie un control UserControl qui défini la fonction publique suivante :

    Public Sub SetError()
        Dim I As Integer
        I = 1 / 0
    End Sub

Puis dans le second projet, je crée un programme avec une form. Je place un bouton et mon controle sur cette form, et dans le code de la form, je mets simplement :

    Private Sub Command1_Click()
        On Error Resume Next
        Call UserControl1.SetError
    End Sub

Et bien quand je lance mon programme (le point d'entrée est la form), l'erreur remontée par I = 1 / 0 n'est pas traitée par le "On Error" du niveau d'au dessus. En fait, j'ai le message de gestion d'erreur par défaut qui propose les 3 boutons Fin, Débogage et Aide à l'utilisateur. Ca n'est bien entendu pas du tout souhaitable !

J'aurais pu mettre  un Err.Raise explicitement à la place de ma division par zéro, c'est le même résultat.

Bref, comment puis-je générer une erreur dans mon UserControl de sorte qu'elle soit gérer par l'appelant avec les "On Error..." ?

Merci d'avance pour votre aide !

8 réponses

Messages postés
14008
Date d'inscription
samedi 29 décembre 2001
Statut
Modérateur
Dernière intervention
28 août 2015
74
Salut
"il ne sera pas possible d'interrompre l'exécution du code de la userform"
Si, puisque dans l'UC le "On Error Goto" a déjà interrompu l'exécution !
Quand cette UserForm reçoit l'évenement myErreur, il te suffit, par exemple, de passer un Booléen à True et de le surveiller dans le code de ta UserForm, exemple :
   Private bStop As Boolean   ' dans 'Déclaration' de ta UserForm
Dans la Sub 'event' myErreur de ta UserForm :
   bStop = True
Dans la Sub de ta UserForm qui appelle ton UC, si tu dois attendre, tu dois avoir une boucle. Dedans tu insères
  If bStop Then Exit Sub
en plus du DoEvents nécessaire au programme pour permettre la gestion des Events
Bien sûr, il faudra penser à remettre à False le bStop avant de relancer ton appel à l'UC

"je supose que le mécanisme de gestion d'erreur basé sur le "On Error" ne permet pas de remonter une erreur d'un UC à la userform qui l'utilise"
Si, les Events sont là pour ça, mais tu peux aussi passer (comme tu le disais avant) par une méthode (property) Get pour récupérer une chaine ou un numéro qui aura été mémorisé dans ton UC.

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

<hr />Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
Messages postés
14008
Date d'inscription
samedi 29 décembre 2001
Statut
Modérateur
Dernière intervention
28 août 2015
74
Salut
Première chose : Pour que ton UserControl (UC) renvoie des erreurs, il faut les intercepter.
Il faut donc utiliser des "On Error Goto monLabel" un peu partout.

Ensuite, pour que ton UC renvoie ce code d'erreur à ton application hôte, il faut utiliser les Event :
Dans la partie déclaration ton UC, ajoute ceci :
   Public Event myErreur(ByVal CodeErreur As Long, ByVal Description As String)
Quand tu placeras ton UC sur une feuille, tu verras qu'il affiche un évenement myErreur comme s'il s'agissait d'un Click du composant.
Suffira de mettre un MsgBox CodeErreur & ", " & Description (ou autre) dedans pour que l'hôte réagisse.

Et enfin, quand tu asa détecté une erreur avec le "On Error Goto", il te suffit d'écrire cette ligne pour que l'évenement se déclenche :
        RaiseEvent myErreur(Err.Number, Err.Description)

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

<hr />Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
Messages postés
18
Date d'inscription
mercredi 19 juillet 2006
Statut
Membre
Dernière intervention
10 avril 2008

Bonjour,

Tout d'abord, merci pour ta réponse.

J'avais déjà un peu penser à cette méthode basée sur des évènements. Elle est facile à mettre en place au niveau de l'appelé (dans le code du UC) mais je ne la trouve pas vraiment satisfaisante lors de l'utilisation au niveau de l'appelant (dans le code de la userform utilisant le UC). En effet, le "On Error Goto xxx" ne sera pas utilisable, et même si l'on pourra exécuter du code en cas d'erreur, il ne sera pas possible d'interrompre l'exécution du code de la userform à partir de l'appel de la fonction qui a provoqué l'erreur, comme le permet le "On Error Goto xxx".

J'avais aussi pensé à un autre moyen basée sur une variable Error membre de mon UC, et de fournir une méthode UC.GetError que l'on peut appeler à tout moment dans sa userform, en mettant des "if UC.GetError(E) then Err.Raise E", mais ça alourdi le code de la userform plus que ne l'aurait permis le "On Error Goto xxx"

Enfin, je supose que le mécanisme de gestion d'erreur basé sur le "On Error" ne permet pas de remonter une erreur d'un UC à la userform qui l'utilise, donc il va bien falloir que je me rabatte sur une méthode de contournement... 
Messages postés
18
Date d'inscription
mercredi 19 juillet 2006
Statut
Membre
Dernière intervention
10 avril 2008

Donc si je veux que le code de ma userform s'interrompe dès qu'il y a une erreur, je dois mettre la ligne "If bStop Then Exit Sub" après chaque ligne de code. En gros, j'altèrne : 1 ligne de code, 1 test d'erreur, 1 ligne de code... Ca ne rend pas le code bien lisible, tout ça ;-) Sans compter que c'est fistidieux...

Ca n'a en tout cas rien a voir avec le système de gestion d'erreur du type du "On Error", où il suffit que je mette un "On Error Goto xxx" au début d'un bloc de ligne de code, et après je mets mes lignes de codes sans me soucier de rien, et l'exécution sera quand même interrompue en cas d'erreur.

Voila, j'espère que tu vois mieux ce que j'ai voulu dire par "remonter une erreur d'un UC à la userform qui
l'utilise"
Messages postés
14008
Date d'inscription
samedi 29 décembre 2001
Statut
Modérateur
Dernière intervention
28 août 2015
74
Salut
Non, insérer une ligne sur deux n'a pas de sens.
Il suffit de tester bStop de temps en temps, quand ton code attend un résultat de ton UC.
Tu dois bien avoir une boucle de ce style quelque part dans ton code hôte :
   Do While maCondition = True
      DoEvents
   Loop
Et bien c'est dans cette boucle qu'il faut tester le bStop :
   Do While (maCondition = True) And (Not bStop)
      DoEvents
   Loop
   If bStop Then ...

Ca me parait difficile de mieux t'expliquer sans avoir le code sous les yeux et sans savoir ce que tu attends (et quand) de ton UC.
La gestion d'Event est très pratique et est faite pour justement déclencher des évènements côté hôte sur demande du UC.

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

<hr />Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
Messages postés
18
Date d'inscription
mercredi 19 juillet 2006
Statut
Membre
Dernière intervention
10 avril 2008

Merci encore pour ton aide. En fait non, je n'ai pas de boucle dans mon code. D'ailleurs, je n'utilise jamais l'instruction DoEvents. Moi, je crée les fenêtres de mes applications, et je mets mon code derrière les boutons ou autres évènements de ces fenêtres. Ces lignes de code s'exécutent séquentiellement, d'où la nécessité d'insérer des tests "bStop" un peu partout. C'est pourquoi la gestion du type "On error" me convient assez bien, parce que sans rien avoir à faire, je sais que j'irais à l'étiquette spécifié dès qu'il y aura une erreur.

Je n'ai pas vraiment de code à te montrer, puisque moi je développe l'UC. Ceux qui utiliseront cet UC sont d'autres développeur, une fois que je leur aurais fourni. Mais je dois aussi fournir une documentation qui indique comment ils doivent l'utiliser, et entre autre comment ils doivent gérer les erreurs. Mais logiquement, on pourrait trouver quelque chose comme ça derrière le code d'un bouton de leurs fenêtres :

  Private Sub Command1_Click()
      < des lignes de codes >
      Call UC1.UneFonction(arguments...)
      < d'autres lignes de codes >
      Call UC1.AutreFonction(...)
      < encore d'autres lignes >
  End Sub

J'aurais donc voulu qu'ils puissent faire ça :

  Private Sub Command1_Click()
      On Error Goto Error

      < des lignes de codes >

      Call UC1.UneFonction(arguments...)

      < d'autres lignes de codes >

      Call UC1.AutreFonction(...)

      < encore d'autres lignes >
  Error:

      MsgBox "Un erreur est apparue"

  End Sub

Mais je peux effectivement leur demander de faire celà, si c'ests la seule solution, mais je trouve quand même ça nettement plus lourd :

  Private Sub UC1_Error(Number,Descriuption)
    bStop = True
    Err.Number = Number
    Err.Description = Description
  End Sub
  Private Sub Command1_Click()
      On Error Goto Error

      < des lignes de codes >

      Call UC1.UneFonction(arguments...)
      If bStop then goto Error

      < d'autres lignes de codes >

      Call UC1.AutreFonction(...)
      If bStop then goto Error

      < encore d'autres lignes >
      Exit Sub
  Error:
      MsgBox "Un erreur est apparue"

  End Sub

Sinon, j'utilise beaucoup les évènements dans les UC que je développe, donc j'en connais bien le foncitonnement, mais ça ne me semble pas réellement adapté pour une bonne gestion d'erreur...
Messages postés
14008
Date d'inscription
samedi 29 décembre 2001
Statut
Modérateur
Dernière intervention
28 août 2015
74
Re
Ok, je comprends mieux ton contexte.
Bah là c'est assez simple et pas besoin d'Event, en effet.
Dans ton UC, transforme tes fonctions en vraies fonctions, qui renvoie une valeur, un booléen par exemple (*).
La déclaration pourrait ressembler à ça :
   Public Function maFonction(arguments) As Booleen
Si ta fonction se déroule correctement, elle doit renvoyer True, sinon False : A la fin de maFonction, ajoute simplement un
   maFonction = True
Si ta fonction est détournée à cause d'une erreur, elle sortira avec un maFonction = False (valeur par défaut)
Ensuite, dans le code appelant, récupère et interprète ce résultat (au lieu du Call) :
   Dim bRet As Booleen
   bRet = maFonction(arguments)
   If Not bRet Then
      ' Il y a eu un problème avec la fonction
   End If
Oui, cela oblige a tester après chaque appel, mais on a guère le choix, mais c'est quand même moi complexe que le bStop

(*) On peut bien sûr renvoyer autre chose, un Long ou une String, suffit de savoir quoi en faire

PS : Attention à ne pas nommer tes fonctions ou event avec des mots clé du langage (comme Error) : ça peut engendrer des résultats bizarres et pas facile à débuguer !

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

<hr />Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
Messages postés
18
Date d'inscription
mercredi 19 juillet 2006
Statut
Membre
Dernière intervention
10 avril 2008

Merci pour toutes ses réponses.

Je vais quand même choisir la solution avec l'Event, qui est la moins lourde à gérer pour l'utilisateur de mes UC, car ça ne nécessite pas de tester systématiquement toutes les erreurs (ça serait illusoire de croire qu'il le ferait)

L'avantage de la méthode avec un Event, c'est qu'on peut y mettre un point d'arret, et donc savoir rapiudement où s'est produite l'erreur, sans avoir à tester le résultat de chaque appel.

Je suis quand même déçu que la gestion d'erreur à la mode "on error" ne fonctionne pas d'un UC vers la form qui l'utilise. C'est bien domage, ça aurait été tellement plus simple...

Merci encore !