InProc Components
InProc Components
Version 3
copyright 1998-2004
Introduction to COM
Page 1
Section I - Introduction
What can you do with COM? What is COM? What is DCOM? Is it technically significant?
Introduction to COM
Page 2
Compose programs using binary components without rebuilding them. Up-date program by replacing components Dynamic Link Library. Reuse existing components.
Windows Process
client .exe
comp.dll
comp.dll
Introduction to COM
Page 3
Introduction to COM
Page 4
Control Container
ActiveX Control
Introduction to COM
Page 5
What is COM?
Introduction to COM
COM Objects
COM objects are wrapped in dll or exe servers. Each server has a class factory, called by COM, to build an instance of the object for client use.
IUnknown IUnknown
ICustom
IClassFactory
Component
Server
Class Factory
Class factory and component expose interfaces for use by COM and clients.
Page 7
Introduction to COM
COM Programs
clients request COM to load servers, instantiate their components and return pointers to the component interfaces.
IUnknown IUnknown Client ICustom IClassFactory
Component
Server
Class Factory
IUnknown
IUnknown
IUnknown
IUnknown
ICustom
IClassFactory
ICustom
IClassFactory
Component
Server
Class Factory
Component
Server
Class Factory
Introduction to COM
Page 8
COM Technologies
COM Controls
OLE documents
in-place activation (visual editing) property pages
ActiveX Controls Support for Windows programs Automation through through scripting Composition of programs from binary components
linking
events
embedding
OLE automation
connectable objects
persistent objects
structured storage
type information
Introduction to COM
Page 9
What is DCOM?
Introduction to COM
Page 10
RPC Channel
message queue
RPC
Server
Component
Class Factory
Stub
Introduction to COM
Page 11
COM has had a fundamental impact on software development processes for many engineering organizations.
Build process can be easier because reused components are not rebuilt. Integration is significantly simpler with standardized interfaces. Provides effective mechanism for software reuse that complements object oriented design methods as supported by C++. Microsoft developed COM into a scalable technology. However, COM is a mature technology and Microsoft is now turning, for a variety of good reasons, to its new .Net technologies.
Introduction to COM
Page 12
Future of COM
COM has competitors. CORBA and JAVI RMI/beans provide very similar services. Microsoft has shifted a lot of its focus to the .Net platform that co-exists with COM but is not COM centered.
Microsofts enterprise platform is moving away from COM to .Net
Introduction to COM
Page 13
Introduction to COM
Page 14
COM Objects
COM objects are wrapped in dll or exe servers. Each server has a class factory, called by COM, to build an instance of the object for client use.
IUnknown IUnknown
IClassFactory
Class factory and component expose interfaces for use by COM and clients.
Page 15
Introduction to COM
COM Interfaces
This means that reuse of software implementation through inheritance is not supported by COM.
Introduction to COM
Page 16
C++ Interfaces
Note that implementation details are not accessible to clients, but also, not hidden either. So clients have compilation dependence on implementation.
Page 17
Introduction to COM
C++ Inheritance
C++ classes can be composed through inheritance. A derived class inherits the public interface and any implementation provided by the base class.
class baseClass { public: virtual rType operation(); }; class derivedClass : public baseClass { public: };
derivedClass inherits the base member operation() and any implementation that baseClass has provided. derivedClass is free to override virtual operations provided by its base, but is not required to do so.
Introduction to COM
Page 18
C++ classes inherit both interface and implementation of their base classes This reuse helps productivity, but may cause breakage if not done carefully.
C++ deriv ed class implementation is inherited, may be ov erriden client - uses deriv ed class object - has compilation dependency on both base and deriv ed classes public interface - inherits all the base interf ace - may add more - changes to the deriv ed implem. can break base
Introduction to COM
Page 19
A C++ class can provide an interface without providing an implementation if it is constructed as an abstract class, e.g.:
class anAbstrBase { public: int operation( ) = 0; : };
class getsBaseInterface : public anAbstrBase { public: int operation( ); // definition must be provided : // in implementation body so }; // objects can be created
Introduction to COM
Page 20
C++ supports inheritance of interface using abstract base classes. Clients hold a base class (interface) pointer attached to the derived class. Client has no compilation dependence on derived class provided that client does not instantiate the object.
C++ deriv ed class implementation prov ided with no support f rom base class public interface - inherits all the base interf ace - may add more
Introduction to COM
Page 21
If the object can be made to create itself then the compilation dependence is broken.
Introduction to COM
Page 22
base class implements all its member functions derived class inherits most base class members. derived class may override an inherited virtual member function implementation but does not have to do so
Introduction to COM
All COM interfaces must declare the IUnknown methods, usually done by inheriting from IUnknown. All COM objects are required to implement the IUnknown interface along with their own operations.
Introduction to COM
Page 24
Introduction to COM
Symme tric
Re fle xiv e
Transitiv e
IUnknown
IUnknown
IUnknown
A B C
A B C
A B C
Introduction to COM
Page 26
COM objects and their interfaces are identified by Globally Unique Identifiers (GUIDs). These are 128 bit numbers generated by an algorithm based on machine identity and date. COM requires that interfaces are immutable. That is, once an interface is published it will never change. A component may change its implementation, removing latent errors or improving performance, but interface syntax and semantics must be fixed. Components may add new functionality, expressed by additional interfaces, but the component must continue to support its orig-inal interface set.
Introduction to COM
Page 27
A COM class object is a component that creates new instances of other objects. Class objects implement the IClassFactory interface and are called class factories. IClassFactory interface has two methods:
CreateInstance accepts an interface identity number and returns a pointer, if successful, to a new component object. LockServer turns on, or off, locking of the factorys server in memory.
COM instantiates factories using a global or static member function provided by the factory code:
DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv)
Introduction to COM
Page 28
Introduction to COM
interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface
IPersistStorage ILockBytes IEnumFORMATETC IEnumSTATDATA IRootStorage IAdviseSink IAdviseSink2 IDataObject IDataAdviseHolder IMessageFilter IRpcChannelBuffer IRpcChannelBuffer2 IRpcChannelBuffer3 IRpcProxyBuffer IRpcStubBuffer IPSFactoryBuffer IChannelHook IPropertyStorage IPropertySetStorage IEnumSTATPROPSTG IEnumSTATPROPSETSTG IClientSecurity
interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface interface
IServerSecurity IClassActivator IRpcOptions IComBinding IFillLockBytes IProgressNotify ILayoutStorage ISurrogate IGlobalInterfaceTable IDirectWriterLock ISynchronize ISynchronizeMutex IAsyncSetup ICancelMethodCalls IAsyncManager IWaitMultiple ISynchronizeEvent IUrlMon IClassAccess IClassRefresh IEnumPackage IEnumClass IClassAdmin
Introduction to COM
Page 30
Introduction to COM
Page 31
Introduction to COM
Page 32
In the diagram on the next page we show a COM component presenting interface2, derived from interface1, to a client. Because interface2 is derived from interface1 the client has access to all the functions in both interfaces.
The implementation of these interfaces, the C++ derived class, uses a second COM component, exposing interface3, to help implement its functionality. The client is unaware of the presence of the second COM component.
Introduction to COM
Page 33
Diagram here
pulic interface definition of protocol no implementation client - only know s interface protocol - has no compilation dependence on implementation COM interface2 pulic interface definition of protocol no implementation COM interface3 pulic interface definition of protocol no implementation
COM interface1
C++ derived class im plem entation provided w ith no support from base class public interface - inherits all the base interface - may add more C++ derived class im plem entation provided w ith no support from base class public interface - inherits all the base interface - may add more
Introduction to COM
Page 34
A Concrete Example
In the diagram on the next page, we show a COM component that implements two interfaces, IX and IY. The client gets a pointer to IUnknown from COMs CoCreateInstance function. That pointer can only be used to access the three IUnknown functions, QueryInterface, AddRef, and Release. The client uses QueryInterface to get a pointer to one of the interfaces, say IX. That pointer can only be used to access the functions exposed by IX, in this case just the function Fx().
Introduction to COM
Page 35
struct IUnknown
virtual Hresult QueryInterface(...) = 0; virtual ULONG AddRef( ) = 0; virtual ULONG Release( ) = 0;
struct IX
virtual void Fx( ) = 0;
struct IY
virtual void Fy( ) = 0;
Class CA Attribute: long m_cRef; Operation: CA( ) ~CA( ); virtual HRESULT QueryInterface(...); virtual ULONG AddRef( ); virtual ULONG Release( ); virtual void FX( ); virtual void Fy( );
pIUnknown
client
pIX
pointers pIunknown, pIX, and pIY can be declared using only declarations for Iunknown, IX, and IY
pIY
Introduction to COM
Page 36
Vtable Layout
On the next page, you see a diagram that illustrates how the C++ interfaces connect to the code that implements them. The IUnknown pointer points to a table of function pointers called the vtable (for virtual function pointer table). It can only access the QueryInterface, AddRef, and Release functions. QueryInterface returns, using the casts shown in the diagram, a pointer to the requested interface, either IX or IY, or NULL if the request cant be satisfied.
Introduction to COM
Page 37
Vtable
reinterpret_cast<IUnknown*>(CA::this) CA::this
CA object in data space CA class virtual function pointer table - only one per class
static_cast<IX*>(CA::this)
IX vtbl pointer
AddRef
AddRef
IY vtbl pointer
Release
Release
long m_cRef;
Fx
Fx
static_cast<IY*>(CA::this)
QueryInterface Fy
AddRef
static_cast<IY*>(CA::this) static_cast provides conversions from the source type (CA::this) to the target type <IY*> It creates a new object of the target type. reinterpret_cast<IUnknown*>(CA::this) reinterpret_cast interprets the same bit pattern as belonging to a different type No new object is created.
Release
Fy
Introduction to COM
Page 38
Reusing Implementations
There are a lot of existing interfaces that we want to use without having to re-implement them. How do we do that? C++ has four mechanisms for reuse:
inheritance of implementation (ruled out by COM due to concerns about software reliability) composition, e.g, using objects of existing classes as data members of the class being implemented Aggregation, e.g., create and use object of existing classes in a member function. templates, shown by the Standard C++ Library to be very powerful
Introduction to COM
Page 39
C++ supports reuse through composition. Composing classes use object members to help implement their interfaces through delegation. Client has no compilation dependence on either implementation class.
C++ deriv ed class implementation prov ided with no support f rom base class public interface - inherits all the base interf ace - may add more
C++ aggregated class implementation may by used by aggregating class thru my public interf ace public interface not giv en to clients of aggregating class
Introduction to COM
Page 40
C++ uses templates to reuse existing designs. A template-based class uses a generic parameter, say T, as if it were a defined type. When instantiated with a specific existing class the compiler substitutes the classs source. Note that this is not binary composition.
class T
Introduction to COM
Page 41
COM defines component containment which has semantics of C++ aggregation but can be composed at run time. With containment the reusing COM object loads an existing component and implements part of its own interface by delegating calls to the contained component.
outer component
IX
IY
inner component
IZ
Introduction to COM
Page 42
Implementing Containment
Client:
no special provisions.
Inner Component:
no special provisions
Introduction to COM
Page 43
What COM chose to define as aggregation is unfortunately quite different than C++ aggregation. With COM aggregation the aggregating class forwards interface of the reused existing class to the client by delivering a pointer to the aggregated interface.
This complicates implementation of the inner IUnknown since the usual COM policy for interfaces must still be carried out.` The result is that, in order to be aggregate-able a component must implement two IUnknown interfaces
Introduction to COM
Page 44
COM Aggregation
outer component
inner component
Delegating IUnknown implementation
Introduction to COM
Page 45
Signaling aggregation:
CoCreateInstance() and IClassFactory::CreateInstance() both have a parameter: Iunknown* pUnknownOuter. If this pointer is null the created object will not be aggregated. If An outer component wants to aggregate an inner component it passes its own IUnknown interface pointer to the inner.
Implementing IUnknown:
If an aggregatable component is not being aggregated it uses its non-delegating IUnknown implementation in the usual way. If it is being aggregated it uses its delegating IUnknown to forward requests for IUnknown or outer interface to the outer component. Clients never get a pointer to the inner non-delegating IUnknown. When they ask for IUnknown they get a pointer to the outer IUknown.
Introduction to COM
Page 46
Implementing Aggregation
The delegating IUnknown forwards QueryInterface, AddRef, and Release calls to the outer IUnknown. When a client requests an inner interface from an outer interface pointer the outer delegates the query to the inner nondelegating QueryInterface. When CoCreateInstance is called by the outer component it passes its IUnknown pointer to the inner and gets back a pointer to the inner IUnknown. This happens in an init( ) function called by the outers class factory in its CreateInstance function.
Introduction to COM
Page 47
- clients need no knowledge of where components reside - avoid name clashes with other components
- use Remote Procedure Call (RPC) communication and marshalling between processes and machines
- support for distributed architectures, e.g., from OLE linking and embedding to enterprise computing
Introduction to COM
Page 48
Introduction to COM
Page 49
In-Process Components
An inproc component is implemented as a dll which the client loads into its own address space, e.g., becomes part of the client process. The inproc component provides a class factory so COM can create an instance on behalf of the client. Thus the client has no compilation dependency on the component. The component also declares its interfaces, IX and IY, and implements them with the class CA. The component also provides four functions in the dll to support its activities:
Dllmain() simply saves a handle to the process DLLRegisterServer() calls function in Registry module to register comp. DllUnRegisterServer() calls function in Registry module to unregister comp. DllCanUnloadNow() tells come that client is done with dll DllGetClassObject() called by COM to get a pointer to the class factory instance.
Introduction to COM
Page 50
The structure of the inproc component is shown by the architectural diagram on the next page. The diagram shows:
Interfaces, IX and IY, declared by the component class factory and class that implements the interfaces DllGetClassFactory function Registry module (no details) that is responsible for writing the path to the component into the registry. declarations of the interfaces in IFACE.H (no implementation details) used by both client and component. Definitions of constant GUIDs in IFACE.CPP used by both client and component. COM library, exposed by the declarations in objbase.h
Introduction to COM
Page 51
CMPNT.CPP
struct IUnknown
virtual Hresult QueryInterface(...) = 0; virtual ULONG AddRef( ) = 0; virtual ULONG Release( ) = 0;
struct IClassFactory
virtual HRESULT CreateInstance(...) = 0; virtual HRESULT LockServer(...) = 0;
Class CA
Attribute: long m_cRef; Operation: CA( ) ~CA( ); virtual HRESULT QueryInter. virtual ULONG AddRef( ); virtual ULONG Release( ); virtual HRESULT Fx(BSTR bstr); virtual HRESULT Fy(BSTR *pBstr);
Class CFactory
Attribute: long m_cRef; Operation: CFactory( ) ~CFactory( ); virtual HRESULT QueryInterface(...); virtual ULONG AddRef( ); virtual ULONG Release( ); virtual HRESULT CreateInstance(...); virtual HRESULT LockServer(...);
cmpnt.idl
DllGetClassObject(...)
REGISTRY.CPP REGISTRY.H
local object
pFactory
cmpnt.h cmpnt_i.c
objbase.h
main( ) CLIENT.CPP
client needs to know about COM and GUIDS but does not need to know about CMPNT
CoCreateInstance(...)
COM Library
INPROC COMPONENT
DllGetClassObject Creates a Factory to Get Object for Client Client Gets Pointer to Abstract Interface to Invoke Derived Class Function
Introduction to COM
Page 52
The diagram on the next page is a structure chart. It shows calling relationships between functions in the client, server, and COM. In this diagram, callers are always above callees. The diagram shows clearly how the client calls COM to get a pointer to an interface. COM calls DllGetClassObject to create the class factory, then uses the pointer it gets to create an instance of the CA class that implements the interfaces. COM then passes the pointer to the interface back to the client for its use. The client finally calls release to tell COM its done with the component.
Page 53
Introduction to COM
Structure chart
INPROC COMPONENT
client::main
cmpnt::CA Fx
cmpnt::CA Fy
COM Library CoFreeUnusedLibraries COM Library CoGetClassObject cmpnt::CFactory B CreateInstance cmpnt DllCanUnloadNow cmpnt DllGetClassObject cmpnt::CFactory LockServer B A
cmpnt::CFactory CFactory
cmpnt::CFactory QueryInterface
cmpnt::CFactory Release
cmpnt::CA CA
cmpnt::CA QueryInterface
cmpnt::CA Release
cmpnt::CFactory AddRef
cmpnt::CA AddRef
Introduction to COM
Page 54
Activation Diagram
The diagram on the next page is an elaborated event trace diagram. It shows the separate, cooperating actions of the client, COM, and the Component to:
Create the component instance Use it Shut it down
Introduction to COM
Page 55
pIX
pIX
server responds to invocation send and receive data this is a synchronous call
client
COM
inproc server
Introduction to COM
Page 56
Code Samples
You will find a sample of an inproc COM component, written in C++ without using the MFC or ATL libraries in the CSE775/code/inproc_Ex1 directory. This code is illustrated by the Class Diagram, Structure Chart, and Activation diagram on the previous slides. Looking carefully at this code, with these three diagrams close at hand will help you understand the details of how an in-process COM component works.
Introduction to COM
Page 57