2012-06-18 1 views
0

J'essaye de dupliquer le comportement que j'observe dans JScript en C#. J'utilise IDispatch pour énumérer les membres et les appeler sur des objets liés en retard. Je suis un Noob C++ complet et je connais juste assez COM pour être très dangereux. Voici ma (mes) question (s):Présentation du comportement COM/WSH - IDispatch lié en retard _Default et Item?

  • Est-ce que DISPID_VALUE est toujours zéro (0)? (semble oui)
  • Lorsque j'appelle des objets COM, quand dois-je appeler le membre DISPID_VALUE? (quelque chose comme, lorsque l'interface elle-même est indexée ou invoquée ...?)
  • Y at-il des règles/conseils pour quand appeler.
  • Pourquoi, dans l'exemple ci-dessous, BindingFlags.SetProperty fonctionne-t-il sur .Cells (x, x) (par opposition à BindingFlags.InvokeMethod)? Appelle-t-il _Default (x, x)? Article (x, x)? Comment sait-il faire cela? Comment puis-je savoir ce qu'il appelle?
  • Y a-t-il une bonne documentation sur l'appel d'objets IDispatch COM à liaison tardive?

Dans l'exemple ci-dessous, la cellule 1,1 d'un tableur Excel a la valeur définie sur du texte et est en "gras".

Tenir compte de la JScript WSH suivant:


var objExcel = new ActiveXObject("Excel.Application"); 
objExcel.Workbooks.Add(); 
objExcel.Visible = true; 
objExcel.Cells(1,1).Value = "some test value"; 
objExcel.Cells(1,1).Font.Bold = true; 

Ce code C# crée le même résultat (oui, désolé, il est très bavard):


Type axType = Type.GetTypeFromProgID("Excel.Application"); 
object objExcel = Activator.CreateInstance(axType); 
object workbooks = objExcel.GetType().InvokeMember("Workbooks", System.Reflection.BindingFlags.GetProperty, null, objExcel, null); 
objExcel.GetType().InvokeMember("Visible", System.Reflection.BindingFlags.SetProperty, null, objExcel, new object[] { true }); 
workbooks.GetType().InvokeMember("Add", System.Reflection.BindingFlags.InvokeMethod, null, workbooks, new object[] { true }); 
object cell = objExcel.GetType().InvokeMember("Cells", System.Reflection.BindingFlags.GetProperty, null, objExcel, new object[] { 1, 1 }); 
cell.GetType().InvokeMember("Value", System.Reflection.BindingFlags.SetProperty, null, cell, new object[] { "some test value" }); 
object font = cell.GetType().InvokeMember("Font", System.Reflection.BindingFlags.GetProperty, null, cell, null); 
font.GetType().InvokeMember("Bold", System.Reflection.BindingFlags.SetProperty, null, font, new object[] { true }); 

Quand je reçois le temps d'une façon je prévois d'essayer et en savoir plus à ce sujet est d'avoir JScript appel à une classe C# COM que je créer avec la journalisation/débogage.

Répondre

3

Oui, DISPID_VALUE est # défini à 0 dans oaidl.idl. Donner une propriété un dispip de 0 en fait la propriété par défaut. Beaucoup de langues permettent d'omettre le nom de la propriété par défaut. Équivalent à l'indexeur C#.

C'est juste une convention, il n'y a certainement pas besoin d'une interface dérivée de COM IDispatch pour exposer une propriété par défaut. La propriété ne doit pas non plus être nommée "Value". Il est simplement commun de le faire. L'indexeur d'une interface [ComVisible] C# obtiendra dispid 0 mais avec le nom "Item". Beaucoup d'autres variations autour, vous ne pouvez rien supposer. BindingFlags.SetProperty fonctionne parce que le membre Cells est une propriété, pas une méthode. Cela ressemble un peu à une méthode uniquement parce que c'est une propriété indexée. C'est à peine supporté en C# (seulement pour l'indexeur) mais non restreint en COM ou VB.NET. L'interface COM IDispatch est utilisée dans votre exemple de code, elle permet de rechercher des membres par leur nom. IDispatch :: GetIDsOfNames() obtient cela fait, mappant une chaîne à un nombre (le dispid) quand il peut alors être utilisé pour invoquer la propriété ou la méthode avec IDispatch :: Invoke(). Notez que cela ne fonctionne que dans un sens, nom à numéro. IDispatch ne prend pas en charge l'équivalent de Reflection. Débarrassez-vous du code C# laid en l'écrivant dans VB.NET ou en utilisant le mot-clé dynamique de C# version 4 .

+0

Merci, Hans! C'est ma deuxième question COM à laquelle vous avez répondu :) J'ai vu votre travail sur d'autres questions aussi! Je souhaite absorber toutes vos connaissances ... Je m'interroge toujours sur le comportement WSH. IE: Sur Scripting.FileSystemObject .Drives, faire un WScript.Echo (x); sur un lecteur particulier donne la lettre de lecteur, que je suppose qu'il sait faire cela via le DISPID_VALUE. Je me demandais si ce genre de comportement est documenté quelque part, donc je peux avoir la compatibilité la plus large possible avec les objets COM. Connaissez-vous quelque chose à propos de cet aspect ou d'où je pourrais en apprendre plus à ce sujet? – aikeru

+0

Aussi, il me semble trouver qu'il pourrait y avoir une sorte de standard pour le dénombrement utilisant dispides après avoir fait une recherche Google, mais je n'ai pas trouvé beaucoup de profondeur ... donc, aussi intéressé par cela si vous le savez. J'apprécie votre aide :) j'espère que d'autres le feront aussi. – aikeru

+0

Cela n'est pas documenté pour la fonction Echo. Mais bien sûr, il est probable qu'il utilise la propriété par défaut. La propriété par défaut de l'objet Drive n'est pas documentée non plus, mais vous pouvez le découvrir en consultant la bibliothèque de types. À partir de l'invite de commande VS, exécutez oleview.exe c: \ windows \ system32 \ cscript.exe –

Questions connexes