2015-03-19 3 views
2

J'ai écrit un simple objet COM en C# avec une seule méthode, appelée GetMac. Je n'arrive pas à le faire marcher. J'essaie d'y accéder à partir d'une ancienne application Borland C++ Builder 4 (BCB4), que je sais être ancienne, et qui n'est plus beaucoup utilisée, mais je suis capable d'accéder à d'autres objets COM à partir d'elle. La machine de développement Borland exécute Windows XP, donc je cible l'objet COM C# l'infrastructure .NET 4.0. J'ai copié le fichier DLL et PDB de la machine C# Visual Studio vers la machine XP. Je me suis inscrit via la commande suivante:Objet COM écrit en C# - Récupère la classe, mais pas les méthodes

"%WINDIR%\Microsoft.NET\Framework\v4.0.30319\regasm.exe" TRSDotNetCOM.dll /tlb /nologo /codebase 

Je suis en mesure d'instancier l'amende objet COM (classe) via la ligne de code suivante:

Variant TDN = CreateOleObject("TRSDotNetCOM.TRSCOM_Class"); 

Si je change la chaîne de nom, il doesn ne fonctionne pas, donc je sais que j'ai cette partie correcte.

Cependant, lorsque je tente d'appeler la méthode comme suit:

MacV = TDN.OleFunction(funcNameV,counterV,macKeyV); 

... Je reçois une exception d'exécution (malheureusement, il y a un problème à l'exception de BCB4 manipulation pour les appels OLE, la seule information du débogueur me donne est "Exception s'est produite").

Étant donné que je suis capable d'appeler d'autres objets COM à partir de la même application BCB4 de la même manière, je ne pense pas que le problème concerne mon code C++. Je pense que c'est un problème avec la DLL COM créée par C#, ou l'enregistrement de celle-ci.

Pour explorer cela, j'ai utilisé Microsoft OLE/COM Object Viewer pour parcourir mon système pour l'objet OLE. J'ai été capable de trouver mon objet comme "TRSDotNetCOM.TRSCOM_Class", comme prévu.

Je suis tout nouveau à l'aide de l'Explorateur d'objets OLE/COM, donc j'espère que je regarde les bonnes choses ci-dessous:

Quand j'élargissons la classe, je vois ce qui suit: My class expanded

J'ai fait un clic droit sur _Object et j'ai choisi "View", puis "View Type Info". Ensuite, le volet sur la droite affiche:

[ uuid(65074F7F-63C0-304E-AF0A-D51741CB4A8D), hidden, dual, nonextensible, 
    custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "System.Object") 

] dispinterface _Object { 
    properties: 
    methods: 
     [id(00000000), propget, 
      custom({54FC8F55-38DE-4703-9C4E-250351302B1C}, "1")] 
     BSTR ToString(); 
     [id(0x60020001)] 
     VARIANT_BOOL Equals([in] VARIANT obj); 
     [id(0x60020002)] 
     long GetHashCode(); 
     [id(0x60020003)] 
     _Type* GetType(); }; 

Quand je développez l'arborescence à gauche, ce que je vois: Expanded _Object

Je ne vois pas répertorié nulle part là-dedans ma méthode « getmac » . Donc, je pense que d'une manière ou d'une autre la méthode n'est pas visible pour COM, ou qu'elle n'est pas enregistrée via regasm.

Voici la source de l'objet COM:

using System; 
using System.Runtime.InteropServices; 
using System.Security.Cryptography; 
using System.Text; 

namespace TRSDotNetCOM 
{ 
    [Guid("80ef9acd-3a75-4fcd-b841-11199d827e8f")] 
    public interface TRSCOM_Interface 
    { 
     [DispId(1)] 
     string GetMac(string counter, string macKey); 
    } 

    // Events interface Database_COMObjectEvents 
    [Guid("67bd8422-9641-4675-acda-3dfc3c911a07"), 
    InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 
    public interface TRSCOM_Events 
    { 
    } 


    [Guid("854dee72-83a7-4902-ab50-5c7a73a7e17d"), 
    ClassInterface(ClassInterfaceType.None), 
    ComVisible(true), 
    ComSourceInterfaces(typeof(TRSCOM_Events))] 
    public class TRSCOM_Class : TRSCOM_Interface 
    { 
     public TRSCOM_Class() 
     { 
     } 

     [ComVisible(true)] 
     public string GetMac(string counter, string macKey) 
     { 
      // convert counter to bytes 
      var counterBytes = Encoding.UTF8.GetBytes(counter); 
      // import AES 128 MAC_KEY 
      byte[] macKeyBytes = Convert.FromBase64String(macKey); 
      var hmac = new HMACSHA256(macKeyBytes); 
      var macBytes = hmac.ComputeHash(counterBytes); 
      var retval = Convert.ToBase64String(macBytes); 
      return retval; 
     } 

    } 
} 

Je n'assurerai et d'entrer dans les propriétés du projet et cochez la case « Enregistrer pour COM Interop ». J'ai également généré un fichier de nom sécurisé avec l'utilitaire "sn", et chargé le fichier dans la section Signing des paramètres.

Alors ...

1) Suis-je à la recherche dans le bon endroit dans l'objet OLE/COM Viewer pour ma méthode?

2) Si oui, pourquoi ma méthode ne serait-elle pas visible ou ne serait-elle pas enregistrée?

3) Des idées de quoi d'autre pourrait être faux?

MISE À JOUR: Voici le code mis à jour avec les suggestions de Joe W et Paulo. (Il ne fonctionne toujours pas cependant)

using System; 
using System.Runtime.InteropServices; 
using System.Security.Cryptography; 
using System.Text; 

