My Blog

Using ComImportAttribute

by lupok on mercoledì 6 febbraio 2013 17:02
Mediante l'interoperabilità COM presente in .NET è possibile creare istanze di componenti COM esistenti richiedere modifiche al codice esistente. 

Ci sono diverse modalità per creare istanze di componenti COM in .NET tra cui: 

  •  Utilizzare TlpImp.exe per creare un wrapper .NET del componente COM esistente ed inserirlo tra i riferimenti del progetto .NET:

    L'utilità di importazione della libreria dei tipi consente di convertire le definizioni dei tipi presenti in una libreria dei tipi COM nelle definizioni equivalenti di un assembly di Common Language Runtime. L'output di Tlbimp.exe è un file binario (assembly) che contiene metadati per il runtime corrispondenti ai tipi definiti all'interno della libreria dei tipi originale. 

  •  Creare manualmente le definizioni COM attraverso un'interfaccia .NET:            

    Mediante una serie di attributi con ad esempio "ComImport" è possibile creare una mappatura tra le definizioni del componente COM e classi .NET, in particolare ComImport indica che il tipo è stato precedentemente definito in COM. 
Per prima cosa ho creato un componente COM semplicissimo da importare in .NET con la seguente interfaccia:
// MyCOM.idl : IDL source for MyCOM
//
 
// This file will be processed by the MIDL tool to
// produce the type library (MyCOM.tlb) and marshalling code.
 
import "oaidl.idl";
import "ocidl.idl";
 
[
   object,
   uuid(E16A9B85-A7B3-44DD-92FD-A18730260899),
   dual,
   nonextensible,
   pointer_default(unique)
]
interface IMyClass : IDispatch{
   [id(1)] HRESULT Initialize(void);
   [propgetid(2)] HRESULT Prop1([outretval] LONG* pVal);
   [propputid(2)] HRESULT Prop1([in] LONG newVal);
};
[
   uuid(F1266AF0-1C30-4B9A-AFB0-C7E96CB1CCF1),
   version(1.0),
]
library MyCOMLib
{
   importlib("stdole2.tlb");
   [		
      uuid(BE770998-A577-418D-9F41-592A11287623)		
   ]
   coclass MyClass
   {
      [defaultinterface IMyClass;
   };
};
 
Ho poi registrato il componente COM mediante il comando: 

C:\Windows\system32>RegSvr32 MyCOM.dll 

Occorre prestare particolare attenzione al tipo di compilazione utilizzata durante la procedura di build del componente COM, se è stata selezionata una compilazione a 64 bit piuttosto che a 32 bit, la stessa configurazione dovrà essere riportata nel progetto che utilizzerà il componente COM. 

Quindi ho creato un progetto di tipo Console Appplication in C# ed ho aggiunto una classe ed un'interfaccia chiamandole rispettivamente MyClass e IMyClass ed ho creato una mappatura tra le definizioni presenti nella interfaccia COM IMyClass e l'interfaccia .NET IMyClass:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace TestComImport
{
 
   //[
   //   object,
   //   uuid(E16A9B85-A7B3-44DD-92FD-A18730260899),
   //   dual,
   //   nonextensible,
   //   pointer_default(unique)
   //]
   //interface IMyClass : IDispatch{
   //   [id(1)] HRESULT Initialize(void);
   //   [propget, id(2)] HRESULT Prop1([out, retval] LONG* pVal);
   //   [propput, id(2)] HRESULT Prop1([in] LONG newVal);
   //};
 
   [System.Runtime.InteropServices.ComImport]
   [System.Runtime.InteropServices.Guid("E16A9B85-A7B3-44DD-92FD-A18730260899")]
   public interface IMyClass
   {
      [System.Runtime.InteropServices.DispId(1)]
      void Initialize();
 
      [System.Runtime.InteropServices.DispId(2)]
      Int32 Prop1
      {
         [System.Runtime.InteropServices.DispId(2)]
         get;
         [System.Runtime.InteropServices.DispId(2)]
         set;
      }
   }
}
Come di vede dal codice riportato sopra ho inserito l'attributo ComImport e l'attributo Guid il cui valore deve coincidere con quello presente nell'interfaccia COM originale. 

Per la classe MyClass fondamentalmente non occorre inserire al metodo o proprietà basta solo aggiungere gli attributi ComImport e Guid dove il valore di Guid deve coincidere con quello presente nell'idl per la coclass MyClass:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace TestComImport
{
   [System.Runtime.InteropServices.ComImport]
   [System.Runtime.InteropServices.Guid("BE770998-A577-418D-9F41-592A11287623")]
   public class MyClass
   {
 
   }
}

A questo punto posso creare istanze del componente COM in .NET in modo molto semplice:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace TestComImport
{
   class Program
   {
      static void Main(string[] args)
      {
         // 
         // Create an instance of a COM coclass - calls
         //
         // CoCreateInstance(BE770998-A577-418D-9F41-592A11287623, 
         //                  NULL, CLSCTX_ALL, 
         //                  IID_IUnknown, &f) 
         //
         // returns null on failure. 
         // 
         IMyClass myClass = (IMyClass)new MyClass();
 
         myClass.Initialize();
 
         myClass.Prop1 = 1200;
 
         Console.WriteLine("Prop1: {0}", myClass.Prop1);
      }
   }
}

Per ulterioni informazioni consultare http://msdn.microsoft.com/en-us/library/aa645736(v=vs.71).aspx

TestComImportAttribute.zip

Blogs Parent Separator My Blog
Author
lupok

My Blog

Tags