Introduzione
Fino ad oggi abbiamo
sempre discusso con un mondo completamente managed, ovvero il cui
codice è scritto al 100% in linguaggi previsti dal FX (VB.NET e C# in primo
luogo), e che quindi gira all'interno del CLR. Possiamo però andare oltre,
e permettere al nostro codice di oltrepassare le normali barriere ed avere a che
fare con il managed unmanaged, ovvero tutto quello che riguarda codice
Win32, mondo COM e via dicendo.
Ovviamente, il fatto che sia possibile non vuol dire che sia una cosa
semplice, nè tantomeno che siamo esenti da rischi. La difficoltà principale è
saper mappare in memoria gli oggetti managed in modo tale che siano
utilizzabili dalle funzioni native Win32, e viceversa. Tale operazione è nota
con il termine di marshaling: vi rimando alla tabella in fondo a questo articolo per tutti i
dettagli del caso. Oggi cominciamo con le cose più semplici: vediamo infatti
come poter aggiungere ad un nostro progetto .NET un riferimento ad un componente
COM, sia esso un OCX, una DLL ActiveX o una type library.
Un riferimento ai componenti di Microsoft Word
Il
concetto che ruota a queste problematiche è che .NET crea una
classe managed che il nostro codice utilizza come wrapper per
tutte le chiamate al mondo unmanaged. Ad esempio, se apriamo un
qualsiasi progetto .NET con Visual Studio 2005, clicchiamo con il pulsanto
destro sul nome del progetto e selezioniamo la voce Add
Reference, l'IDE ci propone una finestra di dialogo dalla quale
possiamo selezionare qualsiasi cosa ci passi per la testa: oggetti .NET, oggetti
COM, altri progetti inseriti nella nostra solution, e via dicendo. Il tab
Browse ci permette di sfogliare il contenuto del nostro
hard-disk alla ricerca di files DLL, TLB, OLB, OCX ed EXE che vogliamo mettere
nei riferimenti del nostro progetto.
Supponiamo per esempio di voler interoperare con Microsoft Word
all'interno della nostra applicazione. Una delle possibili
soluzioni consiste nell'aggiungere come riferimento il file MSWORD.OLB,
seguendo il procedimento indicato prima. Questa semplice operazione si traduce
in:
- la creazione di un nuovo assembly in managed code, ottenuto
partendo dal file MSWORD.OLB
- l'inserimento del nuovo assembly nella GAC
- l'aggiunta del nuovo assembly come riferimento al nostro progetto
.NET
Così facendo, otteniamo in tutto e per tutto un riferimento valido all'object
model di Word, utilizzabile quindi direttamente nel nostro codice attraverso la
classe wrapper. Tale wrapper viene inserito in un namespace dedicato, che va
quindi referenziato tramite la solita using. Per esempio:
Microsoft.Office.Interop.Word.Application appWord =
new Microsoft.Office.Interop.Word.Application();
Document doc = appWord.Documents.Open( /*Parametri*/ );
Il metodo Open esposto dall'oggetto
Documents richiede un gran numero di parametri obbligatori,
cosa che invece non accade per esempio quando facciamo la stessa con VB6. Il
motivo è che molti dei parametri sono opzionali: in .NET questo comportamento si
attua sfruttando l'overloading dei metodi. Questo esempio vale solo a scopo
didattico, per cui ho deciso comunque di mantenerlo.
Il tool Tlbimp.exe
Il meccanismo di creazione della
classe wrapper in managed code è disponibile anche attraverso il tool tlbimp.exe fornito dal FX2.0.
Questo tool richiede essenzialmente il nome del file DLL di cui si vuole creare
il wrapper. Rispetto alle funzionalità esposte dall'IDE, abbiamo diverse marce
in più:
- l'opzione /namespace: permette di specificare il
namespace attraverso il quale sarà possibile raggiungere la nuova classe
wrapper
- l'opzione /out: permette di specificare il nome del file
generato
- l'opzione /keyfile: permette di specificare un file SNK
per firmare con uno strong name l'assembly (tale file viene generato dal tool
sn.exe, cliccare qui per maggiori informazioni)
Questo tool, quindi, permette di generare la classe wrapper al di fuori
dell'IDE ed in modo completamente indipendente. L'unico parametro davvero
necessario è il nome del file (tlbFile), che deve contenere
obbligatoriamente una COM type library.
Compilare un progetto che fa uso di Interop
Esiste una pagina su MSDN che descrive come compilare un progetto
.NET che usa InterOp per interagire con il mondo unmanaged. Se
compiliamo dall'IDE, non cambia nulla: la classe wrapper nasconde il mondo
unmanaged e siamo a posto. Se compiliamo da command-line, assicuriamoci
di utilizzare il parametro /reference: del compilatore per
referenziare l'assembly contenente la classe wrapper che ci serve.
Deploy di un'applicazione che fa uso di InterOp
Se stiamo
facendo il deploy di un'applicazione InterOp, dobbiamo considerare se i nostri
assembly wrapper devono essere condivisi fra più applicazioni. La pagina dedicata su MSDN è piuttosto chiara. Se gli assembly wrapper
sono condivisi, vale la pena firmarli con uno strong name, inserirli nella GAC
(che alla fin fine è un centralized repository fatto apposta per questo
scopo) ed il gioco è fatto. Se gli assembly sono privati per una certa
applicazione, il deploy deve essere fatto nella stessa directory dove si trova
l'applicazione.
Dietro le quinte: come fa Tlbimp a convertire?
A partire da questa pagina su MSDN, vengono descritte
quali sono le logiche che Tlbimp.exe mette in campo per convertire dal mondo COM
al mondo managed. Si parla quindi di Imported Member Conversion,
Imported Library Conversion, Imported Module Conversion e via
dicendo.