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

Delphi Discussion :

Objets Automation et Interface


Sujet :

Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut Objets Automation et Interface
    Salut tout le monde,

    je suis en train de faire des objets automation.

    Je désire pouvoir transtyper une Interface en sa CoClasse associée (je ne suis pas sûr qu'on l'appelle la CoClasse en fait), mais il me met ce message d'erreur :
    Types incompatibles : 'TUser' et 'IUser'
    Les interfaces ne possèdent aucun champs, je les ai donc mis dans la classe associée pour pouvoir travailler avec. Lorsqu'une interface est passée en paramètre, je désire pouvoir la transtyper afin de récupérer les champs et travailler avec.

    Voici un bout de code pour que vous voyez ce que j'essaie de 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
    TUser = class( TAutoObject, IUser )
    private
      FNom : WideString;
    public 
      function Traiter( aUser : IUser ) : WideString; safecall;
      function  Nom : WideString;
    end;
     
    implementation
     
    function TUser.Traiter( aUser : IUser ) : WideString;
    begin
      Result := TUser( IUser ).Nom;
    end;
    Ce n'est pas exactement le nom que je désire récupérer, j'ai fait un exemple plus simple pour que vous comprenniez sans avoir à tout expliquer. La solution dans ce cas étant de définir Nom dans IUser, mais le soucis n'est pas là. Je désire pouvoir transtyper IUser en TUser et il ne veut pas.

    Merci pour votre aide.

  2. #2
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    En fait, pour faire plus simple, j'ai une interface IUser :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    IUser = interface( IDispatch )
    // ...
    end;
    Et un objet qui dérive de cette interface et de TAutoObject :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    TUser = class( TAutoObject, IUser )
    // ...
    end;
    Dans une méthode, j'ai une interface passée en paramètre que je souhaite transtyper en TUser en utilisant as mais il refuse avec message d'erreur à la compilation :
    Types incompatibles : 'TUser' et 'IUser'
    Si j'essaie de faire un TUser( IUser ).... il remonte n'importe quoi, le transtypage ne se fait pas comme il faut.

  3. #3
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    Mauvaise nouvelle, je viens de trouver une partie de la réponse ici :
    http://www.developpez.net/forums/sho...ce+transtypage
    Il faut donc utiliser un pointeur qui renverra vers la CoClasse.

    Le soucis est que je fais une bibliothèque de type et si je veux être compatible .NET, je ne peux pas utiliser les pointeurs.

    Faut que je trouve une autre solution.

  4. #4
    Expert confirmé

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Par défaut
    De fait, c'est impossible. Une référence de type interface cache par définition totalement les références à l'objet qui implémente cette interface.

    Il est possible de récupérer des références vers les autres interfaces qu'implémente l'objet référencé, mais pas l'objet lui-même.

    En effet, si tu es en inter-langages (domaine pour lequel ont été créées les interfaces), tu ne peux pas obtenir une référence valable à un objet.

    Je crois vraiment qu'il y a un problème de conception dans ta solution, car ce n'est pas du tout le but des interfaces de permettre d'obtenir une référence à l'objet.
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  5. #5
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    Pour faire une bibliothèque de type, on déclare des interfaces qui serront distribuées et les utilisateurs utiliseront ces interfaces.

    Mais il faut aussi créer les classes qui vont implémenter ces interfaces, ces classes ne sont pas visibles pour l'utilisateur final, mais son inclues dans la bibliothèque de type, c'est en quelque sorte l'implémentation des interfaces.

    Les interfaces ne possèdent pas de champs, je les inclue dans les classes qui les implémentent.
    Dans les méthodes des interfaces, je ne peux pas passer une classe qui l'implémente (elles ne sont pas visibles pour l'utilisateur), je ne passe que des interfaces.
    Par contre, dans l'implémentation de la méthode, je souhaite pouvoir récupérer les champs des classes qui implémentent les interfaces passées en paramètre.

    Peut-être dois-je trouver une autre solution, à priori, c'était celle qui me parraissaît le plus simple, mais ce n'est pas possible. Dans mon idée, il n'y avait pas de soucis de classes visibles de l'extérieur, il n'y avait que des interfaces.

    J'ai vu une solution qui serrait de renvoyer un pointeur sur l'instance mais dans les objets automation, il n'y a pas le type pointeur possible et ce n'est pas compatible avec .NET.

  6. #6
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    Je vais essayer de faire un exemple plus parlant parce que je pense ne pas avoir bien expliqué mon cas, et si je ne m'y prends pas comme il faut, comment pourrais-je m'y prendre autrement ?

    Dans le fichier TLB, voici la définition de l'Interface (ce n'est qu'un exemple) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      IUser = interface(IDispatch)
        ['{5C266B02-7627-44C0-9388-7007081CF523}']
        function Get_Nom: WideString; safecall;
        procedure Add( const aUser : IUser ); safecall;
        property Nom: WideString read Get_Nom;
      end;
    Et la classe générée qui implémente les méthodes de IUser :
    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
      TUser = class( TAutoObject, IUser )
      private
        FNom : string;
        FMyUser : TMyUser; // objet dérivant de TComponent, utilisé dans l'application
     
      protected
        function Get_Nom: WideString; safecall;
        procedure Add( const aUser : IUser ); safecall;
     
      public
        property MyUser : TMyUser read FMyUser write FMyUser;
      end;
     
    implementation
     
    function TMyUser.Get_Nom: WideString;
    begin
      Result := FMyUser.Nom;
    end;
     
    procedure Add( const aUser : IUser );
    begin
      FMyUser.Add( ( aUser as TUser ).MyUser ); // <- Ici le FMyUser prend un TMyUser en paramètre, je ne sais pas comment arriver à le récupérer depuis l'interface
    end;
    Dans le TLB, il n'y a bien que des interfaces et des types acceptés pour assurer la compatibilité avec les autres langages.

    L'architecture que j'ai choisi n'est pas la bonne ? Je pensais que coller les objets automation aux objets de l'application était une bonne idée.

  7. #7
    Expert confirmé

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Par défaut
    Pourquoi ne fais-tu pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FMyUser.Add(AUser.MyUser);
    ?
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  8. #8
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    Je ne peux pas parce que MyUser est un objet interne, non visible depuis les interfaces, il est déclaré dans la classe qui implémente et en paramètre je n'ai pas cette classe qui implémente mais l'interface.

  9. #9
    Expert confirmé

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Par défaut
    C'est bien ce que je disais... Il y a erreur de conception

    Ce que tu peux faire, c'est déclarer une seconde interface IWithMyUser qui ne définit que deux méthodes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    IWithMyUser = interface
      ['{GUID}']
      function GetMyUser : TMyUser;
      procedure SetMyUser(New : TMyUser);
     
      property MyUser read GetMyUser write SetMyUser;
    end;
    Ensuite, lorsque tu possèdes une référence à IUser, tu peux tenter de la déréférencer en IWithMyUser. Je dis tenter parce qu'imagine qu'une autre classe implémente ton interface IUser, mais pas IWithMyUser...
    (au passage, le const était totalement inutile )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    procedure TUser.Add(aUser : IUser);
    begin
      try
        FMyUser.Add((aUser as IWithMyUser).MyUser);
      except
        on Error : EIntfCastError do
          // ici il te faut gérer le cas où aUser n'implémente pas IWithMyUser
      end;
    end;
    Ca, c'est un modèle de programmation le plus propre possible pour ta conception de base.

    Maintenant, je continue d'affirmer que ce c'est pas top top non plus, car tu supposes que seules tes classes à toi implémente IUser, comme tu le veux, c'est-à-dire avec également une implémentation de IWithMyUser.
    Si tu as l'occasion de revoir ta conception, je crois que ce ne serait pas une mauvaise idée
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  10. #10
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    J'essaierai ta méthode, tu dis que ma conception est à revoir est qu'elle n'est pas top top, mais je ne vois absolument pas du tout comment le concevoir autrement, c'est là le soucis, j'avais vraiment l'impression que la conception que j'avais faite était la seule bonne conception possible et je me rends compte (parce qu'on ne peut pas transtyper une interface) qu'elle n'est pas bonne, mais je ne vois aucune autre conception possible.

  11. #11
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    Je suis désolé de revenir encore une fois sur le problème, je suis en train d'essayer de le mettre en place.

    Le problème avec ton code est qu'il faudrait que TUser implémente l'interface IWithMyUser, hors en codant ma bibliothèque de type, la déclaration de TUser est automatiquement générée par Delphi et TUser est déclaré comme implémentant IUser et non pas IWhithMyUser.

    Je ne vois pas comment faire.

  12. #12
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    En faisant plusieurs tests, je pense avoir trouvé la solution.

    Il faut créer IWithMyUser comme interface dérivant de IUser.
    Déclarer TUser comme implémentant les 2 interfaces, IUser et IWithMyUser.
    Déclarer la méthode de récupération de l'objet TMyUser dans IWithMyUser.

    Puis transtyper IUser en IWithMyUser, mais pas avec as le compilateur le refuse, mais en IWithMyUser( IUser ).GetMyUser.

    Et ça paraît fonctionner. La solution arrive enfin ! Ouf.

    Merci pour ton aide Sjrd.

  13. #13
    Expert confirmé

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Par défaut
    Citation Envoyé par WebPac
    Déclarer TUser comme implémentant les 2 interfaces, IUser et IWithMyUser.
    Juste une petite remarque : si IWithMyUser hérite de IUser, il te suffit de déclarer TUser comme implémentant IWithMyUser
    Citation Envoyé par WebPac
    Merci pour ton aide Sjrd.
    De rien
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  14. #14
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    Je vais essayer, en fait, quand j'ai trouvé une solution qui marchait, je n'ai pas voulu insister dessus. Et comme normalement le Concepteur de bibliothèque de type crée lui-même TUser dérivant de IUser, je n'osais le retirer.

    C'est quand même bête de devoir déclarer une interface intermédiaire qui ne sert qu'à récupérer une méthode qui n'est pas déclarer dans l'interface de base juste parce qu'on ne peut pas faire de transtypage d'une interface en objet mais juste un transtypage d'interface en interface.

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

Discussions similaires

  1. Utiliser des objets automation dans Oracle
    Par WebPac dans le forum Forms
    Réponses: 10
    Dernier message: 29/11/2006, 19h17
  2. Savoir si un objet implement une interface
    Par toure32 dans le forum Delphi
    Réponses: 3
    Dernier message: 17/11/2006, 20h54
  3. [D4] Tps traitement : Objet Automation dans Library
    Par morgiou dans le forum Langage
    Réponses: 2
    Dernier message: 12/01/2006, 17h49
  4. [Appli] Recherche d'un type d'objet précis pour interface
    Par superpatate dans le forum Interfaces Graphiques en Java
    Réponses: 3
    Dernier message: 05/08/2005, 12h02
  5. Objet COM et interface
    Par pio_forum dans le forum Windows
    Réponses: 7
    Dernier message: 08/11/2004, 17h25

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