2010-03-29 5 views
3

je l'interface suivante définie pour exposer une classe .NET à COM:Incohérence dans les objets passant de VBA vers .NET via COM

[InterfaceType(ComInterfaceType.InterfaceIsDual)] 
[Guid("6A983BCC-5C83-4b30-8400-690763939659")] 
[ComVisible(true)] 
public interface IComClass 
{ 
    object Value { get; set; } 

    object GetValue(); 

    void SetValue(object value); 
} 

La mise en œuvre de cette interface est trivial:

[ClassInterface(ClassInterfaceType.None)] 
[Guid("66D0490F-718A-4722-8425-606A6C999B82")] 
[ComVisible(true)] 
public class ComClass : IComClass 
{ 
    private object _value = 123.456; 

    public object Value 
    { 
     get 
     { 
      return this._value; 
     } 

     set 
     { 
      this._value = value; 
     } 
    } 

    public object GetValue() 
    { 
     return this._value; 
    } 

    public void SetValue(object value) 
    { 
     this._value = value; 
    } 
} 

J'ai ensuite enregistré cela en utilisant RegAsm, et a essayé de l'appeler à partir d'Excel via le code suivant:

Public Sub ComInterop() 

    Dim cc As ComClass 
    Set cc = New ComClass 

    cc.SetValue (555.555) 

    valueByGetter = cc.GetValue 
    valueByProperty = cc.Value 

    cc.Value = 555.555 

End Sub 

Lorsque je passe à travers ce code, valueByGetter = 555.5555 et valueByProperty = 555.555 comme prévu. Cependant, j'obtiens une erreur d'exécution "Objet requis" sur la dernière ligne.

Pourquoi le réglage de la valeur via la méthode de réglage fonctionne-t-il mais le paramétrage via la propriété échoue? Que dois-je changer pour que la propriété fonctionne comme prévu? Edit: J'ai eu quelques réponses utiles, donc ma question supplémentaire est "ce problème se posera-t-il avec les clients COM écrits dans d'autres langues, ou est-il spécifique à VBA?".

+0

avez-vous essayé d'attacher le débogueur au processus d'Excel et d'intervenir et de voir exactement où il souffle? –

+0

Vous ne savez pas quel débogueur vous voulez dire. Si je débogue le code .net via VS.Net en démarrant Excel en tant que programme externe, je ne parviens pas au point d'arrêt dans la partie set de la propriété Value, indiquant qu'il s'agit d'un problème d'Excel. Si vous voulez dire directement déboguer Excel, je ne sais pas par où commencer - pourriez-vous me donner plus d'infos? Merci. – Akash

Répondre

4

Votre interface est exportés vers la bibliothèque de types comme ceci:

dispinterface IComClass { 
    properties: 
    methods: 
     [id(00000000), propget] 
     VARIANT Value(); 
     [id(00000000), propputref]    // <=== problem here 
     void Value([in] VARIANT rhs); 
     [id(0x60020002)] 
     VARIANT GetValue(); 
     [id(0x60020003)] 
     void SetValue([in] VARIANT Value); 
}; 

le problème est le poseur de la propriété de la valeur, il est déclaré que propputref i Au lieu de la propput. Qu'il y ait une différence du tout est un problème de cohérence méchant dans COM, provoqué par le fait qu'il supporte une propriété par défaut. C'est pourquoi vous devez utiliser le mot-clé Set dans VBA. Le problème est: vous ne passez pas un objet dans le code VBA, même si .NET en attend un. Après une recherche un peu, je n'ai trouvé aucune solution prête pour ce problème. Il y a une petite chance que le mot-clé Let puisse fonctionner dans VBA, je ne l'ai pas essayé. Le seul correctif à mi-chemin correct est de forcer la liaison tardive, au lieu de ComInterfaceType.InterfaceIsDual utiliser ComInterfaceType.InterfaceIsIDispatch. Ou évitez d'utiliser "objet".

+0

Merci pour l'info - pas la réponse que je voulais bien :) Donc, ce problème ne va se produire dans un client VBA? J'ai testé mon interface COM via VBA mais je n'ai aucun contrôle sur la langue dans laquelle les clients vont être écrits. – Akash

+0

Avez-vous * vraiment * besoin de supporter un Variant? Avez-vous * vraiment * besoin de prendre en charge la liaison anticipée? Il n'y a pas assez d'informations dans votre question pour faire cet appel. –

+0

Je pense que la liaison précoce + intellisense le rend beaucoup plus facile pour les utilisateurs de mon API (et donc moins d'appels de soutien!). Quant à la prise en charge de variant (objet), étant donné les types que j'ai besoin de Value à accepter, je pourrais spécifier que Value est une chaîne et l'interpréter correctement, mais cela semblera étrange aux clients .NET (peut-être pas étranger ...). Dans tous les cas, pensez-vous que le problème d'origine est spécifique à VBA ou à un problème COM plus général? – Akash

0

Vous devez utiliser le mot-clé Situé sur la dernière ligne:

Set cc.Value = 555.555 
+0

Lorsque j'essaie que cela échoue avec une erreur de compilation: objet requis. – Akash

0

Avez-vous essayé quelque chose comme (vb un peu rouillé, vous voyez l'idée):

Dim newValue as Int 
int= 555.555 
cc.Value = newValue (or maybe set cc.Value=newValue) 
+0

Désolé, n'aide pas - mêmes erreurs que l'original :( – Akash

1

Cela semble être un problème avec tlbexp et conseils MS en utilisant des appels tardifs liés comme ceci:

Dim cc As Object ' this one changed from ComClass 
Set cc = New ComClass 
... 
cc.Value = 555.555 

Vous pouvez le laisser tôt lié et essayer une solution beaucoup plus simple:

Set cc.Value = CVar(555.555) 
+0

La suggestion liée en retard fonctionne, mais l'approche CVar donne les mêmes erreurs qu'avant (j'ai essayé avec et sans le mot clé Set). – Akash

+0

Savez-vous si je vais rencontrer le même problème d'un client écrit dans une langue différente? c'est-à-dire est-ce un problème de COM ou un problème de VBA? – Akash

+0

Ceci est un problème d'interopérabilité .Net COM. Êtes-vous sûr que 'CVar' ne change pas le message d'erreur? – wqw

Questions connexes