namespace TRSDotNetCOM 
{ 
    [Guid("80ef9acd-3a75-4fcd-b841-11199d827e8f"), 
    ComVisible(true)] 
    public interface TRSCOM_Interface 
    { 
     [DispId(1)] 
     string GetMac(string counter, string macKey); 
    } 

    // Events interface Database_COMObjectEvents 
    [Guid("67bd8422-9641-4675-acda-3dfc3c911a07"), 
    ComImport, 
    ComVisible(true), 
    InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 
    public interface TRSCOM_Events 
    { 
    } 


    [Guid("854dee72-83a7-4902-ab50-5c7a73a7e17d"), 
    ClassInterface(ClassInterfaceType.None), 
    ComDefaultInterface(typeof(TRSCOM_Interface)), 
    ComVisible(true), 
    ComSourceInterfaces(typeof(TRSCOM_Events))] 
    public class TRSCOM_Class : TRSCOM_Interface 
    { 
     public TRSCOM_Class() 
     { 
     } 


     public string GetMac(string counter, string macKey) 
     { 
      // convert counter to bytes 
      var counterBytes = Encoding.UTF8.GetBytes(counter); 
      // import AES 128 MAC_KEY 
      byte[] macKeyBytes = Convert.FromBase64String(macKey); 
      var hmac = new HMACSHA256(macKeyBytes); 
      var macBytes = hmac.ComputeHash(counterBytes); 
      var retval = Convert.ToBase64String(macBytes); 
      return retval; 
     } 

    } 
} 

Répondre

0

C'est la première fois que j'ai vu une méthode déclarée ComVisible. Je renoncerais à cela et déclarer plutôt l'interface TRSCOM_Interface ComVisible.

+0

Joe W. - Ok, j'ai juste essayé votre suggestion. J'ai enlevé ComVisible de la fonction et l'ai ajouté à la déclaration d'interface. J'ai reconstruit la DLL, l'ai copiée, enregistrée de nouveau, et cela n'a pas fait de différence. Je reçois toujours l'exception et je ne vois toujours rien à propos de ma méthode dans le programme OLE/COM Object Viewer. – JoeMjr2

+0

J'écrirais un simple script VB pour le tester et sortir les trucs de Borland de l'équation. Peut-être que l'erreur de script VB aurait de meilleurs diagnostics ... –

+0

Joe W, merci pour la suggestion. Je pense que c'est une excellente nouvelle étape. Je ne connais pas VB, cependant. Y a-t-il une chance que je puisse obtenir des instructions pour faire cela, avec le code VB équivalent pour instancier mon objet et appeler ma méthode? – JoeMjr2

2

Il vous manque juste quelques bits.

Déclarez vos interfaces comme ComVisible:

[ComVisible(true)] 
public interface TRSCOM_Interface 

Si votre assemblée est déjà COM visible par défaut (vous pouvez le vérifier dans les propriétés du projet ou généralement dans AssemblyInfo.cs), vous n'avez pas besoin de faire ceci, mais il ne fait aucun mal et il gardera l'interface disponible pour regasm.exe et tlbexp.exe au cas où vous inverser cette configuration.

Déclarez l'interface des événements comme ComImport:

[ComImport] 
public interface TRSCOM_Events 

Je suppose ici que cette interface est définie en dehors de votre projet C#, probablement par l'application BCB4 ou l'un de ses modules.

Si ma proposition est fausse et que votre projet C# est celui qui définit cette interface, alors [ComVisible(true)]. Si cette interface comporte des méthodes d'événement, vous devez implement then as events in the class.

Enfin, pour éviter d'avoir une autre interface exportée pour votre classe, vous pouvez ajouter l'attribut ClassInterface:

[ClassInterface(ClassInterfaceType.None)] 
public class TRSCOM_Class : TRSCOM_Interface 

De cette façon, vous dites que TRSCOM_Interface est votre interface par défaut de classe, comme il est le premier que vous implémentez, et regasm.exe /tlb ne générera pas d'interface de classe.

En fonction de l'ordre des interfaces mises en œuvre ne rassure pas, vous pouvez également utiliser l'attribut ComDefaultInterface:

[ClassInterface(ClassInterfaceType.None)] 
[ComDefaultInterface(typeof(TRSCOM_Interface))] 
public class TRSCOM_Class : TRSCOM_Interface 

Maintenant, vous pouvez avoir un ordre dans la liste des interfaces mises en œuvre sans se soucier de changer la classe par défaut interface.

+0

Paulo, j'avais déjà l'attribut [ClassInterface (ClassInterfaceType.None)] sur ma classe Ma classe n'a aucun événement, c'est pourquoi la déclaration TRSCOM_Interface est vide. ailleurs, à part la source que j'ai affichée. Ay, je suis allé de l'avant et ajouté vos autres suggestions (voir la source mise à jour que j'ai ajouté dans ma question). Cependant, cela ne fonctionne toujours pas. Je reçois toujours l'exception et je ne vois toujours pas ma méthode GetMac dans le navigateur d'objets OLE/COM. – JoeMjr2

+0

J'ai copié-collé votre code actuel, compilé avec 'csc/target: library test.cs', puis j'ai lancé' tlbexp test.dll'. En utilisant OleView sur le test.tlb résultant, il y a une méthode 'GetMac' qui prend 2 BSTR 'in' et 1 BSTR' out'. Pouvez-vous copier-coller la sortie de OleView après ces étapes? – acelent

+0

Paulo, merci. Je viens de réaliser que je regardais au mauvais endroit dans OleView. J'allais dans _Object, alors que j'aurais dû aller dans TRSCOM_Interface. Quand je vais dans celui-là, je vois ma méthode GetMac. Je ne travaille toujours pas dans BCB4, cependant. – JoeMjr2