web-dev-qa-db-fra.com

Transformez un simple C # DLL en un composant interop COM

Comment est-ce que je fais un C # DLL dans un interop COM DLL qui peut être consommé par une application VB6?

65
Elena Lawrence

C'est la réponse que je voulais trouver dans StackOverflow mais que je n'ai pas pu. Il s'avère assez facile de transformer une simple dll C # en une dll COM.

Pour créer la dll C #

Créez une solution avec un projet de classe C #. La classe devrait avoir une interface pour les propriétés/méthodes et une interface pour les événements. Assign GUID) attributs de la classe et des interfaces décrits dans MSDN - Exemple de classe COM (Guide de programmation C #) . Voir aussi: MSDN - Comment: déclencher des événements traités par un récepteur COM .

Dans Propriétés du projet> onglet Application> bouton Informations sur l'assemblage> cochez la case "Rendre l'assemblage visible par COM". Cela rend toutes les méthodes publiques de la classe COM visibles.

Dans Propriétés du projet> onglet Construction> Définissez "Cible de la plateforme" sur x86.

C'est tout ce que vous devez faire pour créer la DLL. Pour appeler la DLL, vous devez l'enregistrer.

Enregistrer le DLL sur votre machine de développement

Vous pouvez enregistrer le DLL de l’une des manières suivantes:

  • Vérifiez les propriétés du projet> onglet Construction> "S'inscrire à COM Interop". Cela enregistrera automatiquement le DLL lorsque vous le construirez.
  • Inscrivez manuellement la DLL avec RegAsm. Cela vous permet d'enregistrer la DLL dans le répertoire de votre choix, plutôt que dans le répertoire de construction. C'est la méthode J'ai utilisé.

    • Ne pas vérifier les propriétés du projet> onglet Générer> "S'inscrire à COM Interop"
    • Copiez le DLL dans le répertoire où vous souhaitez l'enregistrer
    • Ouvrez une commande Shell avec les droits d'administrateur et tapez

      RegAsm.exe -tlb -codebase mydll.dll
      

      RegAsm.exe peut être trouvé dans "C:\Windows\Microsoft.NET\Framework\v2.0.50727", tandis que "mydll.dll" est le nom de votre DLL. tlb signifie "créer une bibliothèque de types"; codebase signifie "écrire l'emplacement du répertoire dans le registre, en supposant qu'il ne soit pas placé dans le GAC".

      RegAsm affichera un avertissement indiquant que l’assemblée doit avoir un nom fort. Vous pouvez l'ignorer.

      À ce stade, vous devriez pouvoir ajouter une référence à COM DLL dans VB6, consultez-la avec Intellisense et exécutez-la comme une DLL COM normale.

Installation de DLL avec InstallShield

Si vous utilisez InstallShield pour installer la DLL avec le reste de votre application, procédez comme suit.

Dans InstallShield, ajoutez un nouveau composant à la liste des composants. N'oubliez pas d'associer le composant à une fonctionnalité. Définissez la propriété de composant ".NET COM Interop" sur Oui.

Ajoutez le fichier .dll à la section Fichiers du composant. Ne cochez pas la propriété "Auto-enregistrement". Cliquez avec le bouton droit sur le fichier .dll et sélectionnez "Définir le fichier de clé".

Ajoutez le fichier .tlb à la section Fichiers du composant. Vérifiez la propriété "Self-Register".

La version correcte du .Net Framework doit exister sur le PC cible.

C'est ça.

86
Kieren Johnstone

Comme extension à réponse de @ Kieren Johnstone un exemple de code pratique sur les modifications de classe, vous devez faire:

De:

public class ApiCaller 
{

    public DellAsset GetDellAsset(string serviceTag, string apiKey)
    {
     ....
    }
}

public class DellAsset
{
    public string CountryLookupCode { get; set; }
    public string CustomerNumber { get; set; }
    public bool IsDuplicate { get; set; }
    public string ItemClassCode { get; set; }
    public string LocalChannel { get; set; }
    public string MachineDescription { get; set; }
    public string OrderNumber { get; set; }
    public string ParentServiceTag { get; set; }
    public string ServiceTag { get; set; }
    public string ShipDate { get; set; }

}

À:

