Per partire creiamo con Visual Studio un nuovo progetto Class Library C# con il nome "DotNETComObject" e definiamo una classe che sia accessibile a COM, per fare ciò è sufficiente associare un'interfaccia alla classe da esporre ed applicare qualche attributo (scopo di questo documento non è spiegare in dettaglio come creare una classe visibile a COM mediante .NET ma come sfruttare l'interoperabilità tra classe .NET e VC++):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace DotNETComObject
{
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[ComVisible(true)]
[Guid("B342CFE3-D9C6-40C1-A29E-C37BBE17BD2E")]
public interface IMyComClass
{
String MyComMethod();
}
[ComVisible(true)]
[ComDefaultInterface(typeof(IMyComClass))]
[Guid("E40EC2B1-2A9E-484C-ACF1-235BA32D5495")]
[ProgId("DotNETComObject.MyComClass")]
public class MyComClass : IMyComClass
{
public String MyComMethod()
{
return "my com object!";
}
}
}
quindi occorre impostare a "true" l'attributo ComVisible presente nel file AssemblyInfo.cs:
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(true)]
Per registrare l'oggetto occorre utilizzare l'utility regasm.exe passando come paramtro il percorso del nostro assembly e l'opzione "codebase" e "tlb":
C:\Windows\system32>regasm.exe C:\Temp\DotNETComObject.dll /codebase /tlb
regasm registra l'assembly creato riportando un warning (che ignoreremo) avvertendoci di firmare l'assembly con un nome sicuro. Per firmare un assembly con "strong name" è necessario generare un file con estensione snk attraverso l'utility sn.exe:
C:\Windows\system32>sn.exe -k C:\Temp\myKeyFile.snk
Per firmare l'assembly è necessario impostare il percorso del file snk da utilizzare nelle proprietà del progetto:
1) tasto destro sul progetto presente nella finestra "Solution Explorer" quindi selezionare proprietà,
2) Selezionare "Signing",
3) Spuntare "Signing the assembly"
4) Nella combo con descrizione "Choose a strong name key file" impostare il percorso del file snk creato.
Ora aggiungiamo alla soluzione un nuovo progetto VC++ di tipo console con nome "ConsumeDotNETComObject":
Condizione necessaria per creare un'istanza della classe COM .NET è importare il file con estensione TLB generato dal regasm:
// ConsumeDotNETComObject.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include
#include
#import "..\Build\DotNETComObject.tlb"
int _tmain(int argc, _TCHAR* argv[])
{
CComQIPtrIMyComClass> pIMyComClass;
::CoInitialize(NULL);
HRESULT hr = pIMyComClass.CoCreateInstance(L"DotNETComObject.MyComClass", NULL);
if(hr == S_OK){
std::cout << pIMyComClass->MyComMethod() << std::endl;
}else{
// do something
}
::CoUninitialize();
return 0;
}
Nel caso in cui si volesse utilizzare il file TLB per importare le informazioni della classe COM .NET si può utilizzare il file IDL che deve essere però generato manualmente sfruttando l'utility OleView.exe:
1) Aprire OleView.exe (in genere presente nel percorso C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin);
2) File->View TypeLib e selezionare il file TLB;
3) Copiare tutto il contenuto testuale presente nella finestra ITypeLib Viewer;
4) Creare un nuovo file di testo e incollare quanto copiato al punto 3);
5) rinominare il file creato al punto 4) con DotNETComObject.idl;
Ora con l'utility MIDL.exe possiamo generare il file .h e .c contenti le informazioni della classe COM creata in .NET:
C:\Temp>midl.exe DotNETComObject.idl /h DotNETComObject.h
il comando riportato sopra generara i file DotNETComObject.h e DotNETComObject_i.c da importare nel progetto VC++ per creare istanze della classe COM.
Aggiungiamo un nuovo progetto VC++ di tipo console alla soluzione con nome "ConsumeDotNETComObjectNoTLBImport" e copiamo i file .h e .c generati dal midl.exe nella directory del progetto (dove sono presenti i file sorgenti del progetto), quindi tasto destro sul progetto "Add existing item" e selezioniamo i file DotNETComObject.h e DotNETComObject_i.c.
Per riuscire a compilare il progetto è necessario modificare un'impostazione di compilazione, tasto destro sul progetto selezionare "Properties" e spostarsi nella sezione "C/C++ -> Precompiled Headers" alla voce "Precompiled Header" selezionare "Not Using Precompiled Headers".
Ora possiamo creare un'istanza della classe COM con poche riche di codice:
// ConsumeDotNETComObjectNoTLBImport.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "DotNETComObject.h"
#include
#include "atlstr.h"
#include
int _tmain(int argc, _TCHAR* argv[])
{
CComQIPtr<IMyComClass> pIMyComClass;
::CoInitialize(NULL);
HRESULT hr = pIMyComClass.CoCreateInstance(CLSID_MyComClass, NULL);
if(hr == S_OK){
CComBSTR txt;
if(pIMyComClass->MyComMethod(&txt) == S_OK){
std::cout << CW2A(txt) << std::endl;
}else{
// do something
}
}else{
// do something
}
::CoUninitialize();
return 0;
}
ConsumeDotNETComObjectVc.zip