Component Object Model (COM) &
Distributed COM (DCOM)
Elaborazione Distribuita
(anni ’80)
Appunti di Windows &
Dynamic Data Exchange (DDE)
(1987)
Object Linking and Embedding 1 (OLE 1)
& Dynamic Data Exchange (DDE)
(1992, 1993)
Open Software Foundation (OSF)
Remote Procedure Calls (RPC)
(1992)
COM, OLE2, ActiveX
(Windows NT 4.0)
(1995)
DCOM (1996)
Ragioni dello sviluppo COM
Applicazioni software di dimensioni sempre più grandi
Lunghi tempi per lo sviluppo e la manutenzione
Difficoltà nel rimuovere o aggiornare singole
applicazioni che interagiscono con altre applicazioni
Necessità di:
Semplificare la progettazione e lo sviluppo di applicativi
Facilitare e standardizzare l'interazione tra applicazioni di
diversi produttori
Caratteristiche del modello COM
COM è una specifica
http://www.microsoft.com/com/resources/comdocs.asp
COM è una “filosofia di programmazione”
Programmazione basata su componenti riciclabili
COM è uno standard di interoperabilità binaria
COM è un “collante” tra componenti, permettendo la loro
interazione
Caratteristiche del modello COM
Componente
una parte di software riutilizzabile in forma binaria (non è
un codice sorgente !!!)
Suddivisione di un progetto in componenti
I componenti possono essere facilmente integrati con
componenti prodotti da altri fornitori
Un componente permette di accedere alle proprie
funzionalità tramite le “interfacce”
Esempi di componenti: pulsanti, correttori ortografici
Caratteristiche del modello COM
L’utilizzo di un componente da parte di una
applicazione non comporta la ricompilazione, visto
che il componente che deve essere riutilizzato è già in
versione binaria
Ad esempio un word processor che usa un correttore
ortografico
Un componente è riutilizzabile
Chi produce un componente può riutilizzarne uno già
esistente, utilizzando due tecniche: containment e
aggregation
Caratteristiche del modello COM
Gestione delle versioni
Si è superato il problema delle dll:
un programma che utilizza una dll può interrompersi se trova una
versione diversa di dll
In COM non è possibile cambiare le caratteristiche
("interfaccia") dei componenti già esistenti.
La nuova versione di un componente COM deve
presentare le stesse interfacce, aggiungendone altre
Ad esempio se voglio realizzare un correttore ortografico diverso
da quello offerto da word, devo garantire le stesse interfacce
originarie, aggiungendone altre se voglio
Tecnologie ActiveX e OLE 2
Sono tecnologie create sulla base di COM e della sua
architettura
ActiveX utilizza anche la tecnologia OLE v.2.0
La principale e visibile caratteristica dei documenti
ActiveX è la possibilità di aprire una finestra
all’interno di un’altra applicazione
Ad esempio Explorer nei confronti dei documenti Word o
Acrobat
ActiveX
OLE 2
COM
Oggetti COM
Ogni oggetto COM è un’istanza di una particolare
classe
Ogni oggetto COM presenta una o più interfacce
Ogni interfaccia include uno o più metodi che
possono essere invocati dal programma client
Per invocare uno di questi metodi il client deve
possedere un puntatore all’interfaccia che contiene i
metodi
Client
AddToDictionary()
RemoveFromDictionary()
Oggetto COM
Interfaccia
Metodi
Interfacce degli Oggetti COM
Ogni interfaccia ha due nomi:
Stringa di caratteri. Deve iniziare con la lettera “I”
Globally Unique Identifier (GUID), chiamata Interface
Identifier (IID) o Universal Unique Identifiers (UUID)
GUID è di 16 byte ed è ottenuta eseguendo un apposito tool
GUID contiene un time stamp (tutti i GUID generati nella stessa
macchina saranno diversi)
GUID contiene il MAC address (o un numero casuale se non vi è
una scheda) per differenziare GUID generati da macchine diverse
La specifica delle interfacce (non l’implementazione)
avviene in un linguaggio comune: Interface
Definition Language (IDL)
Deriva dall'IDL usato in Microsoft RPC
Esempio di Interface Definition Language
[object,
uuid(E7CD0D00-1827-11CF-9946-444553540000)]
interface IMyInterface : IUnknown {
import “unknwn.idl”;
HRESULT LookUpInt([in] int c, [out] boolean *found);
HRESULT SumOfIntegers([in] myinteger[5], [out] int *sum);
}
L'interfaccia IMyInterface eredita tutti i metodi definiti in IUnknown
Un client in possesso del puntatore a IMyInterface può invocare anche i
metodi di IUnknown
I metodi dell'interfaccia IUnknown devono essere sempre presenti !
Il comando import specifica il file idl che descrive IUnknown
LookUpInt e SumOfIntegers sono i metodi forniti dall'interfaccia
IMyInterface
HRESULT è un valore di ritorno standard relativo al successo/insuccesso
[in], [out] parametri formali ingresso e uscita (esistono anche quelli
ingresso/uscita [in, out])
Alcune Regole sulla Definizione delle
Interfacce
Una volta che una interfaccia è stata definita e
rilasciata nel "mondo", essa non può più essere
cambiata.
Non è possibile cambiare/aggiungere/modificare
metodi o parametri.
L'unica soluzione è definire una nuova interfaccia
(nuovo nome e IID) che possiede gli stessi metodi
della vecchia interfaccia, aggiungendone altri nuovi.
Definizione delle Interfacce:
Standard binary format
La descrizione dell'interfaccia non è sufficiente per il suo uso da
parte di un generico client
Il client possiede solo il puntatore all'iterfaccia
In genere per invocare un metodo, un client deve sapere come
fare (ciò in genere dipende dal linguaggio in cui è stato scritto il
metodo)
Esiste una struttura binaria (SEMPRE LA STESSA) per
l'accesso ai metodi di una interfaccia di un oggetto COM.
Standard binary interface format
La presenza di uno standard binary interface format implica che
il client possa invocare un metodo di un oggetto senza dover
tener conto del linguaggio in cui è stato scritto il metodo stesso
Esempio di Interface Definition Language
Client
QueryInterface() { ……}
Pointer Method 1
AddRef() { ……}
Pointer Method 2
Release() { ……}
Puntatore
Interfaccia
Pointer Method 3
IMyInterface
Pointer Method 4
LookUpInt() { ……}
Pointer Method 5
SumOfInteger() { ……}
vtable
Internal
Pointer
to vtable
(1)
1) Metodi interfaccia IUnknown (sempre presenti)
2) Metodi interfaccia IMyInterface
(2)
Definizione delle Interfacce:
Standard binary format
La struttura binaria appena vista suggerisce che la
realizzazione più "immediata" e "naturale" di un client COM
si ottiene utilizzando il C++
è necessario implementare la gestione dei puntatori a
vtable per l'invocazione dei metodi
Scrivere un client in C è possibile, ma più difficile
L'assenza di meccanismi per la gestione dei puntatori in VB ha
determinato la necessità di creare una speciale interfaccia
vtable chiamata IDispatch
Interfaccia Fondamentale IUnknown
Tutti gli oggetti COM la devono implementare
Contiene tre metodi:
QueryInterface
AddRef
Release
Interfaccia Fondamentale IUnknown
Metodo QueryInterface
Quando il client crea un oggetto COM (come ? si vedrà
dopo), riceve il puntatore ad una delle sue interfacce
(quella richiesta dal client)
Con tale puntatore il client può invocare tutti i metodi
dell'interfaccia
E se vuole invocare metodi appartenenti ad altre interfacce ?
Ci sono casi in cui un client non crea un oggetto
COM, ma un altro client gli passa (cede) il puntatore ad
un'interfaccia di un oggetto COM già creato
Con tale puntatore il client può invocare tutti i metodi
dell'interfaccia
E se vuole invocare metodi appartenenti ad altre interfacce ?
Interfaccia Fondamentale IUnknown
Metodo QueryInterface
Attraverso il puntatore all’interfaccia, il client accede al metodo
IUnknown::QueryInterface
Specifica l’IID dell’interfaccia che gli necessita
Se l’oggetto COM supporta l’interfaccia richiesta, il client riceverà il
puntatore all’interfaccia richiesta e potrà utilizzarne i metodi.
Altrimenti passerà NULL
1. Il Client usa il puntatore a A per
richiedere il puntatore a B, invocando la
QueryInterface (IID_B)
A
Client
2. L'Oggetto ritorna il puntatore a B
B
3. Il Client può invocare i metodi
dall'interfaccia B
Oggetto COM
Interfaccia Fondamentale IUnknown
Esempio di Utilizzo Metodo QueryInterface
Supponiamo che esista un tool di analisi di testo implementato come
oggetto COM e che esso abbia un'interfaccia ISpellCheck
Una volta installato l'oggetto nel mio sistema, il mio word processor (e
qualunque altro client) lo può utilizzare: interroga la QueryInterface e
chiede del puntatore a ISpellCheck
Supponiamo che venga rilasciata una nuova versione dell'oggetto che ora
comprende anche l'interfaccia IThesaurus (semantica & sinonimi)
Se uso il nuovo oggetto con l'esistente versione di word allora la nuova
interfaccia sarà del tutto ignorata
Installando la nuova release del word processor, esso potrà chiedere sia il
puntatore a ISpellCheck sia a IThesaurus (tramite la QueryInterface)
Se installo la nuova versione di word e mantengo il vecchio oggetto, tutto
funziona ancora bene, perché se il mio word chiederà alla QueryInterface il
puntatore a IThesaurus, otterrà NULL e l'opzione Thesaurus nel menù sarà
disabilitata
Tipi di Componenti
Ogni oggetto COM è implementato dentro un Server
Il Server supporta più oggetti di una determinata classe
Il Server contiene il codice dei metodi delle interfacce
dell'oggetto
Il Server ha il compito di creare l'oggetto
Gestisce i dati di ciascun oggetto
E' possibile avere tre diversi tipi di oggetti COM in base al tipo
di Server che li supporta:
In-Process
Local
Remote
Dal punto di vista del Client non vi è alcuna differenza
Tipi di Componenti
Componenti In-process
Il Server In-Process condivide lo stesso spazio degli
indirizzamenti del Client
Il Server In-Process viene implementato come dll
Vantaggio: velocità di elaborazione (nessun passaggio di
contesto)
Svantaggio: essendo una dll e non exe, può essere
impiegato solo nel contesto di un programma chiamante e
non può essere eseguito come applicazione autonoma
Tipi di Componenti
Componenti Locali
Il Server risiede sullo stesso computer del Client, ma viene
eseguito come processo autonomo (spazio di indirizzi
differente)
Il Server locale viene implementato come exe
Svantaggio: cambio di contesto dal processo chiamante al
componente
Componenti Remoti
Il Server risiede su un computer diverso da quello in cui
viene fatto eseguire il client (processo che utilizza il
componente)
Lo scambio informativo remoto viene supportato da
DCOM
Creazione di un Oggetto COM
Finora si è assunto che un client possegga un
puntatore ad una interfaccia iniziale di un oggetto
COM
Dobbiamo capire come sia possibile creare un
oggetto COM e come un client possa acquisire il
puntatore ad una delle interfacce di tale oggetto
La creazione di un oggetto COM è basata su:
Esistenza di Class Identifier (CLSID).
Ogni oggetto COM è una istanza di una classe
Ogni classe è identificata da un Class Identifier
(CLSID)
Esistenza di una COM Library di supporto
Creazione di un Oggetto COM:
COM Library
Ogni sistema che supporta COM deve fornire
un'implementazione della COM Library
La COM Library fornisce funzioni di supporto ad
oggetti COM e ai client
ad esempio quelle per creare un oggetto COM
Le funzioni della COM Library sono accessibili
tramite semplici chiamate di funzioni
non si usano metodi delle interfacce COM
Il nome di una funzione della COM Library
generalmente inizia con il prefisso Co ad esempio CoCreateInstance
Creazione di un Oggetto COM:
COM Library
La creazione di un oggetto COM implica la
produzione di una istanza della classe dell'oggetto
Ciò viene realizzato tramite l'avvio del Server
relativo alla classe stessa
Tale Server è l'unico in grado di istanziare l'oggetto COM
E' necessario avviarlo solo per la prima istanza
dell'oggetto
E' compito della COM Library avviare il Server e
passargli l'ordine di creare l'istanza dell'oggetto
La creazione di un oggetto COM e l'inizializzazione
dell'istanza sono due fasi separate
Creazione di un Oggetto COM:
COM Library
La COM Library necessita di un "Registro di Sistema" in cui
venga associato ad ogni CLSID il percorso del codice del
Server
L'implementazione del "Registro di Sistema" dipende dal SO
Windows NT utilizza il Registry
In ogni caso il "Registro di Sistema" deve contenere:
CLSID (key-entry)
Tipo di server (in-process, local, remote)
Percorso relativo alla DLL o EXE (percorso locale o
remoto)
Il "Registro di Sistema" viene aggiornato ad ogni installazione
di una applicazione
Creazione di un Singolo Oggetto COM
In-Process e Locale
Il Client invoca la funzione “CoCreateInstance” della COM
Library, passando:
il CLSID (classe desiderata)
l’IID (identificatore dell’interfaccia desiderata)
Sulla base del CLSID ed utilizzando il "Registro di Sistema",
la COM Library:
Localizza il Server in grado di istanziare la classe dell'oggetto
Il Server viene attivato (se non lo è già)
Il Server crea l'istanza dell’object class desiderata, passando
alla COM Library il puntatore all’interfaccia richiesta
La COM Library passa questo puntatore al client
Creazione di un Singolo Oggetto COM
Remoto
Il Client invoca la funzione “CoCreateInstance” della COM
Library, passando il CLSID e IID
Sulla base del CLSID ed utilizzando il "Registro di Sistema",
la COM Library:
localizza il Server (Remoto) in grado di istanziare la classe
dell'oggetto
Viene contattato il Sistema Remoto per realizzare l'istanziazione (via
RPC)
Il Sistema remoto controlla il suo Registro ed individua il server
Il Server viene attivato (se già non lo è)
Il Server crea l'istanza dell’object class desiderata, restituendo al
Sistema Remoto il puntatore all’interfaccia richiesta
Il puntatore viene consegnato al client via RPC
Creazione di Oggetti Multipli
Class Factories
Se l’utente deve creare una sola istanza di un oggetto,
allora la CoCreateInstance è sufficiente
Molto spesso capita che l’utente necessita di istanze
multiple di oggetti della stessa classe
In tal caso viene utilizzato l’oggetto COM “Class
Factory”
Il Class Factory è un oggetto COM in grado di creare più
oggetti COM appartenenti ad una specifica classe
Il nome non è molto appropriato, perché vengono creati
oggetti non classi
Creazione di Oggetti Multipli
Class Factories
L'oggetto "Class Factory" viene gestito come un qualunque altro
oggetto COM (accesso tramite interfacce) e deve possedere almeno
l’interfaccia IClassFactory
In realtà la CoCreateInstance si basa sull'oggetto Class Factory e
sull'interfaccia IClassFactory, ma ciò viene del tutto mascherato
all'utente
Class
Factory
Client
IClassFactory
:: CreateInstance()
:: LockServer()
Server
Creazione di Oggetti Multipli
Class Factories
L’interfaccia IClassFactory contiene due metodi:
CreateInstance. Crea una nuova istanza della classe di
oggetto che la Class Factory può istanziare.
LockServer.
Per attivare un oggetto Class Factory, il client invoca la
funzione della COM Library: CoGetClassObject
Specifica il CLSID della classe di oggetti che l’oggetto
Class Factory dovrà istanziare
Specifica l’IID dell’interfaccia per l’accesso a Class
Factory (IClassFactory)
La COM Library crea l'oggetto Class Factory della classe
desiderata e fornisce al Client il puntatore richiesto
(IClassFactory)
Creazione di Oggetti Multipli
Class Factories
Il Client ha già invocato la funzione CoGetClassObject e la COM Library ha fatto
partire la Class Factory e ha fornito al Client il puntatore ad una sua interfaccia
(ad esempio IClassFactory)
4. Il Client può invocare i
metodi dell'oggetto
A
Object
3.Puntatore interfaccia A
2
Class
Factory
Client
IClassFactory
1.IClassFactory::CreateInstance(IID_A)
Server
Inizializzazione di un Oggetto COM
Quando un oggetto COM viene creato, esso ha dati
non inizializzati
Il Client potrebbe aver di bisogno l’inizializzazione
di dati (ad esempio salvati sul disco)
E' ovviamente necessario che i dati siano salvati in modo
persistente
In tal caso, la prima interfaccia che il Client chiederà
è quella contenente le funzioni di inizializzazione
dell’oggetto.
Esistono interfacce standard a tale scopo (utilizzo di
dati salvati in files):
IPersistFile, IPersistStorage, IPersistStream
Distruzione di un Oggetto COM
La soluzione più ovvia: il client che ha creato un
oggetto lo distrugge. Ciò non è possibile !
Spesso un client passa il puntatore all’interfaccia di un
oggetto ad un altro client (che può fare lo stesso con altri
client)
Ogni client non sa quanti altri client stanno utilizzando lo
stesso oggetto
Solo l’oggetto può sapere quando nessun client lo
utilizza più
Vengono utilizzati i metodi dell'interfaccia
IUnknown:
IUnknown::AddRef()
IUnknown::Release() basati sul Reference Counting
Distruzione di un Oggetto COM
Reference Counting
Ogni oggetto COM che viene creato, mantiene un Reference
Count
Quando l’oggetto COM passa il puntatore ad una sua
interfaccia ad un client, incrementa di 1 il Reference Count
Quando un client termina l'utilizzo l'oggetto, deve invocare il
metodo IUnknown::Release(), che decrementa di 1 il
Reference Count
Quando un client riceve il puntatore da un altro client, invoca
il metodo IUnknown::AddRef(), che incrementa di 1 il
Reference Count
Se il Reference Count è 0, l’oggetto distrugge se stesso
Problemi con i client che non rispettano la regola del
Reference Counting
Riuso di Componenti COM
Containment
IUnknown
Client
A
IUnknown
B
Outer Object
Inner Object
IUnknown
Aggregation
A
Client
Outer Object
IUnknown
Inner
B
Object
Marshalling
Per invocare un metodo di un oggetto COM, il client
deve possedere il puntatore all’interfaccia relativa al
metodo (vtable)
Il puntatore è un indirizzo di memoria
Per poter essere utilizzato, lo spazio degli indirizzi
deve essere lo stesso di quello del client
Come viene utilizzato il puntatore nell’architettura
COM ?
La risposta dipende dalla tipologia del server: inprocess, local e remote
Marshaling: In-process server
E' il caso più semplice.
Lo spazio di indirizzamento del client e del server è lo stesso
Il puntatore all’interfaccia può subito essere utilizzato per
accedere al binario del metodo richiesto
Il Passaggio dei parametri e i valori di ritorno è realizzato nel
modo tradizionale
Client
COM Object
In-process server
Client process
Marshaling:Local Server
Se il client e l'oggetto COM risiedono nella stessa
macchina, ma sono processi separati (spazio di
indirizzi diversi), il client non può puntare
all'interfaccia dell'oggetto
Si utilizzano due oggetti COM:
Proxy e Stub
Un proxy è un oggetto COM, che presenta la stessa
interfaccia dell’oggetto desiderato
Il client invoca il codice del proxy, che crea un
package dei parametri del client e li invia tramite una
interprocess communication (dipende dal SO)
Marshaling:Local Server
La richiesta arriva ad un altro oggetto COM: Stub
Lo stub unpackage la richiesta e passa i parametri del
client all’oggetto reale
Ogni risposta da parte dell’oggetto viene inviata nello
stesso modo al client
Single Machine
Client
Proxy
Interprocess
Stub
Object
communication
Client process
Server process
Marshaling: Remote Server
Stesso schema del Local Server
La comunicazione è basata su DCOM, utilizzando
RPC
Machine Y
Machine X
Client
Proxy
Client process
RPC
Stub
Object
Server process
Marshaling
Cosa è il Marshaling ?
Necessità di un formato standard per lo scambio di
parametri e risultati tra Proxy e Stub (soprattutto per i
remote server) e di opportuno codice per eseguire le
appropriate conversioni
Macchine diverse possono
rappresentazioni di dati diverse
usare
codifiche
e