[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
[ComVisible(true)]
public interface IComClassApiCaller
{
    IComClassDellAsset GetDellAsset(string serviceTag, string apiKey);

}

[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface IComClassApiCallerEvents
{
}

[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"),
    ClassInterface(ClassInterfaceType.None),
    ComSourceInterfaces(typeof(IComClassApiCallerEvents))]
[ComVisible(true)]
[ProgId("ProgId.ApiCaller")]
public class ApiCaller : IComClassApiCaller {

    public IComClassDellAsset GetDellAsset(string serviceTag, string apiKey)
    {
        .....
    }
}


[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83E")]
[ComVisible(true)]
public interface IComClassDellAsset
{
     string CountryLookupCode { get; set; }
     string CustomerNumber { get; set; }
     bool IsDuplicate { get; set; }
     string ItemClassCode { get; set; }
     string LocalChannel { get; set; }
     string MachineDescription { get; set; }
     string OrderNumber { get; set; }
     string ParentServiceTag { get; set; }
     string ServiceTag { get; set; }
     string ShipDate { get; set; }

}

[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA70"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface IComClassDellAssetEvents
{
}

[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F937"),
    ClassInterface(ClassInterfaceType.None),
    ComSourceInterfaces(typeof(IComClassDellAssetEvents))]
[ComVisible(true)]
[ProgId("ProgId.DellAsset")]
public class DellAsset : IComClassDellAsset
{
    public string CountryLookupCode { get; set; }
    public string CustomerNumber { get; set; }
    public bool IsDuplicate { get; set; }
    public string ItemClassCode { get; set; }
    public string LocalChannel { get; set; }
    public string MachineDescription { get; set; }
    public string OrderNumber { get; set; }
    public string ParentServiceTag { get; set; }
    public string ServiceTag { get; set; }
    public string ShipDate { get; set; }

}

J'espère que cela vous fait gagner du temps

4

J'ai utilisé la réponse de Kieren Johnstone pour créer une DLL COM gérée.

  1. Créez une solution pour une bibliothèque de classes C # et nommez-la par exemple SOExampleNew. Dans VS 2017, choisissez la bibliothèque de classes (.Net Framework) et non la bibliothèque de classes (.Net Standard).

  2. Supprimez le code généré et insérez le code suivant:

    using System.Runtime.InteropServices;
    
    namespace SOExampleNew
    {
      [ComVisible(true)]  // This is mandatory.
      [InterfaceType(ComInterfaceType.InterfaceIsDual)]
      public interface ITestCls
      {
        int Add(int a, int b);      // A method
        string TheName { get; set;} // A property
      }
    
      [ComVisible(true)]  // This is mandatory.
      [ClassInterface(ClassInterfaceType.None)]
      [ProgId("SOExampleNew.TestCls")]
      public class TestCls : ITestCls
      {
        private string mName = "Bert";
    
        // A default public constructor is also mandatory.
        public TestCls() { }
    
        public int Add(int a, int b){ return a + b; }
    
        public string TheName { get { return mName; } set { mName = value; } }
      }
    }
    
  3. Construisez le projet avec la configuration Release/Any CPU. La sortie est le DLL SOExampleNew.dll géré situé dans le dossier\bin\release.

  4. Vous devez maintenant enregistrer votre DLL COM gérée. N'essayez pas de regsvr32, il existe un programme spécial appelé regasm pour les DLL COM gérées. Regasm a une version pour les applications 32 bits et 64 bits. Ouvrez une invite de commande en tant qu’administrateur et passez à C:\Windows\Microsoft.NET\Framework\v4.0.30319. Ce dossier contient l'application regasm.exe pour enregistrer le COM DLL géré comme s'il s'agissait d'une DLL COM 32 bits native.

  5. Tapez RegAsm.exe /tlb /codebase path_to_your_bin_release_folder\SOExampleNew.dll. Vous devez enregistrer votre DLL sur n'importe quel ordinateur de cette manière. N'oubliez pas le commutateur/tlb qui crée la bibliothèque de types. Le compilateur commentera le commutateur/code avec des avertissements que vous pouvez ignorer. La DLL est inscrite dans la partie WoW64 du registre et peut être utilisée par les applications 32 bits natives (non gérées).

  6. Répétez maintenant l’enregistrement pour l’utilisation du COM DLL géré par les applications 64 bits. Passez à C:\Windows\Microsoft.NET\Framework 64\v4.0.30319 et tapez la même commande que précédemment.

  7. Vous pouvez accélérer l'enregistrement sur votre propre PC en exécutant Visual Studio avec droits d'administration et en ajoutant les événements post-génération suivants:

    %SystemRoot%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe /tlb /codebase "$(TargetPath)"
    %SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe /tlb /codebase "$(TargetPath)"
    

Vous pouvez maintenant utiliser votre DLL comme une DLL COM non gérée native. Testez votre DLL avec VBA: Sous Outils/Références, cochez SOExampleNew. Si ce n'est pas indiqué, il y a un problème avec l'enregistrement. Un simple sous test:

Sub TestSOExampleNew()
  Dim so As New SOExampleNew.TestCls
  MsgBox so.Add(2, 3) & ", " & so.TheName
End Sub

Pour tester votre COM DLL gérée en C++, créez une nouvelle application console, insérez le code suivant et générez-la en tant que Release/x64 ou Release/x86:

#include "stdafx.h"
#import   D:\Aktuell\CSharpProjects\SOExampleNew\SOExampleNew\bin\Release\SOExampleNew.tlb"
//this is the path to my bin\Release folder
int main()
{
  SOExampleNew::ITestClsPtr TestClsPtr = nullptr;

  if (SUCCEEDED(CoInitialize(0)))
  {
    if (SUCCEEDED(TestClsPtr.CreateInstance("SOExampleNew.TestCls")))
    {
        wprintf(L"out: %ld, %s\n", TestClsPtr->Add(2, 3), (LPCWSTR)TestClsPtr->TheName);
    }
  }

  CoUninitialize();// Uninitialize COM
  return 0;
}
2
Dietrich Baumgarten

Microsoft a un rapide comment ici . Cependant, vous devrez enregistrer la DLL. Pour que votre dll C # ressemble plus à une simple dll C (Exportations non gérées C #), utilisez la méthode this , qui est décrite en détail ici .

1
pcunite

COM Interop est une technologie incluse dans le CLR (Common Language Runtime) .NET Framework qui permet aux objets COM (Component Object Model) d'interagir avec les objets .NET, et inversement. COM Interop a pour objectif de fournir un accès aux composants COM existants sans exiger que le composant d'origine soit modifié et inversement. Plus à: http://www.writeulearn.com/com-interop-using-csharp/

0
bhupesh