Distributed Object Systems – 4 –
COM/DCOM
Piet van Oostrum
Sept 18, 2008
DOS-4
What is COM/DCOM
I Component Object Model
I Components (distributed objects) à la Microsoft
I Mainly on Windows platforms
I Is used in large parts of Windows itself
I COM is local version, DCOM is distributed version
I Microsoft wants it to be replaced by .NET
I Originally developed to connect MS Word and Excel
I OLE: Object Linking and Embedding
I Later: generalisation: basic object communication mechanism could be used for other things: COM
I Mozilla’s XPCOM and UNO (OpenOffice.org) are similar
Piet van Oostrum DOS-4 1
DOS-4
COM vs Corba –1–
I Corba is platform independent
I COM is Microsoft-only
I Corba is multi-vendor
I COM comes with Windows.
I Corba must be installed separately
I Corba specifies how remote objects must be called (source code)
I COM defines a binary standard (implementation)
I Corba and COM have a similar structure (Services, etc.)
Piet van Oostrum DOS-4 2
DOS-4
COM vs. Corba –2–
I Interfaces
I COM objects can have more than one interface
I Corba objects have a single interface
(Corba Component Model supports multiple interfaces) I Identity
I Corba objects are identified by an object reference
I COM objects have one or more interface pointers I Inheritance
I COM and Corba have interface inheritance
I COM has single inheritance
I Corba has multiple inheritance
Piet van Oostrum DOS-4 3
Multiple inheritance vs multiple interfaces
Suppose you have an interface for printing and an interface for storage:
I Print interface:
I set_page(pagesize)
I build_pages(page_numbers)
I printit() I Storage interface:
I open_container(filename)
I read_object(obj_id)
I write_object(obj_id)
I Defining an object that supports both interfaces:
I In COM: the object implements both interfaces
I In Corba: inherit from both:
interface MyClass: Print, Storage
COM – What’s in it?
I COM is a mechanism to call objects (local or remote), compare Corba’s ORB
I Many services are defined that use COM (big parts of Windows O.S.)
I OLE Documents:
I Linking
I Embedding
I In-place activation
I (OLE) Automation (how to command an application from another application)
I Events . . .
DOS-4
Interfaces
I The interfaces to an object must be implemented in a specific binary way.
I This is derived from the way Visual C++ implements objects and methods.
I For COM objects this implementation must be used in all programming languages
I The interface can be described with (Microsoft) IDL
Piet van Oostrum DOS-4 6
DOS-4
Visual C++ object
m4
method code
method table vtable
var1 var2
m1 m2 m3
I Object have a pointer to avtable(an array of method pointers)
I This is followed by the instance variables
I Often a pointer to the object is passed around (object*)
Piet van Oostrum DOS-4 7
DOS-4
COM Interface
m4
code method
method table
vtable m1
m2 m3
I A COM interface is implemented as a pointer to a pointer to a list of function addresses (interface pointer)
I A COM object must implement at least one interface
I A COM object may implement more than one interface
I COM objects written in VC++ can use a pointer to themselves (this) as interface pointer
Piet van Oostrum DOS-4 8
DOS-4
COM Interface - Subclasses
class A { m1(){}; m2(){}; m3(){}; m4(){}; } class B extends A { m5(){}; m6(){}; }
m6
vtable m1
m2 m3 m4
m5
vtable m1
m2 m3 m4
B A
I The vtable for a subinterface is just an extension (more methods at the end) of the superinterface
I so the subinterface pointer can be used where the superinterface is needed
Piet van Oostrum DOS-4 9
Interface pointer Notation
Interface B Interface A
Object
client uses interface pointer:
Client Object
In the case of a remote object, the pointer refers to a proxy object.
There is no concept of object pointer
IUnknown
Every interface must have the following methods in the first 3 slots:
I QueryInterface (IID)
I For finding other interfaces I AddRef ()
I For counting how many references there are I Release ()
I For releasing a reference
I These three methods together form the interface IUnknown (Most people use names starting with ‘I’ for interfaces)
DOS-4
Identification
I A method from an interface is not identified by name, but by its position in the method table
I 0=QueryInterface
I 1=AddRef
I 2=Release, etc.
I An (abstract) interface is identified by a 128-bit (usually random-like) number:
I GUID (Globally Unique Identifier) or
I UUID (Universally Unique Identifier)
I UUID is a DCE term.
I There are utilities to generate GUID’s
Piet van Oostrum DOS-4 12
DOS-4
IUnknown
I QueryInterface on an object with a UUID for an interface as parameter returns an interface pointer for that interface (and the same object) if it exists.
I QueryInterface could return any interface pointer that has the proper slots (e.g. a subinterface)
I AddRef and Release together form a simple garbage collection mechanism (refcount): When the refcount for all interfaces of an object together reaches 0, the object can delete itself
I These three methods can be used with any interface
Piet van Oostrum DOS-4 13
DOS-4
Object identity
I There are no object pointers
I Any interface pointer for an object can be used to identify the object
I Two different interface pointers could identify the same object
I Object identity:
I A QueryInterface call for IUnknown for the same object should always give the same interface pointer
I regardless of the interface upon which it is called.
Piet van Oostrum DOS-4 14
DOS-4
MIDL
I Microsofts IDL is derived from OSF DCE’s IDL.
I MIDL is similar to Corba IDL but uses a different syntax
I It also specifies the UUID’s
I Interfaces can be grouped in classes and classes in libraries
I An interface can be used in many classes
I Classes are used to create objects
I Classes and libraries are also identified by GUID’s
I Class GUID’s (CLSID) are stored in the Windows registry with information how to run the code that implements the objects
Piet van Oostrum DOS-4 15
Example IDL
[object, uuid(3CFDB283-CCC5-11D0-BA0B-00A0C90DF8BC) ] interface IStat: IUnknown {
import "unknwn.idl";
HRESULT init();
HRESULT addItem([in] double item);
HRESULT getAvg([out] double *avg);
HRESULT getNum([out] long *num);
HRESULT getAll([out] double *avg, [out] long *num);
};
Conventionally a HRESULT return code signifies if the operation succeeded or not (there are no exceptions).
Method results are returned through out parameters.
MIDL types
I boolean – 8 bits I byte – 8 bits.
I char – 8 bits.
I double – 64-bit floating point number.
I float – 32-bit floating point number.
I hyper – 64-bit integer.
I int – 32-bit integer.
I long – 32-bit integer.
I short – 16-bit integer.
I small – 8-bit integer.
I wchar_t – 16-bit wide characters.
DOS-4
Examples of structs and arrays
#define MAX_INDEX 10
typedef char ATYPE[MAX_INDEX];
typedef short BTYPE[]; // Equivalent to [*];
typedef long CTYPE[*][10]; // [][10]
typedef float DTYPE[0..10]; // Equivalent to [11]
typedef float ETYPE[0..(MAX_INDEX)];
typedef struct
{ unsigned short size;
unsigned short length;
[size_is(size), length_is(length)] char string[*];
} counted_string;
Piet van Oostrum DOS-4 18
DOS-4
Use of dynamic arrays
HRESULT MyFunction(
[in, out] short * pSize,
[in, out, string, size_is(*pSize)] char a[0..*]
);
I pSize is the size of the array, given as separate parameter.
I IDL tells that this parameter really is the size of the array (needed for marshalling the proper number of elements)
I size_is is the number of elements reserved, length_is is the actual number of elements present if different
Piet van Oostrum DOS-4 19
DOS-4
Unions
Encapsulated union (with a discriminator) typedef union S1_TYPE
switch (long l1) U1_TYPE { case 1024:
float f1;
case 2048:
double d2;
};
S1_TYPE will be a struct in C/C++ with members the long l1 and the union with name U1_TYPE.
There are also other notations.
Piet van Oostrum DOS-4 20
DOS-4
Where are objects running?
I In a DLL:
I The DLL is loaded if necessary (first occurrence) and the client gets the real pointer to the object interface (in C++ could be the object pointer).
I Runs in the same process as the client
I This is calledinprocserver
I Method call is as fast as ‘normal’
I In another process on the same machine
I The process is started if necessary
I In the client process a proxy object is created with the same interface
I The proxy object uses RPC mechanisms to the real object
I This is calledlocalserver
Piet van Oostrum DOS-4 21
Where are objects running?
I In another machine
I Is used similar to local server
I RPC is over the network
I In the registry there is information about inproc or local server
I Also contains the location of the DLL and/or .exe file
I The client can specify inproc or local server
I For DCOM if the object is not found on the local machine, COM asks other machines if the object is there
I Remote objects must be separately registered in the registry
How to create (or get) objects
I Use the class object
I The COM runtime system (Service Control Manager) can find the class object, given a CLSID, from the registry
I It will also start a server or load a DLL if necessary
I The Class object should be a singleton (only one instance)
I It should provide methods to create objects or find existing ones.
I The function CoGetClassObject gets the class object, given a CLSID, interface ID and inproc/local/remote
I It returns an interface pointer for the class object
DOS-4
Integrated method
I Use CoCreateInstance
I This creates a class object and calls its CreateInstance method to get an object (instance)
I Must implement interface IFactory
I There is also an interface IFactory2 which supports licensing
I CoCreateInstance parameters:
I class id
I an Outer pointer (see later)
I inproc/local/remote
I interface id (GUID) for the object
Piet van Oostrum DOS-4 24
DOS-4
Client code
double value;
CoInitialize(NULL); // initialize COM
CoCreateInstance(CLSID_CStat, NULL, CLSCTX_SERVER, IID_IStat, (void**) &pIStat);
pIStat->addItem(value);
pIStat->QueryInterface(IID_IStat2,
(void**) &pIStat2);
pIStat->Release();
pIStat2->count(value);
pIStat2->Release();
CoUninitialize();
Piet van Oostrum DOS-4 25
DOS-4
Client side
(3) (5)
class factory
object
COM library COM runtime system
COM library Client
(6)
[1] [3]
[4]
[2]
[5]
(1) (2)
(4)
Server
1: CocreateInstance, 2: server started,
3: class object created, 4: IFactory interface called, 5: object created, 6: object interface pointer returned, [1],[2],[3]: calls to pIStat,
[4],[5]: calls to pIStat2
Piet van Oostrum DOS-4 26
DOS-4
Implementation
Every object must implement the IUnknown methods:
#define STDMETHODIMP __stdcall HRESULT
STDMETHODIMP Stat::QueryInterface(REFIID riid, void** ppv) { if (riid == IID_IUnknown || riid == IID_IStat)
*ppv = (IStat*) this;
// if more interfaces are supported // else if (riid == ...
else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK;
}
In Visual C++ there are different function calling mechanisms.
For COM objects __stdcall must be used.
Piet van Oostrum DOS-4 27
RefCount
int refcnt;
HRESULT
STDMETHODIMP Stat::AddRef() { refcnt++;
}HRESULT
STDMETHODIMP Stat::Release() { refcnt--;
if (refcnt == 0) { } ...
}
Class Factory
STDMETHODIMP HRESULT
CClassFactory::CreateInstance(LPUNKNOWN p, REFIID riid, void** ppv) { IStat* punk = (IStat*) new Stat();
HRESULT hr = punk->QueryInterface(riid, ppv);
return hr;
}
The CreateInstance method creates a new Stat object and returns its interface pointer for the interface iid.
QueyInterface will do the required AddRef.
DOS-4
Our own Methods
HRESULT
STDMETHODIMP Stat::addItem (double d) { sum += d;
n++;return S_OK;
} HRESULT
STDMETHODIMP Stat::getAvg (double* d) {
*d = sum/n; // should check n!=0 return S_OK;
}
Piet van Oostrum DOS-4 30
DOS-4
Server code
void main() { ...
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
CClassFactory* fact = new CClassFactory;
hr = CoRegisterClassObject(CLSID_CStat, fact, CLSCTX_SERVER, REGCLS_MULTIPLEUSE,
&dwRegister);
...
register the class object
Piet van Oostrum DOS-4 31
DOS-4
Finally
I COM is optimized for local calls (especiallyinproc).
I Is a very popular mechanism on the MS Windows operating system
I DCOM (distributed version) has never become popular
I Is now gradually superseded by .NET
I Mainly used in C, C++ and Visual Basic
I It has a lot of complicated issues
I Java support is minimal
I No multi-platform support
Piet van Oostrum DOS-4 32