Notes on OLE and CORBA

Dinesh Katiyar
katiyar@eng.sun.com


These notes present a comparison between OLE and CORBA in regards to the set of features they provide for developing distributed systems. It focuses on the technical aspects of these frameworks only. The comparison is provided from a developer perspective, and is categorized by the provisions in the two systems for expressiveness in the object models, and support for the development of servers and clients. A few other sundry areas are covered as well.

OLE is an object technology coming out of Microsoft. OLE was once an acronym for Object Linking and Embedding since it was originally meant to support compound documents. The framework is based on COM (Component Object Model), and will eventually support distribution.

CORBA stands for the Common Object Request Broker Architecture - a specification for distributed software systems published by the OMG (Object Management Group) consortium.

This comparison breaks up the developers' view of distributed object systems into the following categories:

  • expressiveness of the object model
  • support for developing objects that are distributable (writing servers)
  • support for using distributed objects (writing clients)
  • A bunch of miscellaneous criteria are also bunched together in the last section.


    INDEX

    The Object Models
    Writing Servers : defining a distributable object
      Defining the interface of an object and identifying such interfaces
      Defining an operation on an object
      Implementing an object in a given implementation language
      Providing means for creating an object
      Making an object uniquely identifiable and testing for object equality
      Making a local object distributable
      Controlling the concurrent behavior of objects
      Controlling the lifetime behavior of objects and object implementations
      Making objects persistent
      Providing support for implementations with no static type information
      Reusing code (implementation inheritance)
      Reporting abnormal behavior (support for exceptions etc.)
      Allowing callback style interaction from servers to clients
      Memory management
      Object server evolution
      Cross-platform support
    Writing Clients : using a distributable object
      Locating a distributable object
      Using a distributable object remotely vs. using it locally
      Writing a client in the same language as the server vs. in a different language
      Making operation invocations without static type information
    Miscellaneous
    

    1. The Object Models

      Let us first look at a top-level view of the underlying object models in OLE and in the CORBA spec. Several details will be left for a closer look in the upcoming sections.

      OLE

      The object model for OLE is called COM (Component Object Model). COM provides a language-independent binary standard for object implementations. This standard is based on the view that an object implements a set of functions, subsets of which provide a coherent "view" of the object. Such subsets are called "interfaces" and an object implements one or more interfaces.

      An implementation of an interface is an array of pointers to functions. Users always access COM objects through such interfaces, and not through some pointer to the entire object. This structure is at the heart of the binary standard of COM. In principle, this avoids the need for a separate interface definition language. This is also the reason that COM does not support multiple inheritance of interfaces.

      Each interface is assigned a GUID (globally unique identifier) - these can be created using some provided software, or through Microsoft. The software version uses the timestamp, a random number and the network address of the machine to generate the GUID.

      Each object supports the IUnknown interface at least - the methods in this interface allow:

    2. users to get handles on other "views" of the object (basically get a pointer to other interfaces that object supports) - this is the QueryInterface method. Note that one has to provide the GUID of the interface one is searching for. So essentially, one can only ask "do you support this interface?" and not "tell me which interfaces you support." (There is a notion of type libraries that permits the second kind of query.)
    3. lifetime control through refcounts - these are the Addref and Release methods
    4. Each COM object also has a class. Objects of the same class implement the same interfaces. But two COM objects implementing the same interfaces needn't be of the same class.

      Objects are implemented in servers, and these can be of three kinds -- in-process, local or remote (the last is not yet supported). An implementation registers itself by providing a unique class id, the type of server, and the location of the server's binary.

      Objects can be given persistent names called monikers which can also be made smart about initializing or restoring persistent information in the object. There is a notion of connectable objects which permits objects to establish a two-way dialogue with their users.

      CORBA

      The CORBA object model revolves around the idea that objects are encapsulated entities that provide one or more services that can be requested by clients in a language-independent way. Thus objects are servers.

      Objects are denoted by object references (or objrefs for short). An object may be denoted by multiple distinct objrefs. Objrefs can be "stringified" transformed into strings). Given such a string form, one can get back the original objref and make requests to it. Objrefs have duplicate and release operations that can be used to implement reference counting, as well as a is_a method that can be used for maintaining runtime type safety if desired. There is also an is_equivalent operation that takes another objref and returns true for cases where it can be determined that the two objrefs denote the same object.

      Clients access services by issuing requests which contain information about the target object (the object reference), the operation, the parameters for the operation (if any) and an optional request context. These requests can be made through pre-compiled stubs or through a dynamic invocation mechanism. Requests cause a service to be performed. If an abnormal condition occurs, an exception can be returned. A request made by a client using an objref is conveyed to the corresponding object implementation by the ORB (Object Request Broker).

      The set of possible operations that a client may request of an object is determined by its interface. Interfaces are defined in OMG IDL (Interface Definition Language). IDL permits the declaration of modules, interfaces, exceptions, constants and typedefs. Modules are a scoping mechanism. Interfaces can contain declarations for attributes and operations in addition to typedefs, constants and exceptions. Interfaces can also inherit from one or more other interfaces (name conflicts in such cases are not permitted). An ORB doesn't necessarily need the IDL definitions for its operation, or any type information for that matter. In practice though, type information is made available either through IDL interfaces, or stub routines or entries in the interface repository.

      Language mappings define how to access objects through the ORB using a particular language. A mapping includes a definition of the IDL declarations into data types and procedures of that language, the structure of stubs and skeletons, the dynamic invocation interface, the object adapters and the interface to the ORB. A language mapping can also define the interaction between object invocations and thread of control in the client or the implementation.

      An ORB provides its services through one or more object adaptors. An object adaptor provides for the creation and interpretation of objrefs, implementation activation/deactivation, registration of implementations, etc. Different object adaptors can qbe used to target the specific needs of sets of implementations (database adaptor, high security adaptor, etc.).

      CORBA specifies an interface repository as a way of presenting type information at runtime, and an implementation repository as a way for an ORB to locate and activate object implementations.

      The CORBAServices specification defines a whole set of interfaces and objects that support some basic services crucial to the building of distributed applications. These include services such as naming, relationships, properties, life cycle, transactions, security, etc. Some of these services are still in the process of being standardized. The CORBAFacilities specification will define higher-level non-critical functionalities such as an electronic mail service.

      Comments:
    5. The basic objects models in OLE and CORBA are fairly similar. The most significant difference is perhaps the fact that COM gives up on multiple inheritance to provide a binary standard for object implementations. (Note that these two could co-exist if COM was willing to use operation dispatch by name instead of by offset). COM instead provides the notion of an object being a set of interface pointers, one for each interface it supports. This also allows for some flexible forms of programming. CORBA sticks to permitting multiple inheritance and the associated transparence to users of an object implementing several interfaces.

    6. Writing Servers : defining a distributable object

      This section looks at the various aspects of building a distributed service and how the frameworks in question support these activities.

      1. Defining the interface of an object and identifying such interfaces

        The framework must provide a way of defining the services that an object supports. This description is typically all that is needed by clients about the object, other than perhaps a way to find its location, to be able to make requests. One must also be able to identify such interfaces and distinguish between similar looking interfaces intended for different object implementations.

        OLE

        One can use the IDL (Interface Definition Language) that is defined in OLE to describe one's interfaces. This derives from and is a superset of DCE IDL.

        OLE's interfaces support inheritance but not multiple inheritance. The restriction has to do with the binary standard for object implementations that the object model defines. However, objects can implement multiple interfaces, and an interface pointer to any particular interface can be obtained through the QueryInterface operation all objects must implement.

        The MIDL (Microsoft IDL) compiler can take IDL definitions and generate the header files that are needed to permit use of the objects being defined. However, it is not necessary to use IDL - there are other ways of conveying the type information contained in IDL definitions to the framework, such as type libraries.

        Interfaces are identified by interface identifiers, which are created by running a function called CoCreateGuid that generates a 128-bit GUID (globally unique identifier). To create this globally unique identifier, the function uses the current date and time, an incremental counter, a random number generated using a clock sequence, and a machine identifier that is either obtained from the network card or created.

        CORBA

        OMG IDL is the interface definition language used in CORBA. It allows one to define modules, interfaces, type definitions, constants and exceptions. Interfaces contain attributes and operations. An interfaces can inherit from one or more other interfaces.

        Interfaces, from a user perspective, are identified by their fully scoped names (the scoping being provided by the names of modules, interfaces, structures, unions, operations and exceptions). However, since this isn't good enough to maintain global uniqueness, CORBA defines the notion of a repository identifier which uniquely identifies a type definition. The repository identifier is usually computed using the fully scoped name as well as some localization prefix, but can be user specified as well -- DCE UUID format ids are also permitted.

        Comments:
      2. CORBA seems to do a better job of hiding from the user issues related to global name conflicts, without having to rely on a function that must be used to generate unique ids.
      3. Defining an operation on an object

        Frameworks must provide expressive mechanisms to describe the operations one can request from an object.

        OLE

        Operations in OLE can have in, out and inout arguments, but are only permitted a 32-bit result (HRESULT or SCODE). This includes a one bit success/failure field and a 15-bit facility field that Microsoft has the exclusive rights to define. The remaining 16 bits can be used to code any other information.

        CORBA

        The parameters to operations can have any of the following modes - in, out and inout. Operations have a return value of any legal kind and can also specify exceptions that might be thrown in case of abnormal behavior. Operations also have an optional context argument that can be used for operation-specific information that might affect its performance. Operations can also be declared oneway if they are meant to be invoked asynchronously (the client does not block on such calls, and the implementation cannot return any values). Furthermore the semantics are "best effort", with no guarantee that the operation will have been executed.

        Attributes are a convenient way of defining a pair of get and set operations in an interface.

        Comments:
      4. CORBA provides for a richer set of operation specifications than COM.
      5. Microsoft's exclusive right to the facility field in the return code of operations is something to be wary about.
      6. Implementing an object in a given implementation language

        One must be able to implement objects in the language of one's choice, and users should be allowed to invoke operations on objects in a reasonably language-independent manner. This is achieved through language mappings of the object model and the operations needed to use it.

        OLE

        OLE currently provides support for implementing objects in C++ and C. For the latter, users have to generate the structure that roughly corresponds to the vtable implementation of the corresponding interface. The OLE automation service makes it easy for users to hook in other languages as clients of OLE objects.

        CORBA

        The CORBA specification has defined mappings for C++, C and Smalltalk. Other mappings are still being worked on. The mappings define the language representation of OMG IDL data types, operations, exceptions, and signatures of operations to access the ORB related functionality. CORBA also specifies the dynamic invocation interface which makes it easy for object invocations to be made from almost any language without a large effort.

        Comments:
      7. OLE is yet to prove itself outside the C++/C realm. OLE automation is a help for scripting languages but it remains to be seen whether other programming languages will be folded in, and if so, how easy the process will be.
      8. CORBA's notion of language mappings is fairly formal and well-defined, and support for a new language is more a matter of consensus than technical difficulty.
      9. The fact that CORBA has defined language mappings for both a statically typed language such as C++ and a dynamic language such as Smalltalk demonstrates the flexibility of the framework and its independence from any particular linguistic bias (inspite of its original C/C++ bias).
      10. Providing means for creating an object

        A distributed framework must have operations for creating objects and associating implementations with them.

        OLE

        An OLE object is simply an implementation of the binary standard specified by COM, and the user can generate this in any way (s)he chooses to. However, OLE provides some prescribed forms of object creation.

        OLE defines the IClassFactory interface with the CreateInstance operation. If an object implements this interface, it can be used to create instances of the objects for which it is a factory. (There also exists an IClassFactory2 interface that includes operations to permit licensed creation of objects).

        If one has the class identifier, one can use the CoGetClassObject function to get its IClassFactory interface and then use that to create objects.

        If one needs to create only one instance of an object, one can use the CoCreateInstance function that takes a class identifier and generates an instance.

        CORBA

        There is no standard way yet defined in CORBA for creating objects, and various vendors are providing their own mechanism for now. The lifecycle service illustrates a generic way of defining factories which can then be used to create objects, although it doesn't specify how factories should be found. The naming service provides a popular way of finding objects, given a name for that object. Once a user has an object reference, the reference can be stringified, passed around, etc. and will continue to access the same object (during its lifetime).

        Comments:
      11. The presence of the IClassFactory2 interface (which permits licensed creation of objects) is a sign of the fact that OLE is maturing for use in large scale applications. However, CORBA's security service specification that is yet to be released, will attempt to provide a general framework to solve this and several other problems related to controlled access to resources.
      12. The need for portability of server code is well known to the OMG and they are in the process of standardizing several of the issues related to the creation of objects. This is certainly one area where CORBA is currently weak.
      13. Making an object uniquely identifiable and testing for object equality

        There must be provisions to identify objects, distinguish them from others, and recognize aliases to the same object.

        OLE

        Typically objects are created using one of the prescribed creation techniques, and the QueryInterface operation is used to get a handle on other interfaces that are implemented by the object. A common way of locating objects is through monikers which are themselves objects that encapsulate a name (that can be used instead of the object) and the intelligence to locate the object, restore its persistent state

        In OLE, object identity can be checked by using the QueryInterface operation to get the pointer to each objects IUnknown interface and comparing for equality on the pointer values returned.

        CORBA

        Objects in CORBA are identified through object references. These object references can be externalized (persistified) into strings which can then be converted back into an objref. A popular way of making objects available is by registering them in the naming service and allowing clients to use a name to locate the object

        An ORB provides the is_equivalent operation on object references which takes an objref as an argument and returns true if the ORB can determine equality of the object references. However, the failure of this test does not necessarily indicate that the object references refer to different objects.

        Comments:
      14. Monikers in OLE provide functionality that in the CORBA world is split across the naming service and the server persistence support.
      15. It is not quite clear how OLE's test for object equality will scale to a distributed system - how does one compare pointers to the IUnknown interface across systems?
      16. Equality testing for distributed objects is simply hard (and when possible, expensive), which is why CORBA only mandates a partial implementation of it.
      17. Making a local object distributable

        Frameworks could provide ways of making local implementations accessible to remote clients. It is of interest to see how much effort is required in making an object remotely accessible.

        OLE

        For existing C++ applications, OLE makes it quite easy to make them act as OLE objects. This is because the binary standard for object implementations is chosen to be almost identical to that chosen by most C++ compilers. Users do not have to necessarily create IDL definitions to specify the interfaces. Hence, the effort involved here is quite minimal.

        For C applications, the effort involved is significantly larger since, amongst other things, the user has to provide the vtable style data structures for their implementations.

        CORBA

        While CORBA does not mandate the presence of IDL interfaces for all objects, one does require stub/skeleton code to support static invocations and runtime type information (through the interface repository) to support dynamic invocations. Whether or not this can be done directly from the existing components in a specific language isn't mandated by the CORBA spec but is left to vendors.

        Comments:
      18. The support for legacy code is an area that CORBA seems weak in. Most vendors provide their own ways of alleviating this problem.
      19. It seems that using OLE with C is a big nightmare in practice.
      20. Controlling the concurrent behavior of objects

        Support for multithreaded applications is becoming quite relevant with multitasking machines.

        OLE

        Microsoft does not guarantee thread-safety for any of its interfaces, and hence does not support multi-threaded code. Threads can be used for user-written code known to be thread-safe.

        CORBA

        The CORBA specification does not require nor preclude multithread support in servers.

        Comments:
      21. Even though CORBA does not mandate it, having a single-threaded ORB would be quite hazardous given that any malicious/buggy object implementation can cause it to hang.
      22. OLE is supposed to become threadsafe in Windows95 and Windows NT 3.51.
      23. Controlling the lifetime behavior of objects and object implementations

        Objects should be easy to create and destroy. Similarly, object implementations should be easy to activate and deactivate.

        OLE

        The creation of objects has been dealt with earlier. The lifetime of objects is maintained through the AddRef and Release operations that are defined on all COM objects. These do reference counting on the objects and delete objects when the reference count goes down to zero.

        Object implementations are provided either as local executables (.EXE files) or as dynamically loaded libraries (.DLL files). Local servers terminate themselves when no longer in use. However, dlls have to be explicitly freed through the CoFreeUnusedLibraries function that in turn calls DllCanUnloadNow on all the dlls not in use.

        CORBA

        CORBA also provides for duplicate and release operations on object references that implement reference counting on the object. The lifetime behavior of servers is unspecified and left to individual implementations.

        Comments:
      24. Having implementations typically available as both DLLs and EXEs in COM provides gain in efficiency at the cost of some transparency.
      25. Making objects persistent

        It is critical for object implementations to be able to preserve state across invocations and far-apart activations. Also, it is critical to provide some form of atomicity in updating such persistent information to maintain the integrity of the system.

        OLE

        OLE has the concept of structured storage - this is a notion of "nested files" arising from the need to support compound documents. A file can have discrete components that can either be storages or streams. Storages are like directories and streams are like files. So storages can contain other storages and streams, while one can read from and write to a stream. For persistence, an object can chose to implement any one of the standard interfaces IPersistFile, IPersistStream and IPersistStorage. This include operations for transaction-style updates that the user is required to provide.

        CORBA

        The CORBA persistence service is yet to be standardized. However, ORBs are required to provide persistence for object references.

        Comments:
      26. OLE simply defines the persistence APIs that objects should implement if they wish to be persistent. There is no notion of transparent persistence.
      27. OLE's structured storage will apparently get OS-level support in Cairo.
      28. Providing support for implementations with no static type information

        Sometimes, one needs to be able to provide implementations for objects without having static type information about their interfaces. This is needed to support dynamically typed languages as well as activities such as debugging or instrumenting that need to transparently interpose themselves between client invocations and object implementations. This also allows one to support multiple dispatch systems (where an implementation of an operation is chosen not just based on the receiver but on the arguments as well).

        OLE

        While there is no direct support for this in OLE, it can be essentially done by implementing all of the objects functionality through the IDispatch interface. The IDispatch::invoke operation, instead of delegating to actual operations, can directly interpose the desired implementation of the various functions.

        CORBA

        CORBA specifies the dynamic skeleton interface (DSI) which allows objects to be implemented using a dynamic implementation routine. This routine gets the entire request context, including the operation name and arguments, and can implement the operation the way it desires.

        Comments:
      29. Here, we are talking only about the object implementation itself. Being able to invoke on an object without type information is a separate issue that is dealt with in the next section that deals with writing clients.
      30. Reusing code (implementation inheritance)

        It is convenient to be able to reuse existing implementations to define new ones.

        OLE

        OLE does not provide any notion of implementation inheritance since it is believed that one rarely shares code across distribution boundaries, especially in a world where products do not ship with source code. Instead, OLE provides two models of implementation reuse - containment and aggregation.

        In the containment model, one object uses an instance of another in its implementation and provides a its own version of the contained object's interface to users. It can control which calls go through to the contained objects and which calls it wishes to handle on its own. This is useful to override some aspects of an object's behavior.

        In the aggregation model, the outer object directly exposes the interface of the inner object. In this case, the inner object must know that it is part of a larger object, since, for instance, the operations in the IUnknown interface must now behave as though they belong to the outer object.

        CORBA

        CORBA does not require or preclude implementation inheritance - it is left to vendors to provide such facilities for languages in which it is possible.

      31. Reporting abnormal behavior (support for exceptions etc.)

        It is important to be able to convey to a client when an object implementation is unable to perform the requested service.

        OLE

        All operations have a 32 bit HRESULT return code which contains a single bit success/failure field and a 15-bit facility field that Microsoft has the exclusive rights to define. The remaining 16 bits can be used to code any other information about the operation's behavior.

        CORBA

        Operations can throw exceptions, which are user-defined structures. For languages that don't support exceptions, these are typically mapped to an extra environment argument passed to each operation, and on completion of the operation, clients can check this variable through a standard set of operations for abnormal behavior.

        The CORBA specification also defines a large set of system exceptions that can typically occur.

        Comments:
      32. The lack of support for exceptions in OLE is one of its biggest drawbacks.
      33. Allowing callback style interaction from servers to clients

        Occasionally, one wants the server object to be able to get information from the client during the execution of an operation or send it notifications or requests. The generic way to do this would require the user to implement the client as a server of some sort as well, but this is quite an overhead. Hence, it is useful to provide a simple way of interaction directed from the server towards the client.

        OLE

        OLE provides what it calls connectable objects which define outgoing interfaces. These outgoing interfaces define operations that represent notifications and requests. To be connectable, an object implementation must implement the IConnectionPointContainer interface. Using this interface, a client can get a connection point. The client specifies a sink object that the server can invoke on when it needs to make a notification or request. The sink implements the outgoing interface of the server object that the client is interested in. Sinks can implement several outgoing interfaces and can be used to be notified from various servers.

        CORBA

        Amongst the OMG specified CORBA services is an event service that implements event channels. Both servers and clients can take either of the roles that the service defines - those of a consumer or a producer. The channels support both the push and the pull model, permitting the channel participants to decide who initiates the event communication. A client can become a push supplier or a pull consumer quite easily (other modes require it to provide the implementation of some operations, and hence force it into becoming a server), and this stylized use of the event service provides a notification and callback service between servers and clients.

        The events service itself is much more elaborate, and permits blocking and non-blocking style event pulling, fan-in and fan-out of event flow, typed event communication (where suppliers can call operations on consumers through some mutually-agreed interface), etc.

        Comments:
      34. The OLE model of interaction between servers and clients requires servers to implement specific interfaces. The CORBA model permits the choice of such interaction to be made completely independently of the object's interface.
      35. Memory management

        This is always a hard task, and any help provided by the frameworks is welcome.

        OLE

        Every COM object has to support the AddRef and Release calls. Clients must invoke Addref whenever a new interface pointer is created, and Release when the pointer is destroyed (including when it goes out of scope). The object's lifetime is controlled by the refcount on all of the interfaces it supports. Since objects are permitted to use interface reference counting, these calls must be matched through the same interface pointer.

        For parameters in operations, in parameters must be allocated and freed by the caller, out parameters must be allocated by the function (even in the case of failure) and freed by the caller, and inout parameters must be allocated and freed by the caller but might be freed and reallocated by the function in between.

        COM provides a task memory allocation service that is available to objects and clients, and which is what makes it possible to hand memory across processes.

        CORBA

        Every object supports the duplicate and release operations which are used to do reference counting on the object.

        The memory allocation for parameters to operations is a function of the language mapping.

        Comments:
      36. OLE and CORBA do not mandate atomicity for reference counting operations - something necessary in a multithreaded environment (what if an object gets released and destroyed after a client got an interface pointer but before the client could increase the reference count?). Vendors would have to provide "smart pointers".
      37. Object server evolution

        Another point of interest is how frameworks permit the evolution of object implementations.

        OLE

        OLE supports a binary standard of object implementations. Thus, a newer implementation can replace an existing one only if it does not change the binary layout of the function pointer structure. However, more usefully, a new implementation can choose to support new interfaces - such evolution can be made without requiring client code to change.

        CORBA

        The OMG is working on a change management service that will define the sorts of evolution that ORBs will be required to support. Currently, the only tacit implication is that as long as the IDL interface of a server does not change, clients need not be concerned. The change management service will also define which sorts of changes clients should be able to overlook, and will also define a versioning policy for both interfaces and implementations.

        Comments:
      38. Still a lot to be done on this front in all frameworks.
      39. Cross-platform support

        Most applications in the modern world need to span multiple architectures, besides multiple languages.

        OLE

        OLE currently runs on Windows (3.1, 95 and NT 3.51).

        CORBA

        The CORBA specification does not make any assumptions about hardware or operating system support and is thus implementable on practically any platform.

        Comments:
      40. OLE's immense installed base for Windows is pitted against multiplatform and interoperable ORBs. The homogeneity of the Windows world will permit for a simpler model of shrink-wrapped off-the-shelf binary components for OLE while CORBA with its standard wire formats will allow for applications spanning heterogenous computing environments, but will only have a more segmented market for binary components.


    7. Writing Clients : using a distributable object

      This section reviews the facilities provided for developing clients of objects. Although several of these capabilities have been alluded to in the previous section, we look at them in a new categorization of functionalities here.

      1. Locating a distributable object

        Clients must have a simple and effective way of locating the objects they wish to use.

        OLE

        In OLE, clients either create objects or are handed objects through operation calls. To create an object, one either needs another instance of that class (so that one can get to the object factory and create another object) or one needs the universal class and interface identifiers of the required object. One can find these through the registry functionality.

        CORBA

        Objects are identified through object references. These are created by the ORB and are made available to clients through the naming service or through operation invocations. Object references can also be externalized into strings, and passed around or saved to files where other clients can read them and get a hold of the original objref and make invocations on it. Most applications would either look for the required object reference by doing a lookup in the naming service, or by reading a persistified form of the object reference. Factories are simply CORBA objects as well.

        Comments:
      2. OLE does not provide for persistified references to objects.
      3. CORBA still needs to work on standardizing object creation.
      4. The naming service in CORBA provides a neat model for registering and locating services.
      5. Using a distributable object remotely vs. using it locally

        This section reviews how the frameworks distinguish between the case when the object being used is in fact a remote object and when its a local one.

        OLE

        OLE supports two notions of local servers - in-process and out-of-process servers. The former are implemented as dynamically linked libraries, and the latter as executable files. Clients have to be aware of this difference since amongst other things, dlls have to be unlinked when done. Often, both kinds of implementations will be provided, and clients can choose between them.

        OLE currently doesn't support remote objects, and hence it is difficult to comment on all the overheads involved. However, OLE does define and provide standard marshalling for objects. Objects can also choose to implement their own marshalling by supporting the IMarshal interface. The advantages of customized marshalling are that users need only compile in marshalling code if its to be used, and can also marshall just the relevant information (which could be something as trivial as a pointer into shared memory instead of a full blown state description).

        CORBA

        CORBA attempts to make remote objects appear identical to local ones, and hence does not mandate any operations that might go against this philosophy. All marshalling/unmarshalling is completely hidden from clients, and local objects have to be accessed the same way as remote ones (i.e. through objrefs) and so on.

        Comments:
      6. A clean abstraction over object location is good, but almost all application developers will want hooks to be able to have finer control on the way object invocations are done, so that they can optimize local and remote behavior for their particular application's need and deployment. While OLE does not provide significant support for this, it still seems to be much ahead in the game than most ORB products are today.
      7. Writing a client in the same language as the server vs. in a different language

        Frameworks have to balance between making it easy for same-language client-server operations without making it too hard to do invocations across language boundaries.

        OLE

        Currently OLE only supports C and C++, while OLE automation is used to hook in client-side capabilities in other languages. For calls from C++ clients to C++ servers on the same machine, OLE provides fast access, since the server layout is identical to that of a C++ class, and the client can choose the dynamically linkable implementation of the server in most cases. However, same-language calls across a network will be unable to take advantage of this. Cross-language calls typically require one to understand the binary implementation standard of COM.

        CORBA

        CORBA attempts to make all implementations available to clients in a language-independent manner, and hence does not mandate any operations that make same-language calls any easier than cross-language ones.

        Comments:
      8. OLE seems to have a bit of an advantage here, in that many application developers will want to be able to optimize their applications to speed up same-language calls.
      9. Making operation invocations without static type information (run time type support)

        Occasionally, one needs to be able to use objects for which one does not have compiled type information. One large class of applications that need such support are those that integrate the facilities of the distributed system with easy-to-use scripting languages.

        OLE

        OLE provides the notion of a type library and dynamic invocations. Type libraries contain class descriptions, interface descriptions, dispatch interfaces (dispinterface) descriptions, module descriptions, and type definitions. These elements have attached attributes that allow one to locate associated help information, besides versions and simple documentation strings. One can use the basic CreateTypeLib APIs to create a type library, or one can use ODL (the Object Description Language) to describe the types, and use the MKTYPLIB tool to generate the corresponding type library. Tools such as the ClassWizard in Visual C++ generates ODL descriptions from C++ class headers.

        Objects that wish to be able to provide type information to clients must implement the IProvideClassInfo interface. Clients can also use the class id to get type information from the registry entries, in which case they don't need an instance of the class to get type information about it.

        Clients can invoke operations through the IDispatch interface. Using the available type information, clients can query the object to find out the dispatch identifiers for various operations, and once it has these, it can call the IDispatch::invoke operation, giving it the dispatch id for whichever operation it wishes to invoke. Arguments are passed as an array of VARIANTARG structures. A VARIANTARG is essentially a union type that can hold any of the basic types in OLE. To pass non-standard data structures, they have to be mapped to these simpler types.

        CORBA

        CORBA defines an IFR (Interface Repository) which makes runtime type information available to clients - all objects implement a get_interface operation. The IFR has several operations defined on it that permit users to load it with type information.

        CORBA also defines the dynamic invocation interface (DII) which allows clients to invoke operations on objrefs without having access to compiled stubs for the interface of that object.This is done through the create_request operation on objrefs which creates a CORBA::Request object. This is filled with information about the operation and the arguments (arguments are wrapped in Anys which contain a type and a value of that type). Clients can then make an invocation by calling the invoke operation on Requests. Operations can also be invoked asynchronously using the DII, so that clients can carry on until they need to access the response from the invocation.

        Using the IFR and the DII, clients can make typesafe calls on objects without having access to compiled stubs for the object.

        Comments:
      10. OLE's design efforts for dynamic invocation support was driven by its Visual Basic supporters.
      11. OLE's ODL is very similar but not identical to it's IDL - Microsoft is trying to merge them into one language.
      12. Microsoft reserves rights to all negative dispids.


    8. Miscellaneous

      This section looks at some other aspects of the frameworks that did not fit cleanly into the categorization chosen for this exposition, but that are relevant and interesting nonetheless.

      OLE

    9. Environment support : One of the biggest factors in OLE is the support that it is getting and is expected to get from available tools and even from the operating system. Current Visual C++ programming environments make it easy to integrate OLE objects. Structured storage is expected to become the native file system in Cairo. OLE automation provides a natural framework for hooking in OLE objects into another language's development environment. OLE controls define a way for independently developed applications to be "OLE-enabled". All of this gives OLE a very visible prominence that is critical to its widespread acceptance.

    10. Support for compound documents : Not surprising, OLE provides several interfaces that are meant to support useful functionalities for compound documents, such as notification between objects, property sheets on objects that can be "edited" through notifications, the notion of data sources and targets and the associated support for drag-and-drop, support for viewable objects and image caching and in-place activation (visual editing) of embedded objects amongst others.

    11. OLE controls : OLE has a formal definition of a control which can be readily used as part of other applications. An OLE control is simply an OLE object that supports persistence, embedding, in-place activation, automation, outgoing interfaces, property pages, and keyboard mnemonics. This is achieved by implementing a fixed set of interfaces besides the IOleControl interface. There is also a notion of a control container which again implements a fixed set of interfaces along with the IOleControlSite interface.

    12. Component licensing support : OLE factories can implement the IClassFactory2 interface which makes object creation go through only if some licensing criteria are met. The interface has some minimal licensing API support that makes it possible to implement such controlled factories.

    13. CORBA

    14. Object adaptors : An object adaptor defines the interface that object implementations use to access the services provided by an ORB. An ORB can target different groups of object implementations by providing several object adaptors, each providing a customized view of method invocation, object activation/deactivation, security, generation and interpretation of object references, etc. Vendors have only begun to implement generic object adaptors, but as this technology matures, one will see more and more specific object adaptors and correspondingly better support for developing object implementations that will use a specific adaptor.

    15. Interoperability between ORBS : OMG has defined an interoperability standard for ORBs, which essentially means that vendors will be able to generate object invocation requests or responses in a standardized on-the-wire format. Thus, as vendors make this a part of their ORBs, one will be able to make object invocations almost seamlessly across ORBs.

    16. CORBA services and facilities : The OMG has already defined a set of services that implement properties, relationships, naming, events, object lifecycles, etc. and is in the process of standardizing others that address topics such as security, transactions and change management amongst others. The OMG will also publish standards for facilities such as electronic messaging in the future.

    17. Design by consortia : While the OMG design process has been slow, it must be admitted that the outcome has stood well to scrutiny so far. The fact that several services have been successfully standardized bodes well for firstly the expressiveness and stability of the CORBA core technology, and secondly for the OMG process itself. Also, as the OMG gets into standardizing more and more specialized technologies, its vast membership will certainly provide some of the foremost experts in each of those areas, allowing the design process to utilize the experiences of these frontrunners.


    Disclaimer : The views expressed here are solely my own and do not reflect any opinions of my employer.