Upload
tracy-freeman
View
214
Download
0
Embed Size (px)
Citation preview
COM and DCOM
CS 562
February 27, 2001
Motivation
Data Analyzer
Resource Monitor
int compute (…) {}
int compute (…) {}
Data Analyzer
int compute (…) {}
Resource Monitor
int compute (…) {}
Dynamically Linked Library
int compute (…) {}
Distributed Objects
• Object locator [registry]
• Communication– Data typing [interface]– Data representation [marshaling]– Synchronous/Asynchronous
• State persistence• System properties: Security, reliability, availability
ArchitectureClient Server
Client Application Object Implementation
Proxy Stub
Channel
Client Application contains code to access functionality from an object
Server may run on same “local” machine, or “remote” machine
Registry Registry
COM Basics
• Component Object Model (COM)
• COM is a specification that describes:
– What an object is
– How an object can manage itself over its lifetime
– How it tells the outside world what it can do
• COM is a binary specification, not a language
– Java, C++, VB, C
COM object
• A COM class defines the implementation of one or more interfaces
• A COM object is instantiated from a COM class
• A Client application accesses a COM object through interface pointers
Client Application COM object
interface pointer
Interfaces
• List of functions
– name
– parameters
– return type
• A COM object can implement multiple interfaces
• Once a COM interface is published it can never change
IUnknown
interface IUnknown { HRESULT QueryInterface (REFIID iid, void **ppvObject); ULONG AddRef (); ULONG Release ();}
• The ancestor of all Interfaces
• All COM objects must support this interface
– Provides reference counting for each interface
– Allows clients to locate appropriate interface
Registration of COM objects
• Interface ID (IID)– 128 bits. Statistically “Unique”
• Excel Worksheet– 00030000-0000-0000-C000-000000000046
• System Registry maintains all information– regsvr32.exe
regedit utility
COM IUnknown
interface IUnknown { HRESULT QueryInterface ([in] REFIID iid, [out] void **ppvObject); ULONG AddRef (); ULONG Release ();}
pInterface pQueryInterface
pAddRef
pRelease
Interface
QueryInterface (…)
AddRef ()
Release ()
Object
IUnknownCOM
Component
VTable
IUnknown
IAnother
IOneMore
ISum example
pQueryInterface
pAddRef
pRelease
VTable
QueryInterface (…)
AddRef ()
Release ()
Object
IUnknown
ISum
IUnknownCOM
Component
ISum
pSum
Sum ()
pInterface
ISum example
ULONG MiniCalc::AddRef() { return ++m_cRef; }
ULONG MiniCalc ::Release() { if (--m_cRef != 0) return m_cRef; delete this; return 0;}
HRESULT MiniCalc::QueryInterface (REFIID riid, void** ppv) { if (riid == IID_IUnknown) { *ppv = (IUnknown*) this; } else if (riid == IID_ISum) { *ppv = (ISum*)this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK;}
HRESULT MiniCalc ::Sum(int x, int y, int* retval) { *retval = x + y; return S_OK;}
class ISum : public IUnknown { public: virtual HRESULT Sum (int x, int y, int *retval) = 0;};
class MiniCalc : public ISum { public: // IUnknown ULONG AddRef(); ULONG Release(); HRESULT QueryInterface(REFIID iid, void** ppv);
// ISum HRESULT Sum(int x, int y, int* retval);
MiniCalc() : m_cRef(1) { } ~MiniCalc () {}
private: ULONG m_cRef;};
Implementing Interfaces in C++
• Multiple Inheritance
• Containment
• Aggregation
IUnknownCOM
Component
IMultiplyISum
[ object, uuid(10000001-0000-0000-0000-000000000001) ]interface ISum : IUnknown{
HRESULT Sum(int x, int y, [out, retval] int* retval);}
[ object, uuid(10000011-0000-0000-0000-000000000001) ]interface IMultiply : IUnknown{
HRESULT Multiply(int x, int y, [out, retval] int* retval);}
Multiple Inheritanceclass ISum : public IUnknown { public: virtual HRESULT Sum (int x, int y, int *retval) = 0;};
class IMultiply : public IUnknown { public: virtual HRESULT Multiply (int x, int y, int *retval) = 0;};
class MandS : public ISum, IMultiply { public: // IUnknown HRESULT QueryInterface(REFIID tiid, void **ppvObject); ULONG AddRef(); ULONG Release();
// Isum HRESULT Sum (int x, int y, int *retval);
// IMultiply HRESULT Multiply (int x, int y, int *retval); private: ULONG m_cRefs;}
MandS() : m_cRef(1) {}~MandS() {}
ULONG MandS ::AddRef() { return ++m_cRef; }
ULONG MandS ::Release() { if(--m_cRef != 0) return m_cRef; delete this; return 0;}
HRESULT MandS::QueryInterface(REFIID riid, void** ppv){ if (riid == IID_IUnknown) { *ppv = (IUnknown *) this; } else if (riid == IID_ISum) { *ppv = (Isum *) this; } else if (riid == IID_IMultiply) { *ppv = (Imultiply *) this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK;}
Reference Counting on Object Level!
Not on interface Level
const CLSID CLSID_Container = {0x10000012,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}};
class Container : public IMultiply, ISum { public: // IUnknown HRESULT QueryInterface(REFIID tiid, void **ppvObject); ULONG AddRef(); ULONG Release();
// IMultiply HRESULT Multiply (int x, int y, int *retval);
// ISum HRESULT Sum (int x, int y, int *retval);
HResult Init(); private: ULONG m_cRef; ISum *m_pSum;}
Container::Container() : m_cRef(1), m_pSum(NULL) {}Container::~Container() { m_pSum->Release(); }
HRESULT Container::Init() { return CoCreateInstance(CLSID_Container, NULL, CLSCTX_INPROC_SERVER, IID_ISum, (void**)&m_pSum);}
HRESULT Container::Sum(int x, int y, int* retval) { return m_pSum->Sum(x, y, retval);}
HRESULT Container::Multiply(int x, int y, int* retval) { *retval = x * y; return S_OK;}
ULONG Container::AddRef() { return ++m_cRef; }ULONG Container::Release() { if (--m_cRef != 0) return m_cRef; delete this; return 0;}
Containment
IUnknown
ISum IMultiply
ISum
const CLSID CLSID_ Aggregator = {0x10000022,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}};
class Aggregator : public IMultiply { public: // IUnknown HRESULT QueryInterface(REFIID tiid, void **ppvObject); ULONG AddRef(); ULONG Release();
// IMultiply HRESULT Multiply (int x, int y, int *retval);
Aggregator(); ~Aggregator(); HResult Init(); private: ULONG m_cRef; IUnknown* m_pUnknownInner;}
Aggregator::Aggregator() : m_cRef(1) {}Aggregator::~Aggregator() { m_pUnknownInner->Release(); }
HRESULT Aggregator::Init() { return CoCreateInstance(CLSID_Aggregator, (IUnknown*)this, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&m_pUnknownInner);}
HRESULT Aggregator ::Sum(int x, int y, int* retval) { return m_pSum->Sum(x, y, retval);}
HRESULT Aggregator ::Multiply(int x, int y, int* retval) { *retval = x * y; return S_OK;}
AggregationHRESULT CAggregator::QueryInterface(REFIID riid, void** ppv) { if (riid == IID_IUnknown) { *ppv = (IUnknown*)this; } else if (riid == IID_ISum) { return m_pUnknownInner->QueryInterface(riid, ppv); } else if(riid == IID_IMultiply) { *ppv = (IMultiply*)this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK;} IUnknown
IMultiplyISum
IUnknown
Knows ISum and IMultiply
Reference counts
• A COM object must remember which of its interfaces are being used
– once refcount = 0, interface is no longer being used
– once all refcounts = 0 for all interfaces supported by an object, it can be shutdown
• Client code must be disciplined– when making a copy of an interface pointer, must manually increment refcount
– when finished with an interface, must manually decrement refcount
Accessing COM objects
const CLSID CLSID_Container = {0x10000012,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}};
main () { IMultiply* pMultiply; CoInitialize(NULL); // Get COM started
CoCreateInstance(CLSID_Container, // [in] RCLSID NULL, // [in] Outer Object (if any) CLSCTX_INPROC_SERVER, // [in] Access Context IID_IMultiply, // [in] RIID (of desired interface) (void**) &pMultiply); // [out] Interface Pointer
int multiply; hr = pMultiply->Multiply(4, 3, &multiply); if(SUCCEEDED(hr)) { // process }}
Accessing interfaces using interface pointer
// use existing interface pointer to locate other interface pointer
ISum* pSum;
pMultiply->QueryInterface(IID_ISum, (void**) &pSum);
int sum;
hr = pSum->Sum(4, 3, &sum);
if(SUCCEEDED(hr)) {
// process
}
hr = pMultiply->Release();
hr = pSum->Release();
CoUninitialize();
}
Responsibility of QueryInterface
Class Factoryconst CLSID CLSID_ Factory = {0x10000032,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}};
class CFactory : public IClassFactory { public: // IUnknown HRESULT QueryInterface(REFIID tiid, void **ppvObject); ULONG AddRef(); ULONG Release();
// IClassFactory HRESULT CreateInstance(IUnknown *pUnknownOuter, REFIID iid, void** ppv); HRESULT LockServer(BOOL bLock);
CFactory() : m_cRef(1) { } ~CFactory() { } private: ULONG m_cRef;};
ULONG CFactory::AddRef() { return ++m_cRef; }ULONG CFactory::Release() { if (--m_cRef != 0) return m_cRef; delete this; return 0;}
HRESULT CFactory::QueryInterface(REFIID iid, void** ppv) { if ((iid == IID_IUnknown) || (iid == IID_IClassFactory)) { *ppv = (IClassFactory *) this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK;}
HRESULT CFactory::CreateInstance(IUnknown *pUnknownOuter, REFIID iid, void** ppv) { if (pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION; MiniCalc *pMiniCalc = new MiniCalc; if (pMiniCalc == NULL) return E_OUTOFMEMORY;
// QueryInterface probably for IID_IUNKNOWN HRESULT hr = pMiniCalc ->QueryInterface(iid, ppv); pMiniCalc ->Release(); return hr;}
Factory example// {10000002-0000-0000-0000-000000000001}const CLSID CLSID_Factory = {0x10000032,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}};
void main(){ HRESULT hr = CoInitialize(NULL); IUnknown* pUnknown; ISum* pSum;
IClassFactory* pClassFactory; hr = CoGetClassObject(CLSID_Factory , CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void**)&pClassFactory);
pClassFactory->CreateInstance(NULL, IID_IUnknown, (void**)&pUnknown); pClassFactory->Release();
hr = pUnknown->QueryInterface(IID_ISum, (void**)&pSum); hr = pUnknown->Release();
int sum; hr = pSum->Sum(2, 3, &sum); if (SUCCEEDED(hr)) cout << "Client: Calling Sum(2, 3) = " << sum << endl;
hr = pSum->Release(); CoUninitialize();}
IClassFactory
ClassFactory
IUnknown
pCreateInstance
pLockServer
IUnknown
creates
Object
IUnknown
ISum
IUnknown
pAdd
Add
Object Countslong g_cComponents = 0;long g_cServerLocks = 0;
Container::Container() : m_cRef(1), m_pSum(NULL) { g_cComponents++; }Container::~Container() { g_cComponents--; }
HRESULT CFactory::LockServer(BOOL bLock) { if (bLock) g_cServerLocks++; else g_cServerLocks--; return S_OK;}
HRESULT DllCanUnloadNow() { if (g_cServerLocks == 0 && g_cComponents == 0) return S_OK; else return S_FALSE;}
HRESULT DllGetClassObject(REFCLSID clsid, REFIID iid, void** ppv) { if (clsid != CLSID_Aggregate) return CLASS_E_CLASSNOTAVAILABLE;
CFactory* pFactory = new CFactory; if (pFactory == NULL) return E_OUTOFMEMORY;
// QueryInterface probably for IClassFactory HRESULT hr = pFactory->QueryInterface(iid, ppv); pFactory->Release(); return hr;}
HRESULT DllRegisterServer() { return RegisterServer("aggregate.dll", CLSID_Container, "Aggregate", "Component.Aggregate", "Component.Aggregate.1", NULL);}
HRESULT DllUnregisterServer() { return UnregisterServer(CLSID_Aggregate, "Component.Aggregate", "Component.Aggregate.1");}
Context for COM object
• INPROC_SERVER
• INPROC_HANDLER
• LOCAL_SERVER
• REMOTE_SERVER
INPROC_SERVER
• Dynamically Linked Library (DLL)
• COM object executes in same process space
IMultiply* pMultiply;
CoCreateInstance(CLSID_Container, [in] RCLSID NULL, [in] Outer Object CLSCTX_INPROC_SERVER, [in] ClsContext IID_IMultiply, [in] RIID (void**)&pMultiply); [out] Interface Pointer
INPROC_HANDLER
• DLL with custom marshaling of data
LOCAL_SERVER
• Executable (EXE)
• Dynamically Linked Library loaded into a surrogate process
REMOTE_SERVER
• Executable (EXE) on a remote machine
• Dynamically Linked Library loaded into a surrogate process on a remote machine
The Big Picture
ClientApplication
In-Process Server
In-ProcessObject
COM
Local ObjectProxy
Remote ObjectProxy
Client ProcessLocal Server Process
Remote Server Process
COM
Stub
COM
Stub
Local Server
Remote Server
LocalObject
RemoteObject
Remote Machine
Under the Hood
Page 115 from DCOM