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 :

COM multi-interfaces en C# pour vbscript


Sujet :

C#

  1. #1
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    63
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2010
    Messages : 63
    Par défaut COM multi-interfaces en C# pour vbscript
    Bonjour à tous,

    J’ai un problème d’accès depuis un script VBS pour remonter dans la classe héritée de l’objet COM d’un assembly développé en C#. Bon c’est pas très parlant, je développe :

    J'ai fait un assembly .NET, en version 1.0.0.0, inscrit dans le GAC, publié dans COM, pour l’utiliser depuis un script VB. Mon assembly est codé avec une classe et son interface. J’ai donné manuellement tous les ID (CLSID, ProgID, IID, LIBID) pour gérer ça correctement. Mon vbscript fonctionne parfaitement. La structure du code de l’assembly peut se résumer à :

    MonInterface{ getValue() }
    MaClass : MonInterface{ getValue() }
    Fort de ce succès, aujourd’hui j’ai amélioré mon assembly .NET. J’ai ajouté des méthodes...
    J’ai désinscrit la 1.0.0.0 du GAC, dépublié dans COM, supprimé la DLL.
    Incrémenté la version de la DLL en 1.1.0.0, recompilé, inscrit dans le GAC et publié dans COM.
    Je ne veux pas toucher à l’ancien code pour rester compatible avec les anciens programmes client-COM. J’ai donc joué avec les implémentations des interfaces et l’héritage pour n’ajouter que le nouveau code... La structure du projet recompilé est la suivante :

    MonInteface{ getValue() }
    MaClasse : MonInterface{ getValue() }

    MonInterface1 : MonInterface{ getValue1() }
    MaClasse 1 : MaClasse, MonInterface1{ getValue1() }
    Les vieux scripts VB fonctionnent toujours parfaitement car les CLSID, ProgID, IID, LIBID de MonInterface et MaClasse n’ont pas changé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Set oMonComposant = CreateObject("MonComposant.MaClasse")
    MsgBox oMonComposant.getValue()
    Les nouveaux scripts VB fonctionnent parfaitement car j’ai des nouveaux CLSID, ProgID, IID. Le LIBID par contre, est resté le même puisque c’est le même projet C# pour les 2 classes (dans AssemblyInfo.cs, l’attribut [assembly: Guid(...)] ) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Set oMonComposant = CreateObject("MonComposant.MaClasse1")
    MsgBox oMonComposant.getValue1()
    Enfin, et c’est là mon problème, dans les nouveaux scripts VB, je devrais pouvoir faire appel via la nouvelle classe aux méthodes héritées de l’ancienne classe. Et c’est ici que j’ai une erreur. Je ne comprends pas pourquoi ce code ne fonctionne pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Set oMonComposant = CreateObject("MonComposant.MaClasse1")
    MsgBox oMonComposant.getValue()
    Voici le vrai code C# de l'assembly :

    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
     
     
    namespace MonComposant
    {
        // Interface originale
        [ComVisible(true), GuidAttribute("00FC2F76-E57A-4a64-904C-5BF44BEEBF8D")]
        [InterfaceType(ComInterfaceType.InterfaceIsDual)]     
        public interface MonInterface
        {
            string getValue();
        }
     
        // Classe originale
        [ComVisible(true), GuidAttribute("E7FF8AB7-4F15-4dac-89BD-A20FB1E9E10D")]
        [ProgId("MonComposant.MaClasse")]
        [ClassInterface(ClassInterfaceType.None)]
        public class MaClasse : MonInterface
        {
            public string getValue()
            {
                return "hello v0";
            }
        }
     
     
        // Nouvelle Interface (hérite de MonInterface)
        [ComVisible(true), GuidAttribute("82B1983C-7C33-4158-8CCF-D2A87713A060")]
        [InterfaceType(ComInterfaceType.InterfaceIsDual)] 
        public interface MonInterface1 : MonInterface
        {
            string getValue1();
            string getValue2();
        }
     
        // Nouvelle Classe (hérite de MaClasse + implémente MonInterface1)
        [ComVisible(true), GuidAttribute("62561DCA-B35C-4bd5-B5BB-80A72D2AB207")]
        [ProgId("MonComposant.MaClasse1")]
        [ClassInterface(ClassInterfaceType.None)]    
        [ComDefaultInterface(typeof(MonInterface1))]
        public class MaClasse1 : MaClasse, MonInterface1
        {
            public string getValue1()
            {
                return "hello v1";
            }
     
            public string getValue2()
            {
                return this.getValue() + " -+- " + this.getValue1();
            }
        }
    }
    avec le assemblyinfo.cs :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    [assembly: ComVisible(true)]
    [assembly: Guid("0fd06878-6c46-40a2-aff8-7e19ed68ac4c")]
    [assembly: AssemblyVersion("1.1.0.0")]
    [assembly: AssemblyFileVersion("1.1.0.0")]

    Voilà, voilà... je ne comprends pas ce que je fais mal.

    Merci d'avance pour votre aide.

  2. #2
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut herit interface in com not supported
    bonjour
    tu as empeche l'heritage des membres d'interface de base par un attribut com .
    voici le bout de code et un exemple en vba(identique à vbscript):

    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
     
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
     
    namespace MonComposant
    { 
        // Interface originale
        [ComVisible(true), GuidAttribute("4BB56966-2BCA-4587-AB86-AC5EF47ADA24")]
        [InterfaceType(ComInterfaceType.InterfaceIsDual)]
        public interface MonInterface
        {
         string getValue();
         string messageValue();
         string getPropToShadow();
        }
     
        // Classe originale
        [ComVisible(true), GuidAttribute("EE94F5D7-6C3B-4471-82BA-07DB2765E1C5")]
        [ProgId("MonComposant.MaClasse")]
        [ClassInterface(ClassInterfaceType.None)]
        public class MaClasse
        {  
            public string getValue()
            {
                return "hello  getValue from BaseClasse MaClasse "; 
            }
            public string messageValue()
            {
                return "hello  messageValue from BaseClasse MaClasse ";
            }
            public string getPropToShadow()
            {
                return "hello  getPropToShadow sera masquee ";
            }
        }
    }
     
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    namespace MonComposant
    {
        // Nouvelle Interface (hérite de MonInterface)
        [ComVisible(true), GuidAttribute("54D391AF-3866-4aea-9A28-B4B36A7D2BD4")]
        [InterfaceType(ComInterfaceType.InterfaceIsDual)]
        public interface MonInterface1 : MonInterface
        {
     
     
            string getValue1();
            string getAutreProp();
            //Pour masquer eventuellement une prop de classe base MaClasse 
            //utiliser plutot un New qui redefinit cette prop
            new string getPropToShadow();
     
        }
     
        // Nouvelle Classe (hérite de MaClasse + implémente MonInterface1)
        [ComVisible(true), GuidAttribute("7713C7EB-A93B-4c0d-9856-87B4AE737F54")]
        [ProgId("MonComposant.MaClasse1")]
        [ClassInterface(ClassInterfaceType.None)]
        //SUPPRIME CA qui fait le contraire de ce que tu veux.
        //Empeche l'acces aux classes de MonInterface base
        //[ComDefaultInterface(typeof(MonInterface1))]
        public class MaClasse1 :MaClasse, MonInterface1
        {
     
            #region MonInterface1 Membres
     
     
            string MonInterface1.getValue1()
            {
                return "hello1 getValue1 from MaClasse1";
            }
     
            string MonInterface1.getAutreProp()
            {
                return "hello1 getAutreProp from MaClasse1";
            }
            string MonInterface1.getPropToShadow()
            {
                return "hello   getPropToShadow Masquee ";
            }
            #endregion
     
     
     
     
     
        }
    }
    code vba qui accede aux classes com:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    'a noter que classe base MaClasse n'est accessible que via son
    'interface "MonInterface" en liaison tardive via  CreateObject
    Private Sub CommandButton1_Click()
    Dim c As MaClasse1
    Set c = New MaClasse1
     
    TextBox1.Text = c.getValue1 & " - " & c.getAutreProp & "  - " & c.getPropToShadow & vbCrLf
    Dim IObjInterface As MonInterface
    Set IObjInterface = CreateObject("MonComposant.MaClasse1")
    TextBox2.Text = IObjInterface.getValue & " - " & IObjInterface.messageValue & " - " & c.getPropToShadow
    End Sub
    bon code...

  3. #3
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    63
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2010
    Messages : 63
    Par défaut
    Bonjour,

    Merci pour ta réponse MABROUKI.

    J'ai retiré mon assembly du GAC, dépublié de COM, J'ai supprimé mon attribut ComDefaultInterface, recompilé republié COM et ajouté au GAC.

    Malgré tout, dans un fichier texte renommé en .vbs, si je fais le bout de code suivant j'ai une erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Set IObjInterface = CreateObject("MonComposant.MaClasse1")
    Wscript.Echo IObjInterface.getValue()
    Est-ce que ca marche chez toi avec un simple VBS ?

    Remarque, en vbs, l'interface de l'objet n'est pas connue, en tout cas j'ai aussi une erreur si je déclare une variable "Dim var MonInterface".

    Une telle différence de comportement est-elle possible entre vba et vbs ?

    Aurais-je encore oublié qqc ?

  4. #4
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut VBS,vba,vb6
    bonjour
    Non il n' y a aucune difference entre VBA Excel,VBS,VB6.Cet exemple tel quel fonctionne aussi bien en vb6.
    Ensuite je me suis rappele Excel VBA.En effet quand j'essayais il y a longtemps de ca de demarrer PowerPoint ou Word via CreateObject(progID), la doc microsoft recommende de mettre un trapping d'erreur sans autre explication ,pour resoudre le plantage d'interface.
    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
     
    Sub progTest1()
    'note la classe obj prealable
    Dim obj As Object
    On Error Resume Next
    ' CreateObject appelle l'interface PowerPoint
    obj = CreateObject("PowerPoint.Application")
    Resume Next
    MsgBox Err.Description & Err.Source
     
     
    End Sub
    Sub progTest1()
    'note la classe obj prealable
    Dim obj As Object
    On Error Resume Next
    ' CreateObject appelle l'interface
    obj = CreateObject("Word.Application")
    Resume Next
    MsgBox Err.Description & Err.Source
    tu ne peux pas acceder acceder à l'interface que via :
    -la declaration prealable et l'instanciation de MaClasse1,car une interface est "une espace de classe de base abstraite comme les classes vb.net du type MustInherit donc instanciable seulement par le biais des classes derives concretes ".
    En fait l'interface va examiner
    1/s'il y a un objet MaClasse1 dans MonInterface1 qui possede la fameuse Prop GetValue, sinon
    2/elle remonte vers MonInterface et examine s'il y a une classe concrete dans MonInterface c.à.d trouve MaClasse et recherche dans celle-ci GetValue.
    en vbs met un trapping d'erreur au debut de ton code:
    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
     
     
     
    Private Sub CommandButton1_Click()
     
    Dim c As MaClasse1
    Set c = New MaClasse1
    'Trapping error
    On Error Resume Next
     
    TextBox1.Text = c.getValue1 & " - " & c.getAutreProp & "  - " & c.getPropToShadow & vbCrLf
    Dim IObjInterface As MonInterface
    Set IObjInterface = CreateObject("MonComposant.MaClasse1")
    TextBox2.Text = IObjInterface.getValue & " - " & IObjInterface.messageValue & " - " & c.getPropToShadow
     
    'en cas d'erreur on vient ici avec les infos sur le type d'erreur
    Resume Next
    MsgBox CStr(Err.Number) & "  ..." & Err.Source & "  ..." & Err.Source
     
     
    End Sub
    J'ai comme l'impression que c'est le trapping d'erreur mais verifie aussi la frappe de ta chaine progid,ca se pourrait.
    bon code.....

Discussions similaires

  1. [MySQL] Interface d'administration pour un client
    Par diden138 dans le forum PHP & Base de données
    Réponses: 8
    Dernier message: 23/05/2007, 00h18
  2. créer une interface utilisateur console pour requetes sur mysql
    Par begonia dans le forum Shell et commandes GNU
    Réponses: 2
    Dernier message: 23/03/2007, 15h16
  3. Comment interfacer une apllication pour mobile gsm avec une application sur pc
    Par appsn dans le forum Développement Mobile en Java
    Réponses: 2
    Dernier message: 19/08/2006, 13h22
  4. Réponses: 2
    Dernier message: 20/08/2005, 12h53
  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