Creazione di un oggetto in COM
Dopo che un thread ha inizializzato la libreria COM, è sicuro che il thread usi interfacce COM. Per usare un'interfaccia COM, il programma crea innanzitutto un'istanza di un oggetto che implementa tale interfaccia.
In generale, esistono due modi per creare un oggetto COM:
- Il modulo che implementa l'oggetto potrebbe fornire una funzione progettata in modo specifico per creare istanze di tale oggetto.
- In alternativa, COM fornisce una funzione di creazione generica denominata CoCreateInstance.
Ad esempio, prendere l'oggetto ipotetico Shape
dall'argomento Che cos'è un'interfaccia COM?. In questo esempio l'oggetto implementa un'interfaccia Shape
denominata IDrawable
. La libreria grafica che implementa l'oggetto Shape
potrebbe esportare una funzione con la firma seguente.
// Not an actual Windows function.
HRESULT CreateShape(IDrawable** ppShape);
Dato questa funzione, è possibile creare un nuovo Shape
oggetto come indicato di seguito.
IDrawable *pShape;
HRESULT hr = CreateShape(&pShape);
if (SUCCEEDED(hr))
{
// Use the Shape object.
}
else
{
// An error occurred.
}
Il parametro ppShape è di tipo pointer-to-pointer-to-IDrawable
. Se prima non si è visto questo modello, la doppia indirettità potrebbe essere puzzante.
Prendere in considerazione i requisiti della CreateShape
funzione. La funzione deve restituire un IDrawable
puntatore al chiamante. Tuttavia, il valore restituito della funzione è già usato per il codice di errore/esito positivo. Pertanto, il puntatore deve essere restituito tramite un argomento alla funzione. Il chiamante passerà una variabile di tipo IDrawable*
alla funzione e la funzione sovrascriverà questa variabile con un nuovo IDrawable
puntatore. In C++, esistono solo due modi per sovrascrivere un valore di parametro: passare per riferimento o passare per indirizzo. COM usa quest'ultimo indirizzo pass-by-address. L'indirizzo di un puntatore è un puntatore a un puntatore a un puntatore, quindi il tipo di parametro deve essere IDrawable**
.
Ecco un diagramma per visualizzare ciò che sta succedendo.
La CreateShape
funzione usa l'indirizzo di pShape (&pShape
) per scrivere un nuovo valore puntatore in pShape.
CoCreateInstance: un modo generico per creare oggetti
La funzione CoCreateInstance fornisce un meccanismo generico per la creazione di oggetti. Per comprendere CoCreateInstance, tenere presente che due oggetti COM possono implementare la stessa interfaccia e un oggetto può implementare due o più interfacce. Pertanto, una funzione generica che crea oggetti necessita di due informazioni.
- Oggetto da creare.
- Interfaccia da ottenere dall'oggetto.
Ma come indicare queste informazioni quando si chiama la funzione? In COM un oggetto o un'interfaccia viene identificato assegnando un numero a 128 bit, denominato GUID ( Global Unique Identifier ). I GUID vengono generati in modo da renderli effettivamente univoci. GUID è una soluzione al problema di come creare identificatori univoci senza un'autorità di registrazione centrale. I GUID sono talvolta denominati identificatori univoci universalmente (UUID). Prima di COM, sono stati usati in DCE/RPC (Distributed Computing Environment/Remote Procedure Call). Esistono diversi algoritmi per la creazione di nuovi GUID. Non tutti questi algoritmi garantiscono rigorosamente l'univocità, ma la probabilità di creare accidentalmente lo stesso valore GUID due volte è estremamente piccola, in modo efficace zero. GUID può essere usato per identificare qualsiasi tipo di entità, non solo oggetti e interfacce. Tuttavia, questo è l'unico uso che ci riguarda in questo modulo.
Ad esempio, la Shapes
libreria potrebbe dichiarare due costanti GUID:
extern const GUID CLSID_Shape;
extern const GUID IID_IDrawable;
È possibile presupporre che i valori numerici effettivi a 128 bit per queste costanti siano definiti altrove. La costante CLSID_Shape identifica l'oggetto, mentre la costante IID_IDrawable identifica l'interfaccia IDrawable
Shape
. Il prefisso "CLSID" è l'identificatore di classe e il prefisso IID è l'identificatore dell'interfaccia. Si tratta di convenzioni di denominazione standard in COM.
Dato questi valori, si creerebbe una nuova Shape
istanza come indicato di seguito:
IDrawable *pShape;
hr = CoCreateInstance(CLSID_Shape, NULL, CLSCTX_INPROC_SERVER, IID_IDrawable,
reinterpret_cast<void**>(&pShape));
if (SUCCEEDED(hr))
{
// Use the Shape object.
}
else
{
// An error occurred.
}
La funzione CoCreateInstance include cinque parametri. I primi e quarto parametri sono l'identificatore e l'identificatore dell'interfaccia della classe. In effetti, questi parametri indicano alla funzione "Creare l'oggetto Shape e assegnarmi un puntatore all'interfaccia IDrawable".
Impostare il secondo parametro su NULL. Per altre informazioni sul significato di questo parametro, vedere l'argomento Aggregazione nella documentazione COM. Il terzo parametro accetta un set di flag il cui scopo principale è specificare il contesto di esecuzione per l'oggetto. Il contesto di esecuzione specifica se l'oggetto viene eseguito nello stesso processo dell'applicazione; in un processo diverso nello stesso computer; o in un computer remoto. La tabella seguente mostra i valori più comuni per questo parametro.
Flag | Descrizione |
---|---|
CLSCTX_INPROC_SERVER | Stesso processo. |
CLSCTX_LOCAL_SERVER | Processo diverso, stesso computer. |
CLSCTX_REMOTE_SERVER | Computer diverso. |
CLSCTX_ALL | Usare l'opzione più efficiente supportata dall'oggetto. La classificazione, da più efficiente a meno efficiente, è: in-process, out-of-process e cross-computer. |
La documentazione per un determinato componente potrebbe indicare quale contesto di esecuzione supporta l'oggetto. In caso contrario, usare CLSCTX_ALL. Se si richiede un contesto di esecuzione che l'oggetto non supporta, la funzione CoCreateInstance restituisce il codice di errore REGDB_E_CLASSNOTREG. Questo codice di errore può anche indicare che CLSID non corrisponde a alcun componente registrato nel computer dell'utente.
Il quinto parametro di CoCreateInstance riceve un puntatore all'interfaccia. Poiché CoCreateInstance è un meccanismo generico, questo parametro non può essere fortemente tipizzato. Il tipo di dati è invece void**e il chiamante deve coercere l'indirizzo del puntatore a un tipo void** . Questo è lo scopo della reinterpret_cast nell'esempio precedente.
È fondamentale controllare il valore restituito di CoCreateInstance. Se la funzione restituisce un codice di errore, il puntatore dell'interfaccia COM non è valido e il tentativo di dereferenza può causare l'arresto anomalo del programma.
Internamente, la funzione CoCreateInstance usa varie tecniche per creare un oggetto. Nel caso più semplice, cerca l'identificatore della classe nel Registro di sistema. La voce del Registro di sistema punta a una DLL o EXE che implementa l'oggetto. CoCreateInstance può anche usare informazioni da un catalogo COM+ o da un manifesto SxS (side-by-side). Indipendentemente dal fatto che i dettagli siano trasparenti per il chiamante. Per altre informazioni sui dettagli interni di CoCreateInstance, vedere Client e server COM.
L'esempio Shapes
che è stato usato è leggermente contrived, quindi è ora possibile passare a un esempio reale di COM in azione: visualizzazione della finestra di dialogo Apri per l'utente per selezionare un file.
Prossima
Esempio: finestra di dialogo Apri