0. Intended Use
OLE (and its Component Object Model) provide a basis for applicationinteroperation in the Microsoft Windows environment.
1. Basic Concepts
Microsoft's OLE provides an application integration framework for MicrosoftWindows. OLE defines the Component Object Model, which specifiesa programming-language-independent binary standard for object implementations(i.e., it specifies what the implementation of the objects has to looklike). Any object conforming to this standard is a legitimate Windows Object,no matter what language is used to implement it. The programming modelis synchronous, based on a "Lightweight Remote Procedure Call"(lightweight because, at least at the moment, the calls are not reallyremote; they are all made on one machine).
In the Component Object Model, the concept of interface assumesgreat importance. An interface is "a set of semantically relatedfunctions implemented on an object" [Bro94a]. The Component ObjectModel uses the word "interface" by itself to refer to the definition(signatures) of those functions. An implementation of an interface is anarray of pointers to functions. Any code that has a pointer to that arraycan call the functions in that interface. A Windows Object implements oneor more interfaces, i.e., provides pointers to function tables for eachsupported interface.
Users of objects always obtain and act through pointers to object interfaces;users never obtain pointers to an entire object. For example, when theuser of some object first obtains a pointer to the object, the user actuallygets a pointer to one of the object's interfaces. This pointer allows theuser to call only the functions in that one interface's function table.Through this pointer, the user has no access to any state of the object,nor does the user have any direct access to functions in other interfaces.
OLE defines a standard function, called QueryInterface, throughwhich the user of one interface of an object can obtain a pointer to anotherinterface of the same object. QueryInterface is part of an interfacecalled IUnknown, which defines a group of fundamental functionsthat all Windows Objects support (thus IUnknown is supported byall objects). All other interfaces in OLE are derived from IUnknown,so all interfaces contain the QueryInterface function. This insuresthat navigation is always possible between the interfaces of a given object.
Using QueryInterface, the user of an object can discover thecapabilities of that object at run-time by asking for pointers to specificinterfaces. This enables an object to implement as many interfaces as itwants. Because all Windows Objects implement at least IUnknown,there is always some basic way for a user to communicate with any object.
The function table that implements an interface is designed to havea layout that is identical to the one generated by many C++ compilers.This layout allows a single indirection (->) on the pointer to callan interface function. However, while this makes the use of C++ to programOLE convenient, this is not a requirement. An object implementation isonly required to provide separate function tables for each supported interface.How these tables are created can differ, depending on the particular languageused. Because neither use or implementation of a Windows Object is dependenton the programming language used, the Component Object Model is referredto as a binary standard. This provides for language independencewithout involving the definition of a separate language (e.g., an InterfaceDefinition Language).
2. Objects
The Component Object Model specifies a programming-language-independentbinary standard for object implementations (i.e., it specifies whatthe implementation of the objects has to look like). Any object conformingto this standard is a legitimate Windows Object, no matter what languageis used to implement it.
Users of objects always obtain and act through pointers to object interfaces.An implementation of an interface is an array of pointers to functions(the functions themselves are implemented by the object). Any code thathas a pointer to that array can call the functions in that interface. AWindows Object implements one or more interfaces, i.e., provides pointersto function tables for each supported interface. Users never obtain pointersto an entire object. For example, when the user of some object first obtainsa pointer to the object, the user actually gets a pointer to one of theobject's interfaces. This pointer allows the user to call only the functionsin that one interface's function table. Through this pointer, the userhas no access to any state of the object, nor does the user have any directaccess to functions in other interfaces.
A Windows Object is any object, in whatever form, that supports at leastone predefined interface, called IUnknown. As part of the IUnknowninterface, OLE defines a standard function, called QueryInterface,through which the user of one interface of an object can obtain a pointerto another interface of the same object. QueryInterface takes asinput a pointer to an interface identifier (IID) for the desired interface,and either returns an error (and a NULL pointer), meaning the object doesnot support the interface, or a valid pointer to the new interface. [Seeentry under 6. Identity, Equality, Copy for a discussion of IIDs.]All other interfaces in OLE are derived from IUnknown, so all interfacescontain the QueryInterface function (the other two functions ofIUnknown are AddRef and Release). This insures thatnavigation is always possible between the interfaces of a given object.
A Windows Object must be able to provide a separate function table foreach interface it supports. The implementation of the IUnknown functionsin each supported interface must be "aware" of the entire object,because they must be able to access all other interfaces in the objectand must be able to affect the object's reference count.
The implementation in the component object library (COMPOBJ.DLL) providesa small number of fundamental API functions that permit creation of whatis called a Component Object, a special type of Windows Object identifiedwith a unique class identifier that associates an object with a particularDLL or EXE in the file system. A Windows Object does not always need tobe structured as a Component Object such that the API functions in COMPOBJ.DLLcan create it. Use of such API functions is merely one way through whichan initial pointer to an object can be obtained.
Unlike C++, where objects are defined using class definitions whichgenerate user-defined types, Windows Objects are defined in terms of theinterfaces they support. Since all objects support at least one interface(IUnknown), all Windows Objects are at least of type IUnknown,and can be treated as being of another type by using a different interface.Because of this mechanism, there is no single user-defined type associatedwith a Windows Object class, as there is with a C++ class. In fact, thereis no specific way to identify a specific object. This is because objectreferences (pointers) in Windows Objects are not references to the objectitself, as in C++, but rather are pointers to one of the object's interfaces.Given a pointer to an interface, the user can access only functions containedin that interface. The user can never have a pointer to the whole object(because there is no direct user-visible concept of "whole object"),so there is no direct access to state, and no concept of "friend"as in C++. Through the IUnknown interface, a user can obtain pointersto other interfaces that the object also supports, but this means obtaininga different pointer that refers (indirectly) to the same object.Each pointer to an interface points to a function table associated withthe object, and each table contains only functions for a specific interface.Because a pointer to a Windows Object always points to a function table,such a pointer can also be used from within programs written in languagesother than C++, such as C or assembly code.
The list of interfaces that an object of a specific class supports isconstant only within a specific object's lifetime, and can vary betweendifferent instances of objects of the same class. It cannot be assumedthat if Object 1 of class X supports a particular set of interfaces, Object2 of class X does as well. (Note that the "class" denotes theapplication providing the object's implementation, not the set of interfaces(type) supported). It also cannot be assumed that if objects of class Xonce supported interface Y, they always will, because the object mightchange later. This provides justification for the QueryInterfacemechanism of dynamically finding out about interfaces. It is always possibleto find out about other interfaces the object supports; thus, if an objectis acquired as an instance of a "superclass", it is possibleto find out what specific "subclass" it is by examining the otherinterfaces at runtime. There is no requirement to always treat an objectas an instance of the type (interface) through which it was originallyacquired.
2.1 operations
Operations resemble standard C++ functions, and are defined as partof interface definitions. Operations are always invoked indirectly, throughinterfaces, as described in the entry under 2. Objects.
2.2 requests
Requests resemble calls to C++ functions. However, functions are alwayscalled indirectly, through interfaces, as described in the entry under2. Objects.
2.3 messages
2.4 specification of behavioral semantics
2.5 methods
Methods in the Component Object Model are essentially equivalent toC++ member functions.
2.6 state
State in the Component Object Model consists of a set of stored valuesessentially equivalent to C++ data members.
2.7 object lifetime
In C++, objects are constructed using the class's constructor function.There are a number of ways to create a Windows Object, but a common wayis to use a class factory object. A class factory object representsa specific class identifier, is obtained by a specific OLE function, andsupports an interface named IClassFactory. The IClassFactoryinterface contains a function named CreateInstance, to which ispassed an identifier of the desired interface to that object. The expressionIClassFactory::CreateInstance is the logical equivalent of C++'snew.
In C++, an object is destroyed by calling the delete operatoron an object pointer (which ultimately causes the object's destructor functionto be called). The corresponding function that frees a Windows Object (andessentially calls its destructor) is a function called Release.This function is part of the IUnknown interface, and is thus presentin every interface. However, calling Release does not necessarilydestroy the object. Internally, the object maintains a count of how manyreferences exist to any of its interfaces. Creating an interface pointerincrements the reference count, whereas Release decrements it. Whenthe count is reduced to zero, the object frees itself, calling its owndestructor.
2.8 behavior/state grouping
The Component Object Model implements a classical object model.
2.9 communication model
The programming model for Windows Objects is synchronous, based on a"Lightweight Remote Procedure Call" (lightweight because, atleast at the moment, the calls are not really remote; they are all madeon one machine). Further development will allow the lightweight RPC tobe replaced by genuine (distributed) RPC.
2.10 events
OLE handles event notifications through an object called an advisesink--that is, an object that absorbs notifications from a source.The advise sink not only handles notifications for data changes, but italso is generally used to detect changes in another compound document object,such as when it is saved, closed, or renamed. Specifically, an object thatis interested in being notified about changes to a specific data objectimplements an object with an IAdviseSink interface, and passes apointer to this interface to the data object using the DAdvise functionof the IDataObject interface (see entry under 9.2 attributes).Whenever its data changes, the data object calls the OnDataChangefunction in the IAdviseSink interface it has been passed. (The IAdviseSinkinterface also contains other notification functions, such as OnRename,OnSave, etc.)
3. Binding
"Binding", meaning the choice of a method to be executed inresponse to a request, is handled by directly calling the object functionidentified in the request. OLE does not support implementation inheritance(see entry under 8. Inheritance and Delegation), so there is nodispatching by searching a class hierarchy. The term "binding"as used in the OLE context has a somewhat different meaning, relating tothe use of a type of object called a moniker in object linking.See entry under 9.6 other.
4. Polymorphism
The Component Object Model is polymorphic in the sense that what appearsto be the same request can be sent to any interface supporting the requestedoperation; the interfaces need not refer to objects of the same class.However, unlike models supporting a "conventional" subtypingmechanism for objects having a single interface, the interfaces in WindowsObjects remain distinct. Through a pointer to a Y interface, the objectcannot be treated as an X, even if the object also has an X interface;instead, the user must explicitly get a pointer to the X interface.
See also entry under 8. Inheritance and Delegation.
5. Encapsulation
Objects may only be accessed through the operations defined in one ofthe object's interfaces. Moreover, given a reference to one interface,only the operations in that interface may be used. Operations in anotherinterface may only be used after first obtaining a reference to that interface.
6. Identity, Equality, Copy
Object references (pointers) in Windows Objects are not references tothe object itself, as in C++, but rather are pointers to one of the object'sinterfaces. In fact, there is no specific way to identify a specific object(i.e., it is only possible to obtain references to interfaces, notwhole objects). Given a pointer to an interface, the user can access onlymember functions contained in that interface. The user can never have apointer to the whole object (because there is no direct user-visible conceptof "whole object"), so there is no direct access to data members,and no concept of "friend" as in C++. Through the IUnknowninterface, a user can obtain pointers to other interfaces that the objectalso supports, but this means obtaining a different pointer thatrefers (indirectly) to the same object. Each pointer to an interface pointsto a function table in the object, and each table contains only memberfunctions for a specific interface. Because a pointer to a Windows Objectalways points to a function table, such a pointer can also be used fromwithin programs written in languages other than C++, such as C or assemblycode.
Every interface is associated with an interface identifier, orIID. An IID is a special case of a universally unique identifier,or UUID. The universally unique identifier is also known as the globallyunique identifier, or GUID. GUIDs are 128-bit values created with aDEFINE_GUID macro. Every interface and object class uses a GUID for identification.As described in the OLE SDK, Microsoft will allocate one or more sets of256 GUIDs for a developer's exclusive use on request. Alternatively, auser with a network card can run a tool UUIDGEN.EXE that will provide aset of 256 GUIDs based on the time of day, the date, and a unique numbercontained in the network card [Bro94a].
OLE defines IIDs for every standard interface along with class identifiers(CLSID) for every standard object class. When a function is called thatasks for an IID or CLSID, what is actually passed is a referenceto an instance of the GUID structure that exists in the process space (usingthe reference types REFIID or REFCLSID). To compare two GUID, IID, or CLSIDvalues for equality, the functions IsEqualGUID, IsEqualIID,and IsEqualCLSID are used. In C++, an overloaded "=="operator can be used.
The QueryInterface function must always behave according to specificrules which, among other things, implement an indirect concept of objectidentity. First, any call to QueryInterface through any interfaceon a given object asking for a pointer to the IUnknown interfacealways returns an identical pointer value. This means that, given two arbitraryinterface pointers, it is possible to determine whether they belong tothe same object by asking each for an IUnknown pointer and comparingthe returned pointer values. If they match, both interface pointers referto the same object. Second, after an object is created, the interfacesit supports are static. If QueryInterface succeeded for a particularinterface at one point in the object's lifetime, an identical call to QueryInterfaceat a later time will also work. (This does not mean that the exact pointervalues returned will be identical, just that the interface is always available).The static set of available interfaces applies to a specific object, notan object class. That is, two objects of the same class might not bothsupport the same interfaces, but during the lifetime of each, the interfacesthey each support will remain static. Finally, as along as an object isin existence, all interface pointers obtained on that object must remainvalid, even if the Release function has been called through thosepointers.
7. Types and Classes
Unlike C++, where objects are defined using class definitions whichgenerate user-defined types, Windows Objects are defined in terms of theinterfaces they support. Since all objects support at least one interface(IUnknown), all Windows Objects are at least of type IUnknown,and can be treated as being of another type by using a different interface.Because of this mechanism, there is no single user-defined type associatedwith a Windows Object class, as there is with a C++ class (examples ofstandard Windows Objects include such things as windows, dialogs, messages,controls, and GDI objects, such as pens, brushes, fonts, and bitmaps).
A Windows Object class is identified as such only through a class ID(a structure called CLSID) that associates an object with a particularDLL or EXE in the file system (e.g., the application that implements theobject). The class ID is stored in a registration database, along withinformation that defines where the object "lives" and characteristicsthat a potential user may wish to know without having to actually instantiatethe object. The registration database is stored in REG.DAT in the Windowsdirectory. Under Windows Objects, a class object represents a specificclass ID, is obtained by a specific OLE API, and supports an interfacecalled IClassFactory. Every component object class (but not all types ofWindows Objects) must have a unique CLSID associated with it in the registrationdatabase (i.e., Windows Objects can exist that do not have defined classesin this sense).
See also entry under 2. Objects.
8. Inheritance and Delegation
Windows Objects and the classes they identify through class identifiershave no notion of implementation inheritance. One Windows Object does notinherit the implementation of another Windows Object. Instead, reuse ofobjects is supported through the containment and aggregationmechanisms. In the Component Object Model, inheritance is simply consideredas a language-specific tool (e.g., in C++) that may be useful for implementingclasses and defining interfaces in that language. The reason given fornot supporting inheritance is that systems built on it must ship all theirsource code in order to be useful [Bro94a]. For example, inheritance cannotbe used to inherit from objects used in the operating system itself, forwhich source code is not available.
In the Component Object Model, both the containment and aggregationmechanisms work by using the implementation of another object. However,the object being used remains entirely self-contained and operates on itsown instance of data. The containing object also works on its own data,and calls the other object as necessary to perform specific functions forwhich it can be passed the data on which to operate.
To implement what corresponds to a subclass Y of a class X using containment,class Y completely contains an X object and implements its own versionof the X interface which it exports to clients. This makes Y a simple userof X, and X need not know about its use within Y. This is useful when Yneeds to override some aspect of X's behavior. Since all external callsgo to the Y implementation first, Y can either override selected behavioror pass the calls directly through to X.
To implement what corresponds to a subclass Y of a class X using aggregation,class Y directly exposes X's interface. This requires that X "know"that its interface is exposed for something other than itself, such thatthe QueryInterface, AddRef, and Release functionsbehave as a user expects (e.g., X's QueryInterface function mustbe capable of returning references to interfaces implemented by Y which,as a part of an X interface, it did not originally know about; OLE providesa mechanism for dealing with this when an aggregate is created).
Windows Objects do support a specific case of interface inheritance,in that all other interfaces derive from IUnknown, as describedin the entry under 2. Objects. Generally, however, unlike modelssupporting a "conventional" subtyping mechanism for objects havinga single interface, the interfaces in Windows Objects remain distinct.Through a pointer to a Y interface, the object cannot be treated as anX, even if the object also has an X interface; instead, the user must explicitlyget a pointer to the X interface.
C++ multiple inheritance is a convenient way to provide multiple functiontables for each interface, since the compiler generates them automatically.Because each implementation of a C++ member function is already part ofthe object class, each automatically has access to everything in the object.[Bro94a] also discusses a more general approach to constructing objects,for use by programmers in C and other languages that do not provide built-ininheritance. In this approach, a C++ object class corresponding to theWindows Object class inherits from IUnknown, and implements thesefunctions to control the object as a whole. Each interface supported bythe object is then implemented in a separate C++ class that singly inheritsfrom the interface it is implementing. These "interface implementations"are instantiated with the object, and live as long as the object lives.The IUnknown members of these interface implementations always delegateto some other IUnknown implementation, which in most cases is theoverall object's IUnknown. Each interface implementation also holdsa "back pointer" to the object in which the implementations arecontained so that they are able to access information centrally storedin the object. In C++, this generally requires that each interface implementationclass be a friend of the object class.
9. Noteworthy Objects
9.1 relationships
9.2 attributes
As described in the entry under 2. Objects, Windows Objects areaccessed through interfaces consisting of sets of functions. Windows Objectsthat include "data" to be made available to users can be definedwith a special interface for accessing that data. Specifically, a dataobject is a Windows Object that provides a standard data transfer interfacecalled IDataObject. IDataObject includes, among other things,functions for getting and setting data (GetData, SetData,GetDataHere), for querying the ability of the object to providedata in specific formats (QueryGetData), and for notifying clientsof the data when the data changes in various ways(DAdvise, DUnadvise).
9.3 literals
9.4 containment
See entry under 8. Inheritance and Delegation.
9.5 aggregates
See entry under 8. Inheritance and Delegation.
9.6 other
The use of the object linking supported by OLE can introduce problemsin maintaining referential integrity. Specifically, since the data referencedby linked objects lives in a separate file on the file system, links areeasily broken when the end user manually changes the location of that file...Tosolve most of the link breakage problems as well as to provide for arbitrarilydeep object nestings, OLE uses a type of object called a moniker.
A simple moniker contains some reference to a linked object and containscode that knows how to "bind" to that linked object. Bindingis the process of launching the application that handles the class of thelinked object, asking the application to load a file in which the objectlives, then asking the application to resolve the name of the object downto an object pointer.
A file moniker is used to store either an absolute or relative pathname.A linked object maintains an absolute moniker and a relative moniker. Ifit fails to locate the file with the absolute, it tries the relative moniker.Complex object references are described using composite monikers that aresequences of any other simple or composite monikers. Most links can beexpressed in a composite of one file moniker and one item moniker, i.e.,a link to an embedded object (the item) in a container document (the file).The item name is only meaningful to the application that created it. Thatapplication will be asked later to return a pointer to the object identifiedby the item name...An example of a composite moniker might be one thatcontains a file (a spreadsheet) and an item moniker (a cell reference).
Editor's note: For the benefit of you word origin fans, a "moniker"(or "monica") was originally a nickname taken by a hobo (oneof Jack London's was "Skysail Jack"). Later the term became usedcolloquially to mean any form of name for a person, including an alias,or his or her real name.
10. Extensibility
10.1 Dynamic
10.2 Metaclasses/Metaobject Protocol
10.3 Introspection
11. Object Languages
The Component Object Model specifies a programming-language-independentbinary standard for object implementations (i.e., it specifies whatthe implementation of the objects has to look like). Any object conformingto this standard is a legitimate Windows Object, no matter what languageis used to implement it.
12. Semantics of Base Classes (+ type constructors)
13. Background and References
[Bro94a] K. Brockschmidt, Inside OLE 2, Microsoft Press, Redmond,1994.
[Bro94b] K. Brockschmidt, "OLE 2.0 Part I: Windows Objects andthe Component Object Model", Microsoft Systems Journal, Aug.1993.
[Bro94c] K. Brockschmidt, "OLE 2.0 Part II: Implementing a SimpleWindows Object Using Either C or C++", Microsoft Systems Journal,Sept. 1993.
features matrixintro page