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++ Discussion :

Pilotage lecteur bancaire via RAII


Sujet :

C++

  1. #1
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut Pilotage lecteur bancaire via RAII
    J'ai un lecteur de carte bancaire pour lequel on me fournit une DLL pour le piloter. J'aimerais en faire une classe RAII. Si un problème survient lors de la transaction, alors une exception est envoyée.

    Voici un exemple très simplifié du problème:

    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
    class CDistributorRAII
    {
    public:
    	CDistributorRAII() {}
    	~CDistributorRAII() { CloseSession(); Disconnect(); }
     
    	void Connect() { if (!distributor_connect()) throw CConnectionException(); }
    	void OpenSession() { if (!distributor_open_session()) throw CSessionException(); }
    	void ProcessTransaction(float fAmount) { if (!distributor_process_transaction()) throw CTransactionException(); }
    	bool CloseSession() { if (!distributor_close_session()) throw CSessionException(); }
    	bool Disconnect() { if (!distributor_disconnect()) throw CConnectionException(); }
    };
     
    try
    {
    	CDistributor distributor;
     
    	distributor.Connect();
    	distributor.OpenSession();
    	distributor.ProcessTransaction(49.90);
    }
    catch (CDistributorException &e)
    {
    	cerr << e.what() << endl;
    }
    Le destructeur ferme une session ainsi qu'une connexion (bien sûr si elles sont ouvertes, par soucis de visibilité, je ne l'ai pas intégré dans le code exemple). Ces fonctions peuvent renvoyer une erreur dans la DLL, j'aimerais donc pouvoir lancer une exception. Cependant, un destructeur ne doit jamais envoyer d'exception. D'où le problème.

    Pour résoudre ce problème, je suppose que je dois faire des classes RAII pour une connection et une session?

  2. #2
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Pourquoi ne pas faire une fonction membre publique qui appelle CloseSession() et Disconnect()?
    Autrement dit, sortir CloseSession() et Disconnect() du destructeur.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  3. #3
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Si jamais la solution précédente ne te vas pas, tu as toujours le choix de gérer les erreurs à l'intérieur de ton destructeur, sans rien faire remonter...
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  4. #4
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par r0d Voir le message
    Pourquoi ne pas faire une fonction membre publique qui appelle CloseSession() et Disconnect()?
    Autrement dit, sortir CloseSession() et Disconnect() du destructeur.
    Je ne veux pas appeler explicitement ces 2 fonctions, d'où l'idée de le mettre dans le destructeur. Ou s'ils sont appelés explicitement, alors bien sûr ne sera pas rappelé dans le destructeur.

    J'ai fait la solution de Lavock, après tout, même si la fermeture de session ou déconnexion échoue, la transaction a quand même réussi au final.

  5. #5
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par trunk
    J'ai fait la solution de Lavock, après tout, même si la fermeture de session ou déconnexion échoue, la transaction a quand même réussi au final.
    Je pense que c'est effectivement une bonne solution. Surtout que ce type de matériel est extrêment protégé. Je veux dire par là que tu n'as aucun risque de le laisser dans un état "dangereux". Tu utilise MDB pour la communication?
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  6. #6
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par r0d Voir le message
    Je pense que c'est effectivement une bonne solution. Surtout que ce type de matériel est extrêment protégé. Je veux dire par là que tu n'as aucun risque de le laisser dans un état "dangereux". Tu utilise MDB pour la communication?
    Qu'est-ce qu'un MDB?

  7. #7
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Trunks Voir le message
    Qu'est-ce qu'un MDB?
    Donc non, tu n'utilises pas
    MDB est un protocole de communication conçu pour les machines dites de "vending", mais en fait il s'utilise aussi souvent pour les machines "à carte" (distributeurs, etc.).
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  8. #8
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par r0d Voir le message
    Donc non, tu n'utilises pas
    MDB est un protocole de communication conçu pour les machines dites de "vending", mais en fait il s'utilise aussi souvent pour les machines "à carte" (distributeurs, etc.).
    Effectivement ... je n'utilises pas sur aucun de mes 2 lecteurs bancaires (systèmes différents, Wynid pour la France, Banksys-Xenteo pour la Belgique)

    Je communique juste avec une DLL en lui donnant des ordres via l'appel de fonctions.

  9. #9
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    J'ai dit traité l'erreur, pas l'ignorer >< !
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  10. #10
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Tu n'es pas RAII, là, mais purement RRIF.

    D'ailleurs, je trouve ça un peu bizarre. Pourquoi vouloir laisser l'utilisateur appeler Connect() et OpenSession() ?

    Et au final, ce qui intéresse l'utilisateur, c'est de savoir que la transaction s'est bien passée, non ? Soit le distributeur est capable de gérer plusieurs transactions sur la même connexion, et là, je comprends l'objet persistant, soit ce n'est pas le cas, et il ne devrait y avoir qu'une seule fonction visible de l'extérieur, ProcessTransaction(...), non ?

  11. #11
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par Lavock Voir le message
    J'ai dit traité l'erreur, pas l'ignorer >< !
    Je ne l'ignore pas, je ne lance juste pas remonter d'exception.

    Citation Envoyé par white_tentacle Voir le message
    Tu n'es pas RAII, là, mais purement RRIF.
    RRIF? Jamais vu ce terme, à quoi ça correspond?

    Edit: Sur d'autres posts, j'ai vu que ça voulait dire Resource Release Is Finalization. Quelle est la différence avec le RAII?

    Citation Envoyé par white_tentacle Voir le message
    D'ailleurs, je trouve ça un peu bizarre. Pourquoi vouloir laisser l'utilisateur appeler Connect() et OpenSession() ?

    Et au final, ce qui intéresse l'utilisateur, c'est de savoir que la transaction s'est bien passée, non ? Soit le distributeur est capable de gérer plusieurs transactions sur la même connexion, et là, je comprends l'objet persistant, soit ce n'est pas le cas, et il ne devrait y avoir qu'une seule fonction visible de l'extérieur, ProcessTransaction(...), non ?
    Il s'agit d'une borne tactile. L'utilisateur choisit sa place de cinéma et paie sa place via sa carte bancaire. Mais il faut bien programmer la borne. C'est moi qui fait appel à ces fonctions, ça reste transparent pour l'utilisateur.

  12. #12
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Trunks Voir le message
    RRIF? Jamais vu ce terme, à quoi ça correspond?

    Edit: Sur d'autres posts, j'ai vu que ça voulait dire Resource Release Is Finalization. Quelle est la différence avec le RAII?
    En gros tu ne gères que la libération de ta ressource (RRIF), pas son acquisition (RAII).

    Citation Envoyé par Trunks Voir le message
    Il s'agit d'une borne tactile. L'utilisateur choisit sa place de cinéma et paie sa place via sa carte bancaire. Mais il faut bien programmer la borne. C'est moi qui fait appel à ces fonctions, ça reste transparent pour l'utilisateur.
    En parlant d'utilisateur, je pense qu'il désignait l'utilisateur de ta classe c'est à dire une autre classe pas l'utilisateur final Si je suis bien notre tentacule, l'idée est d'ouvrir ta connexion à la construction de l'objet, de la fermer à sa destruction, dès lors la seule autre opération visible est la demande d'une transaction.

  13. #13
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    En gros tu ne gères que la libération de ta ressource (RRIF), pas son acquisition (RAII)..
    Donc pour qu'elle soir RAII, il faudrait mettre la connexion et l'ouverture de session dans le constructeur?

    Citation Envoyé par 3DArchi Voir le message
    En parlant d'utilisateur, je pense qu'il désignait l'utilisateur de ta classe c'est à dire une autre classe pas l'utilisateur final Si je suis bien notre tentacule, l'idée est d'ouvrir ta connexion à la construction de l'objet, de la fermer à sa destruction, dès lors la seule autre opération visible est la demande d'une transaction.
    En effet, j'aurais qu'une seule connexion (au lancement du programme de la borne tactile), et qu'une seule déconnexion (à l'arrêt du programme de la borne), ainsi qu'une initialisation que je n'ai pas mis dans mon exemple car pas pertinent.
    Cependant, il y aura une session par transaction (une session par carte bancaire).
    Ce qui donne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Connexion
        Initialisation
        Ouverture de session
            Transaction
        Fermeture de session
        Ouverture de session
            Transaction
        Fermeture de session
        ...
        Ouverture de session
            Transaction
        Fermeture de session
    Déconnexion
    Donc je ne peux pas mettre la session dans le destructeur (ainsi que dans le constructeur d'ailleurs).

  14. #14
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Un pattern Etat me semble bien correspondre avec comme états : non-initialisé, initialisé, connecté (transaction ?) et comme transitions :
    non-initialisé -> initialisé : à la construction
    initialisé -> connecté : au début d'une transaction
    connecté -> initialisé : à la fin de la transaction
    initialisé -> non-initialisé : à la destruction.
    La gestion des connexions/deconnexion/ouverture/fermeture de sessions se gérant dans les transitions.

  15. #15
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Un pattern Etat me semble bien correspondre avec comme états : non-initialisé, initialisé, connecté (transaction ?) et comme transitions :
    non-initialisé -> initialisé : à la construction
    initialisé -> connecté : au début d'une transaction
    connecté -> initialisé : à la fin de la transaction
    initialisé -> non-initialisé : à la destruction.
    La gestion des connexions/deconnexion/ouverture/fermeture de sessions se gérant dans les transitions.
    Je vais y jeter un oeil, merci

  16. #16
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Tu n'es pas RAII, là, mais purement RRIF.

    D'ailleurs, je trouve ça un peu bizarre. Pourquoi vouloir laisser l'utilisateur appeler Connect() et OpenSession() ?

    Et au final, ce qui intéresse l'utilisateur, c'est de savoir que la transaction s'est bien passée, non ? Soit le distributeur est capable de gérer plusieurs transactions sur la même connexion, et là, je comprends l'objet persistant, soit ce n'est pas le cas, et il ne devrait y avoir qu'une seule fonction visible de l'extérieur, ProcessTransaction(...), non ?
    Finallement, je fais comme tu m'as dit.

    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
    class BANKSYSXENTEORAII_API CBanksysXenteoRAII
    {
    public:
    	CBanksysXenteoRAII();
    	~CBanksysXenteoRAII();
     
    	bool ProcessTransaction(UINT iAmount);
     
    private:
    	void Connect();
    	void Initialize();
    	void OpenSession();
    	void CloseSession();
    	void Disconnect();
     
    	static void __stdcall EventCallbackFunction(HPAYTYPE hPayType);
     
    	HPAYTYPE m_hPayType;
     
    	bool m_bConnected;
    	bool m_bSessionOpened;
    	bool m_bInitialized;
    };
    L'utilisateur n'aura qu'à créer une instance de CBanksysXenteoRAII, puis faire les transaction souhaitées. Les sessions sont gérées à l'intérieur de ProcessTransaction().

  17. #17
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Mais alors, pourquoi une classe ? Au pire, un vielle objet purement statique si tu y tiens... m'enfin, le truc que tu nous décris, ça ma beaucoup plus l'air purement procédural...
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  18. #18
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par Lavock
    Mais alors, pourquoi une classe ? Au pire, un vielle objet purement statique si tu y tiens...
    Tu n'as jamais entendu parlé du concept de RAII, ni jamais utilisé ifstream ?

  19. #19
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Le rapport ???

    Puis RAII, c'est un concept fort pratique pour des algorithme qui en ont besoin... Pourquoi le mettre en place si l'objet n'as pas de persistance ?? D'ailleur, pourquoi mettre en place un objet ?
    C'est la définition même d'une fonction => un changement de bord ponctuelle.

    C'est bien beau de vouloir mettre du DP partout... m'enfin faut-il encore que se soit utile...

    Et oui, je sais ce que le RAII... Si effectivement, l'objet était persistant, fort utile : création de l'objet avec ouverture de connexion et de session, fermeture à la destruction. C'est pas comme si c'était d'une difficulté fondamental à mettre en place !

    Au pire, ce sont les objets de la fonction qui en ont besoin... Mais je vois vraiment pas l'interet là... on va dire que dans l'absolue de l'absolue, on peut faire :

    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
     
    class BANKSYSXENTEORAII_API CBanksysXenteoRAII
    {
    public:
    	static bool ProcessTransaction(UINT iAmount);
     
    private:
     
    	CBanksysXenteoRAII(); //throw execpt1 except2
    	~CBanksysXenteoRAII();
    	void Connect();
    	void Initialize();
    	void OpenSession();
    	void CloseSession();
    	void Disconnect();
     
    	static void __stdcall EventCallbackFunction(HPAYTYPE hPayType);
     
    	HPAYTYPE m_hPayType;
     
    	bool m_bConnected;
    	bool m_bSessionOpened;
    	bool m_bInitialized;
    };
     
    static bool BANKSYSXENTEORAII_API::ProcessTransaction(UINT iAmount) {
         BANKSYSXENTEORAII_API b();
         //traitement
    }
     
    BANKSYSXENTEORAII_API::BANKSYSXENTEORAII_API() {
        //connection, intialisation, et ouverture de session
        //throw si pb
    }
     
    BANKSYSXENTEORAII_API::~BANKSYSXENTEORAII_API() {
       //fermeture session, deco
    }
    Mais encore une fois, je trouve que c'est s'embêter pour pas grand chose, mis à part avoir mis un pattern dans son code...
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  20. #20
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    La connexion peut être persistante d'une transaction à l'autre, donc ça a du sens d'encapsuler ça dans un objet.

    La méthode processTransaction ne faisant qu'ouvrir la session et la fermer, tout en gardant la connexion.

    Pas vraiment besoin de RAII, cela dit.

Discussions similaires

  1. se connecter à un lecteur réseau via service windows
    Par Tiger44 dans le forum Général Dotnet
    Réponses: 2
    Dernier message: 27/01/2010, 19h41
  2. Accèder à un lecteur réseau via Apache 2
    Par ndsaerith dans le forum Apache
    Réponses: 4
    Dernier message: 04/11/2008, 13h39
  3. Intégrer un lecteur vidéo via XML ?
    Par Maomam dans le forum XML/XSL et SOAP
    Réponses: 1
    Dernier message: 24/04/2008, 12h14
  4. Pilotage d'Excel via la classe
    Par petit arbre dans le forum WinDev
    Réponses: 1
    Dernier message: 25/11/2006, 22h40
  5. Pilotage d'excel via Access
    Par Bombar dans le forum Access
    Réponses: 8
    Dernier message: 30/07/2006, 18h51

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