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

Macros et VBA Excel Discussion :

Tester un ObjPtr ou un RtlMoveMemory


Sujet :

Macros et VBA Excel

  1. #1
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 281
    Points : 11 737
    Points
    11 737
    Par défaut Tester un ObjPtr ou un RtlMoveMemory
    Bonjour,

    Dans un développement Excel VBA, j'enregistre l'adresse mémoire d'un objet avec ObjPtr, pour retrouver plus tard une référence à l'objet avec RtlMoveMemory. Le problème est que dans certains cas, l'adresse enregistrée n'est plus valable au moment où j'essaie de l'utiliser. Du coup, la création d'objet fonctionne (ou en tout cas elle ne provoque pas d'erreur), mais quand j'invoque une méthode de cet objet, ça plante Excel.

    Je cherche donc un moyen de tester que le numéro de pointeur est toujours valable, ou que l'objet renvoyé est correct, du bon type, etc., pour abandonner la création d'objet et éviter le plantage.

    Je ne m'y connais pas trop en programmation système, donc toute piste sera la bienvenue !

    Les infos détaillées : je suis en Excel 2010 sur du Windows 7 SP1 64 bit. J'utilise le CustomUI, et l'objet que je référence est le ruban personnalisé (classe IRibbonUI).

    Voici les lignes pertinentes de mon code :
    Code VBA : 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
    ' déclarations
    Private iRuban As IRibbonUI
    Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes&)
    
    ' enregistrement de l'adresse mémoire de l'objet ribbon dans un name du fichier Excel
    Sub ruban_chg(ribbon As IRibbonUI) ' événement qui se produit au chargement du ruban
    Set iRuban = ribbon
    ThisWorkbook.Names(NOMRUBAN_REVLIST).RefersTo = ObjPtr(ribbon)
    End Sub
    
    ' récupération de l'objet ruban
    Function Ruban() As IRibbonUI
    Dim ribbonPointer As Long
    
    If iRuban Is Nothing Then
      ribbonPointer = Mid(ThisWorkbook.Names(NOMRUBAN_REVLIST).Value, 2) ' le premier caractère est un = généré par Excel
        If ribbonPointer <> 0 Then Call CopyMemory(iRuban, ribbonPointer, 4)
    Set Ruban = iRuban
    End Function
    
    ' ça plante ensuite quand je fais par exemple ça :
    Ruban.Invalidate

    En vous remerciant,
    Antoun
    Expert Essbase, BO, SQL

    La bible d'Essbase, 2ème édition

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Si j'en crois la doc .Net Interop, RefersTo est une String, donc si tu veux jouer à ce genre de trucs tu as intérêt à activer Option Strict, Option Explicit, et faire toutes les conversions toi-même.

    Ensuite, tu oublies la règle d'or de COM: Si tu copies le pointeur quelque part, tu dois faire manuellement un AddRef dessus (et un Release quand tu t'en débarrasses, même si ici ta technique de copie via CopyMemory devrait t'en dispenser).

    PS: De préférence, utilise ByRef et ByVal explicitement quand tu déclares une fonction.

    Edit: Tu devrais garder to CopyMemory bien au chaud dans une fonction, comme PtrObj.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 281
    Points : 11 737
    Points
    11 737
    Par défaut
    Merci pour ta réponse !

    En fait je suis en VBA et non en VB.NET, donc je n'ai pas de Option Strict, mais s'il s'agit juste de faire les conversions explicitement, je peux le faire.

    Quand tu dis que je dois faire un AddRef, qu'est-ce que c'est et comment je dois faire ?

    Je vais faire un crash test avec ta fonction PtrObj. Qu'est-ce que c'est exactement que cette question de référence légale et illégale ?
    Antoun
    Expert Essbase, BO, SQL

    La bible d'Essbase, 2ème édition

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par Antoun Voir le message
    Merci pour ta réponse !

    En fait je suis en VBA et non en VB.NET, donc je n'ai pas de Option Strict, mais s'il s'agit juste de faire les conversions explicitement, je peux le faire.
    OK.

    Quand tu dis que je dois faire un AddRef, qu'est-ce que c'est et comment je dois faire ?
    Tu utilises une interface COM (IRibbonUI) sans connaitre les principes de base de COM (qui utilise du comptage de référence)?
    D'un autre côté, j'ignore si en VBA on peut influer sur ce genre de compte; le gros problème, c'est que tu ne dois PAS laisser la valeur retournée par ObjPtr() devenir le seul pointeur vers l'objet, sans quoi il sera détruit sous tes pieds. Donc, tu devrais mémoriser ton objet dans une collection, au minimum (mais j'ignore quelles collections VBA propose).

    Je vais faire un crash test avec ta fonction PtrObj. Qu'est-ce que c'est exactement que cette question de référence légale et illégale ?
    Je n'ai pas les détails, mais je suppose que ça implique le comptage de références.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 281
    Points : 11 737
    Points
    11 737
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Tu utilises une interface COM (IRibbonUI) sans connaitre les principes de base de COM (qui utilise du comptage de référence)?
    Ciel, je suis découvert ! Je vais aggraver mon cas en disant même que je pensais ne rien faire de plus grave que d'utiliser une interface XML sans trop connaître le XML, mais pour le COM, ça a l'air vachement plus grave !
    Citation Envoyé par Médinoc Voir le message
    D'un autre côté, j'ignore si en VBA on peut influer sur ce genre de compte;
    La question a l'air assez controversée... J'ai trouvé ces deux liens : http://stackoverflow.com/questions/7.../addref-in-vb6 et http://www.mrexcel.com/forum/excel-q...eferences.html, mais je ne comprends rien aux discussions...
    Citation Envoyé par Médinoc Voir le message
    le gros problème, c'est que tu ne dois PAS laisser la valeur retournée par ObjPtr() devenir le seul pointeur vers l'objet, sans quoi il sera détruit sous tes pieds. Donc, tu devrais mémoriser ton objet dans une collection, au minimum (mais j'ignore quelles collections VBA propose).
    En fait, le problème se pose un peu différemment. C'est précisément quand mon objet IRibbonUI est détruit que j'utilise la référence et le CopyMemory pour tenter de le ressusciter. La plupart du temps, ça marche. Je pourrais accepter sans problème que de temps en temps, ça ne marche pas, et envoyer un message d'erreur du genre "merci d'enregistrer vos classeurs, puis fermer et rouvrir Excel", mais le hic est que quand ça ne marche pas, tout plante. Je voudrais juste pouvoir détecter si va marcher ou si ça va planter...
    Antoun
    Expert Essbase, BO, SQL

    La bible d'Essbase, 2ème édition

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par Antoun Voir le message
    En fait, le problème se pose un peu différemment. C'est précisément quand mon objet IRibbonUI est détruit que j'utilise la référence et le CopyMemory pour tenter de le ressusciter. La plupart du temps, ça marche. Je pourrais accepter sans problème que de temps en temps, ça ne marche pas, et envoyer un message d'erreur du genre "merci d'enregistrer vos classeurs, puis fermer et rouvrir Excel", mais le hic est que quand ça ne marche pas, tout plante. Je voudrais juste pouvoir détecter si va marcher ou si ça va planter...
    Alors ça par contre, aucune chance que ça marche.
    Si tu veux maintenir une référence, il saut soit pouvoir faire le AddRef toi-même, soit mémoriser les références dans, par exemple, un tableau associatif (une Map, ça doit bien exister quelque part dans VBA, non?)
    (Edit: oui, apparemment)

    Mais dans un comptage de références, plus encore qu'avec un GC, un truc qui tombe à zéro référence est mort immédiatement.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 281
    Points : 11 737
    Points
    11 737
    Par défaut
    La principale cause de perte de l'objet est quand je teste et que j'arrête le déroulement du code, ce qui détruit toutes les variables (c'est moins susceptible de se produire chez les utilisateurs, mais ça peut arriver aussi). Du coup, toute idée de faire d'autres références est vaine, puisqu'elles seront détruites avec...

    Néanmoins, le ruban physique continue à exister et à fonctionner normalement, simplement je ne peux plus y faire référence et donc plus appeler ses méthodes. Et, bizarrement, recréer un objet à partir de la référence fonctionne souvent...
    Antoun
    Expert Essbase, BO, SQL

    La bible d'Essbase, 2ème édition

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Ça ressemble bien plus à un hack qu'autre chose.
    Regarde plutôt s'il n'y a pas moyen de ré-obtenir le ruban en le demandant à sa source...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 281
    Points : 11 737
    Points
    11 737
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Ça ressemble bien plus à un hack qu'autre chose.
    Waouh, j'ai hacké Excel

    Citation Envoyé par Médinoc Voir le message
    Regarde plutôt s'il n'y a pas moyen de ré-obtenir le ruban en le demandant à sa source...
    Il y a moyen : en fermant le fichier Excel et en le rechargeant...

    Bon, si rien n'est possible, tant pis, je vais faire sans.

    Merci pour tes lumières !
    Antoun
    Expert Essbase, BO, SQL

    La bible d'Essbase, 2ème édition

  10. #10
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 361
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 361
    Points : 20 381
    Points
    20 381
    Par défaut
    Citation Envoyé par Antoun Voir le message
    Dans un développement Excel VBA, j'enregistre l'adresse mémoire d'un objet avec ObjPtr, pour retrouver plus tard une référence à l'objet avec RtlMoveMemory. Le problème est que dans certains cas, l'adresse enregistrée n'est plus valable au moment où j'essaie de l'utiliser. Du coup, la création d'objet fonctionne (ou en tout cas elle ne provoque pas d'erreur), mais quand j'invoque une méthode de cet objet, ça plante Excel.
    je ne comprends pas il suffit de faire set obj=new reference_object
    Il n'y a pas le mot clé new dans le code donné si ne me trompe..

  11. #11
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 281
    Points : 11 737
    Points
    11 737
    Par défaut
    à quelle partie du code penses-tu ?
    Antoun
    Expert Essbase, BO, SQL

    La bible d'Essbase, 2ème édition

  12. #12
    Invité
    Invité(e)
    Par défaut
    Hello,

    Enfaite, le problème qui se pose en VBA est qu'il est possible d'écraser toutes les variables au sein de l'environnement VBA.
    Ça peux arriver de multiple manière.
    Alors l'idée de stocker les référence dans une Collection est vaine.
    Le mot clé End remet toutes les variables à 0 par exemple.
    Egalement, en passant en MODE CREATION sur Excel, ça remet à jour toutes les variables à 0.
    Lorsque l'on crée un composant ActiveX => Idem. Toutes variables sont perdus.
    Cette liste est loin d'être exhaustive.

    L'object du Ruban est fourni par un Callback qui intervient lorsque l'on ouvre le classeur par la fonction de Rappel:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Sub OnLoad(ribbon As IRibbonUI)
    End Sub
    Etant donnée qu'il n'existe pas de fonction permettant de retrouver l'object du Ruban (Mauvaise conception) en cours d'execution, il faut stocker le Pointeur du Rubban "en Dur".
    En dur, ça signifie ici dans une cellule Excel par exemple puisque par programmation, le pointeur à l'object n'est plus fiable et sera à Nothing (voir les différentes raisons que j'ai cité au dessus). Cependant, le pointeur réel de l'object Rubban ne change pas en cours d'exécution. Donc, par un simple test:
    Si MonObject Est Rien, Faire
    MonPtr = Cellule Excel, Puis Converti MonPtr en MonObject Puis GetMonObject = MonObject
    Sinon, GetMonObject = MonObject

    C'est possible uniquement parce le pointeur du Ruban ne change pas tant que le classeur n'a pas été fermé, donc il faut écraser l'ancien Ptr stocké en dur à l'ouverture du classeur, puis le remplacer par le nouveau fourni par le Callback OnLoad.

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

Discussions similaires

  1. Peut on tester l'existence d'un fichier ?
    Par Alamassepointcom dans le forum Flash
    Réponses: 2
    Dernier message: 10/10/2002, 12h10
  2. tester si une date est valide
    Par Andry dans le forum Langage
    Réponses: 5
    Dernier message: 17/09/2002, 11h54
  3. [VB6] [Interface] Tester le Type de Controle
    Par SpaceFrog dans le forum VB 6 et antérieur
    Réponses: 9
    Dernier message: 16/09/2002, 09h51
  4. [ADO] Tester l'existence d'une table
    Par nd25 dans le forum VB 6 et antérieur
    Réponses: 11
    Dernier message: 05/09/2002, 13h55
  5. Tester connexion Internet active sous Windows
    Par Altau dans le forum Développement
    Réponses: 3
    Dernier message: 12/08/2002, 12h43

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