1 / 22

Componenti COM

Componenti COM. Componenti COM (COM server). Un Componente COM implementa ed esporta un insieme di Interfacce (oltre a IUnknown) L’implementazione delle interfacce è fornita da un insieme di CoClass Ogni CoClass è univocamente identificata da un CLSID

upton
Télécharger la présentation

Componenti COM

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Componenti COM

  2. Componenti COM (COM server) • Un Componente COM implementa ed esporta un insieme di Interfacce (oltre a IUnknown) • L’implementazione delle interfacce è fornita da un insieme di CoClass • Ogni CoClass è univocamente identificata da un CLSID • Le CoClass di un componente sono contenute nel file eseguibile del componente (per esempio Dll o Exe) • In Windows i CLSID delle CoClass dei componenti disponibili sono registrate nel Registry di sistema

  3. Creazione di un server COM locale (server in un file .exe) • Passi necessari • Definire le interfacce specifiche del componente • Definire i parametri delle CoClass del componente • Fornire l’implementazione delle interfacce esportate dal componente • Fornire una class factory per creare le istanze del componente quando richieste dai client • Implementare l’entry point (main) del server • Impostare il registry per l’attivazione del componente

  4. Passo 1Interfaccia del componente • IDL è un linguaggio che permette di definire interfacce e librerie di tipi (contenenti CoClass) • Attributi IDL • Identificano le caratteristiche delle interfacce/CoClass • Attributo [uuid]: definisce gli IID o CLSID • Attributo [oleautomation]: definisce che l’interfaccia sarà usata per comunicazione inter-processi • Attributo [version]: definisce il numero di versione • Attributo [helpstring]: descrizione testuale • (per altri attributi vedere http://msdn2.microsoft.com/en-US/library/8tesw2eh(VS.80).aspx) • MIDL (Microsoft IDL compiler) permette di compilare l’interfaccia. Genera 3 file • <interface>_h.h: Contiene le definizioni delle interfacce (da usare come header file) • <interface>_i.c: Contiene gli IID e CLSID (usare in tutti I server e client) • <interface>_p.c: Contiene il codice di proxy/stub per client-server distribuiti

  5. Interfaccia IDL (esempio) [uuid(5C6CD72C-8FDE-4117-98BE-B2BB2D4110CB), version(1.0), oleautomation, helpstring("Interfaccia IMyCounter")] interface IMyCounter : IUnknown { HRESULT Reset([in] int val); HRESULT Inc(); HRESULT GetVal([out,retval] int* val); }; Le specifiche sui parametri di input/output sono necessarie per la corretta implementazione della comunicazione fra i processi (eventualmente in rete)

  6. Passo 2. Type Library • Una TypeLibrary contiene informazioni sulle CoClass incluse nel componente e le interfacce da esse implementate [uuid(2EBFC693-433E-41f5-B80B-98BDCDD8AD96), version(1.0), helpstring("TypeLib contenente il server locale (coclass) dei componenti MyCounter")] library CounterLocalServerLib { importlib("stdole32.tlb"); [uuid(34898D9A-B306-42ee-9105-300945C2B151)] coclass MyCounter { [default]interface IMyCounter; }; };

  7. Passo 3 (i/iii)Implementazione del componente • Implementazione di tutte le funzionalità esportate dalle interfacce del componente • Può essere realizzata in un qualsiasi linguaggio facendo riferimento agli IID e CLSID definiti in IDL • L’implementazione può consistere di uno o più moduli indipendentemente dal numero delle interfacce implementate • Va sempre implementata anche l’interfaccia IUnknown

  8. Passo 3 (ii/iii): Esempio in C++ class MyCounter : public IMyCounter { public: MyCounter(); virtual ~MyCounter(); // Metodi per implementare IUnknown STDMETHODIMP QueryInterface(REFIID riid, void** pIFace); STDMETHODIMP_(DWORD)AddRef(); STDMETHODIMP_(DWORD)Release(); // Metodi per implmentare IMyCounter STDMETHODIMP Reset(int val); STDMETHODIMP Inc(); STDMETHODIMP GetVal(int* val); private: DWORDm_refCount; intval; };

  9. Passo 3 (iii/iii)Implementazione di QueryInterface STDMETHODIMP MyCounter::QueryInterface(REFIID riid, void** pIFace){ if(riid == IID_IUnknown)*pIFace = this; else if(riid == IID_IMyCounter)*pIFace = this; else { *pIFace = NULL; return E_NOINTERFACE; } ((IUnknown*)(*pIFace))->AddRef(); return S_OK; }

  10. Passo 4. Class Factory • La class factory è necessarie per poter creare più istanze dello stesso componente per richieste provenienti da client diversi • Le class factory implementano l’interfaccia standard IClassFactory class MyCounterClassFactory : public IClassFactory { public: MyCounterClassFactory(); virtual ~MyCounterClassFactory(); // IUnknown …… // IClassFactory STDMETHODIMP LockServer(BOOL fLock); STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter,REFIID riid,void** ppv); private: ULONG m_refCount; };

  11. Passo 5. Server Entry Point • Main che viene eseguito quando viene lanciato l’eseguibile del server • Registra tutti i tipi del componente (CLSID e IID) nel registry di sistema (LoadTypeLibEx) • Crea gli oggetti ClassFactory per ogni componente gestito dal server e li registra nel sistema (CoRegisterClassObject) in modo che possano essere trovato attraverso CoGetClassObject • Rimane in attesa che il client smetta di usarlo client

  12. Server object counting • Il server viene attivato da COM quando un client fa richiesta • Il server deve rimanere attivo fino a quando almeno un client sta usando almeno un oggetto residente sul server, poi terminare • Per questo motivo, il server conta gli oggetti attivi (usati dai client), e quando il contatore va a 0 termina • La terminazione può per esempio avvenire attraverso un messaggio che interrompe il ciclo di attesa (o attraverso altre primitive di sincronizzazione)

  13. Object counting e reference counting • L’object counting è di solito associato alla costruzione/distruzione degli oggetti • Per ogni nuovo oggetto creato, si incrementa il contatore di 1 • Per ogni oggetto distrutto lo si decrementa di 1 • A sua volta, la distruzione degli oggetti è regolata dal meccanismo di reference counting (AddRef-Release) • Quando viene rilasciato l’ultimo reference, l’oggetto viene distrutto

  14. Class Factory e Reference Counting • Per le class factory l’incremento del contatote di reference (AddRef) effettuato in fase di registrazione (CoRegisterClassObject) non sarebbe mai controbilanciato, rendendo così impossibile terminare il server quando non è più usato da nessun client • Soluzione • Non uso reference counting per le class factory (annullando così l’effetto problematico di CoRegisterClassObject) • Quando una class factory viene richiesta per la prima volta con CoGetClassObject, COM invoca IClassFactory::LockServer(TRUE) • Com gestisce il reference counting relativo al client, attraverso un oggetto proxy, e quando viene rilasciato l’ultimo riferimento invoca ICLassFactory::LockServer(FALSE) • Quindi • Non c’è bisogno di usare reference counting, perché viene gestito automaticamente da COM • Il contatore degli oggetti sul server può essere gestito opportunamente attraverso IClassFactory::LockServer

  15. Passo 6. Impostazioni per l’attivazione del componente • Nel Registry di sistema va registrata l’associazione fra CLSID principale del server e file eseguibile che va lanciato per attivare il server • Bisogna creare opportune chiavi sotto HKEY_CLASSES_ROOT per registrare • L’associazione fra CLSID del server, e il per percorso del file eseguibile • L’associazione fra LIBID della TypeLib e il percorso del file contenente la typeLib • L’associazione fra gli IID delle interfacce e le proprietà delle stesse

  16. Meccanismi di riuso in COM • In COM esistono due principali forme di riuso di componenti (e delle loro interfacce) per implementare nuovi componenti • Delega (delegation) • Aggregazione (aggregation)

  17. Riuso attraverso “delega” • Si “riusano” i servizi di un componente esistente per implementare alcune funzionalità di un nuovo componente

  18. Delega: cenni all’implementazione e all’uso • Il componente esterno (outer object) è client del componente interno (inner object) • Generalmente, il componente interno non è visibile all’esterno • L’implementazione del componente esterno controlla il ciclo di vita del componente interno • definisce un puntatore al componente interno • crea il componente interno quando opportuno (per esempio in fase di creazione del componente esterno) • usa il componente interno attraverso le opportune interfacce • Rilascia il componente interno quando opportuno (per esempio quando viene rilasciato il componente esterno) • In questo modo è inoltre possibile • usare le interfacce del componente esistente come base per implementare le medesime interfacce nel nuovo componente • aggiungere (se necessario) codice prima e/o dopo l’invocazione dei metodi del componente esistente

  19. Riuso attraverso “aggregazione” • Si espongono le interfacce di un componente esistente come parte di un nuovo componente senza modificarne il comportamento

  20. Aggregazione: cenni all’implementazione e all’uso • Il componente interno viene creato in modo da delegare le chiamate a IUnknown all’interfaccia IUnknown del componente esterno • Il metodo QueryInterface del componente esterno restituisce (per le opportune interfacce) un puntatore al componente interno • In questo modo è possibile • usare lo stesso esatto comportamento di un componente esistente senza conoscerne i dettagli comportamentali • evitare il codice di delega dei servizi • aumentare le prestazioni evitando troppe chiamate di procedura annidate

  21. Aggregazione: creazione del componente interno (cenni) • Attraverso i metodi di creazione della COM library (CoCreateInstance, CoGetClassObject, IClassFactory::CreateInstance) • Tali metodi ricevono un puntatore (pUnkOuter) all’interfaccia IUnknown cui delegare le chiamate • L’idea è di usare tale parametro in modo che, se il puntatore pUnkOuter è diverso da NULL, le chiamate vengano delegate all’oggetto da esso puntato • L’implementazione dei componenti deve tenere opportunamente conto del puntatore pUnkOuter affinché il componente sia aggregabile • Tenere conto dell’aggregabilità costa poche linee di codice (circa 10) quindi è generalmente consigliato nell’implementazione del componente

  22. Alcuni riferimenti utili • Principali Interfacce COM • http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/html/aa9b11ae-7978-44ff-afe7-00c34bd235e3.asp

More Related