250 likes | 403 Views
Component Object Model (COM). Cos’è COM?. Tecnologia specifica della famiglia di sistemi operativi Windows che abilita la comunicazione fra i componenti software del sistema Teconologia component-based Favorisce lo sviluppo di componenti riusabili
E N D
Cos’è COM? • Tecnologia specifica della famiglia di sistemi operativi Windows che abilita la comunicazione fra i componenti software del sistema • Teconologia component-based • Favorisce lo sviluppo di componenti riusabili • Permette di creare applicazioni connettendo fra loro inisiemi di componenti • Rende possibile l’uso e lo sviluppo di servizi • Si tratta di una famiglia di tecnologie che include • COM+ • DCOM • ActiveX
Brevi cenni storici • 1991: OLE (Object Linking and Embedding) • Basato su DDE (dynamic data exchange) • Dedicato principalmente al progetto di compound-documents (documenti costituiti di parti gestite da diverse applicazioni) • 1993: OLE2 • COM viene introdotta come tecnologia di riferimento • Dedicato al progetto di componenti applicativi in genere • 1994: OCX (OLE Control Extension) • Estensioni COM per la creazione di componenti nella maggior parte dei linguaggi di programmazione • 1996: ActiveX • Estensione dei componenti OCX • Possono essere contenuti in pagine Web ed eseguiti nel browser • 1996: DCOM (distributed COM) • … • Oggi: .NET
COM: Principali caratteristiche • Standard binario per l’invocazione di funzioni fra diversi componenti • Indipendenza dal linguaggio di programmazione • Interoperabilità fra componenti di diversi fornitori • Meccanismi di scoperta delle interfacce implementate dai componenti • Meccanismo per l’identificazione univoca dei componenti e delle interfacce • Permette trasparentemente la comunicazione fra componenti eseguiti nello stesso processo o in processi diversi • Disponibile su diverse piattaforme • Windows, Macintosh, Unix…
Binary Standard • Oggetti COM: elementi di codice eseguibile che forniscono servizi al resto del sistema (terminologia alternativa: componenti, component object) • Il lay-out in memoria delle funzioni eseguibili è definito in modo standard per permettere l’interoperabilità binaria • Una virtual table contiene i puntatori all’implementazione delle funzioni • La doppia indirettezza permette a multiple istanze di condividere la stessa virtual table
Interfacce • I componenti COM forniscono i propri servizi attraverso collezioni di funzioni dette interfacce • Un componente generalmente supporta un insieme di interfacce • Convenzionalmente il nome delle interfacce comincia con una I (i maiuscola) seguita da un ulteriore lettera maiuscola • IUnknown (supportata da tutti i componenti COM) • ILookup • IDropTarget • IDragSource • IUnEsempioDiInterfaccia • Un puntatore ad un componente COM è in effetti un puntatore ad un’interfaccia supportata dal componente • Es: IUnknown* pRef;
Notazione grafica per i componenti COM componente Interfaccia implementata/supportata/esportata
Caratteristiche generalidelle interfacce • Un’interfaccia non è una classe • Solo metodi senza implementazione • Le interfacce non sono componenti • Piuttosto vengono implementate/supportate/esportate dai componenti • Gli utilizzatori di un componente usano puntatori a interfacce (supportate dal componente) • I componenti COM possono implementare interfacce multiple • Le interfacce sono fortemente tipizzate • Le interfacce sono immutabili
GUID • COM garantisce l’identificazione univoca di interfacce e classi attraverso GUID • GUID = Globally Unique Identifier • Numeri di 128 bit • Ogni GUID è garantito come unico nel mondo senza limiti di spazio e tempo • L’identificatore GUID di un interfaccia è detto IID • L’identificatore GUID di una classe è detto CLSID • I nomi simbolici sono usati solo per convenienza, ma l’identificazione reale di classi e interfacce avviene attraverso GUID • Esempio di GUID DEFINE_GUID(IID_ILOOKUP, 0xc4910d71, 0xba7d, 0x11cd, 0x94, 0xe8, 0x08, 0x00, 0x17, 0x01, 0xa8, 0xa3);
Tool GuidGen • Tool distribuito con Windows SDK
Component Object Library • Parte del sistema operativo con cui si interagisce per gestire COM • Contiene le API principali per la creazione e la gestione dei componenti COM • Alcune API della COM library sono • HRESULT CoInitialize(LPVOID pvReserved); • Inizializzazione dell’ambiente di esecuzione COM • void CoUninitialize(void); • Chiusura della COM library e delle connessioni COM per il thread corrente
CoCreateInstance(COM Library) • HRESULT CoCreateInstance( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID* ppv); • rclsid • CLSID della CoClass che implementa il componente • pUnkOuter • Serve per l’aggregazione di componenti. Per adesso useremo NULL • dwClsContext • Tipo di server COM da usare (in-process, local, remote): per ora useremo CLSCTX_INPROC_SERVER • riid • IID dell’interfaccia per usare il componente • ppv • Puntatore all’interfaccia restituito come risultato di CoCreateIntance
Un esempio • Il componente di sistema ActiveDesktop esporta i propri servizi attraverso l’interfaccia IActiveDesktop • IID_IActiveDesktop • f490eb00-1240-11d1-9888-006097deacf9 • CLSID_ActiveDesktop • 75048700-ef1f-11d0-9888-006097deacf9
IActiveDesktop (shlobj.h) DECLARE_INTERFACE_( IActiveDesktop, IUnknown ){ // IUnknown methods STDMETHOD (QueryInterface)(THIS_ REFIID riid, void **ppv) PURE; STDMETHOD_(ULONG, AddRef) ( THIS ) PURE; STDMETHOD_(ULONG, Release) ( THIS ) PURE; // IActiveDesktop methods STDMETHOD (ApplyChanges)(THIS_ DWORD dwFlags) PURE; STDMETHOD (GetWallpaper)(THIS_ LPWSTR pwszWallpaper, UINT cchWallpaper, DWORD dwReserved) PURE; STDMETHOD (SetWallpaper)(THIS_ LPCWSTR pwszWallpaper, DWORD dwReserved) PURE; STDMETHOD (GetWallpaperOptions)(THIS_ LPWALLPAPEROPT pwpo, DWORD dwReserved) PURE; STDMETHOD (SetWallpaperOptions)(THIS_ LPCWALLPAPEROPT pwpo, DWORD dwReserved) PURE; STDMETHOD (GetPattern)(THIS_ LPWSTR pwszPattern, UINT cchPattern, DWORD dwReserved) PURE; STDMETHOD (SetPattern)(THIS_ LPCWSTR pwszPattern, DWORD dwReserved) PURE; STDMETHOD (GetDesktopItemOptions)(THIS_ LPCOMPONENTSOPT pco, DWORD dwReserved) PURE; STDMETHOD (SetDesktopItemOptions)(THIS_ LPCCOMPONENTSOPT pco, DWORD dwReserved) PURE; STDMETHOD (AddDesktopItem)(THIS_ LPCCOMPONENT pcomp, DWORD dwReserved) PURE; STDMETHOD (AddDesktopItemWithUI)(THIS_ HWND hwnd, LPCOMPONENT pcomp, DWORD dwReserved) PURE; STDMETHOD (ModifyDesktopItem)(THIS_ LPCCOMPONENT pcomp, DWORD dwFlags) PURE; STDMETHOD (RemoveDesktopItem)(THIS_ LPCCOMPONENT pcomp, DWORD dwReserved) PURE; STDMETHOD (GetDesktopItemCount)(THIS_ LPINT lpiCount, DWORD dwReserved) PURE; STDMETHOD (GetDesktopItem)(THIS_ int nComponent, LPCOMPONENT pcomp, DWORD dwReserved) PURE; STDMETHOD (GetDesktopItemByID)(THIS_ ULONG_PTR dwID, LPCOMPONENT pcomp, DWORD dwReserved) PURE; STDMETHOD (GenerateDesktopItemHtml)(THIS_ LPCWSTR pwszFileName, LPCOMPONENT pcomp, DWORD dwReserved) PURE; STDMETHOD (AddUrl)(THIS_ HWND hwnd, LPCWSTR pszSource, LPCOMPONENT pcomp, DWORD dwFlags) PURE; STDMETHOD (GetDesktopItemBySource)(THIS_ LPCWSTR pwszSource, LPCOMPONENT pcomp, DWORD dwReserved) PURE; };
Uso del componente ActiveDesktop #include <shlobj.h> …… HRESULT hr; IActiveDesktop* pIAD; // creazione del componente hr = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER, IID_IActiveDesktop, (void**)&pIAD); // uso del componente hr = pIAD->GetWallpaper(wszPath, MAX_PATH, 0);
HRESULT • Handle di un risultato in COM • Valore di 32 bit che segnala il risultato di un operazione • Usato dalle API della COM Library • Usato dai metodi delle interfacce COM • Si interpreta attraverso macro per scoprire il successo/fallimento • SUCCEEDED(hr) • Fa il check che il valore sia >=0 • FAILED(hr) • Fa il check che il valore sia <0 • I valori specifici HRESULT danno informazioni sugli errori, e sono associati a corrispondenti messaggi testuali. Esempi: • E_NOINTERFACE (0x80004002) “No such interface supported.” • CO_E_CREATEPROCESS_FAILURE (0x80004018): “The server process could not be started. The pathname may be incorrect.” • CO_E_NOTINITIALIZED (0x800401F0) - “CoInitialize has not been called.”
Error Lookup Tool • Parte di Visual Studio
Nota Tecnica:Unicode String e Character string • COM gestisce le stringhe secondo la codifica Unicode • In Windows le stringhe Unicode corrispondono ad array di WCHAR • Per ottenere una stringa di caratteri ASCII (TCHAR in Windows), bisogna usare un’API di conversione: WideCharToMultiByte
WideCharToMultiByte • int WideCharToMultiByte( UINT CodePage, //CP_ACP per ASCII DWORD dwFlags, //trattamento dei caratteri composti LPCWSTR lpWideCharStr, //la stringa Unicode da convertire int cchWideChar, //lungh. stringa Unicode, -1 se null terminated LPSTR lpMultiByteStr, //buffer di caratteri per il risultato int cbMultiByte, //lungh del buffer di caratteri in byte LPCSTR lpDefaultChar, //carattere di default LPBOOL lpUsedDefaultChar); //indica uso del caratt. di default • Il trattamento dei caratteri composti (parametro dwFlags) è indicato dai seguenti possibili flag: • WC_COMPOSITECHECK: controllo sulla presenza di caratt. Composti • WC_SEPCHARS: separa i caratteri composto in 2 caratteri • WC_DISCARDNS: scarta la seconda parte dei caratteri composti • WC_DEFAULTCHAR: usa il carattere di default (parametro lpDefaultChar)
L’interfaccia IUnknown • Deve essere supportata da tutti i componenti • Tutte le interfacce derivano da IUnknown interface IUnknown { virtual HRESULT QueryInterface(IID& iid, void** ppvObj) = 0; virtual ULONG AddRef() = 0; virtual ULONG Release() = 0; } • Implementa le funzionalità essenziali di un componente • AddRef e Release per il conteggio dei riferimenti • QueryInterface per permettere agli utilizzatori di scoprire a runtime se una data interfaccia è supportata da un componente, e in caso positivo di ottenerne un riferimento
Reference Counting • Serve ad assicurare che i componenti (non le interfacce) rimangano vivi finché ci sono utilizzatori che hanno accesso ad una o più interfacce • I metodi AddRef e Release di IUnknown gestiscono il conteggio dei riferimenti • AddRef aggiunge un nuovo riferimento, viene invocata dalle funzioni che restituiscono riferimenti ad interfacce • Release deve essere invocata su un riferimento ad un’interfaccia quando quel riferimento non è più utilizzato • Se si fa una copia di un riferimento ad interfaccia bisogna invocare AddRef sul riferimento • Prestare molta attenzione all’uso di AddRef e Release perché il meccanismo del conteggio dei riferimenti è fonte di molti errori con COM
QueryInterface HRESULT QueryInterface(IID& iid, void** ppvObj) • iid • Interfaccia per la quale si richiede un riferimento • ppvObj • Riferimento all’interfaccia restituito come risultato di QueryInterface • Se il componente non supporta l’interfaccia richiesta viene restituito un valore di ritorno (HRESULT) che segnala l’errore
EsempioComponente ShellLink (estratto) • ShellLink • Componente per la creazione di link simbolici (shortcut) • CLSID = 0021401-0000-0000-C000-000000000046 • Interfacce supportate • {000214ee-0000-0000-c000-000000000046} IShellLink • SetPath • … • {0000010b-0000-0000-c000-000000000046} IPersistFile • Save • …
EsempioUso di ShellLink HRESULT hr; IShellLink* pISL; IPersistFile* pIPF; hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pISL); hr = pISL->SetPath(wszPath); hr = pISL->QueryInterface(IID_IPersistFile, (void**)&pIPF); hr = pIPF->Save(L"C:\\wallpaper.lnk",FALSE); pIPF->Release(); pISL->Release();
Componenti 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