Distributed OLE promises cross-platform remote capabilities for linking component software
Keith Pleas
For Microsoft, OLE is the foundation not only of component software but also of future releases of Windows itself. OLE serves as a programming model for and provides access to key Windows services, such as memory management, structured storage, and data transfer. In the future, new services--including visual controls, multimedia services, data-access services, name services, and distributed security--will be available only through OLE. As object-based capabilities become more prevalent, the distinction between applications and the system will start to disappear. Ultimately, the operating system itself will become a collection of replaceable components. OLE is the ``glue'' that will
bind these objects together.
By mid-1995, a more capable version of OLE, called Distributed OLE, will appear on the scene. Today, OLE objects may run in the same process as in-process servers and OLE Controls or in another process, such as a separate executable file like Microsoft Excel. Under Distributed OLE, objects will be able to run on another machine via a newly defined flavor of RPC (remote procedure call). For in-process servers, this will mean greater efficiency, tighter control, and fewer concurrency problems. For executable files, Distributed OLE will bring improvements in process security while permitting objects to use existing code. Over a network, the whole programming model will change, and things such as shared specialized object servers will become possible. Such servers will have the ability to store graphic images that require literally hundreds of megabytes of memory to render, objects that require particular hardware (e.g., digital signal processors, or DSPs), or databases that re
quire specialized connectivity. (See the text box ``Cairo Takes OLE to New Levels.'')
OLE Technology
Underlying OLE is COM (Component Object Model), the language that OLE speaks. It doesn't impose any restrictions on applications or say anything about how they're designed (see ``Componentware,'' May BYTE). Rather, COM facilitates interoperability between OLE components, including (in the future) those running on remote machines. OLE itself embodies the object services--such as visual editing, structured storage, and object conversion--that the system provides to facilitate COM interactions.
Component objects are exposed through interfaces, each of which is a group of closely related member functions. A component object can have any number of interfaces, each providing a well-defined service. All interface names begin with an I. IDropSource and IDropTarget, for instance, handle a drag-and-drop function in OLE documents, IDispatch controls OLE automation, and IOleControl and IOleControlSite
are responsible for the recently defined OLE controls. OLE handles communications between the interfaces.
The essential component object interface is IUnknown; all objects must support it and its three base member functions: QueryInterface, which is used to obtain pointers to interfaces, and AddRef and Release, which are used for reference counting over an object's lifetime. All other COM interfaces are derived from IUnknown. They are not inherited, which has myriad religious object-oriented connotations, because interfaces are independent of implementation. Their purpose is to enable interface pointers that shield the component object. These pointers are 128-bit integers that are virtually guaranteed to be globally unique, even in networks with millions of objects.
The separation of interface and implementation lets you replace or modify the code for a particular implementation without making any changes in the objects and systems that call into it. You can also add new interfaces without break
ing existing applications, which is what component software is all about. Clients see only interfaces; what exists behind the interfaces is opaque, even though the internal representations may be handled as if they were true objects. Put another way, what you think of as a Worksheet object in Microsoft Excel does not, in fact, exist. Rather, it's a useful abstraction. Excel supports a set of interfaces to something that it calls a Worksheet. How Excel manages that Worksheet is something only those inside Microsoft will ever know.
Monikers and Binding
So, the minimum COM object is very lightweight. This is fortunate, because COM objects are used for virtually everything in OLE. A perfect example of this is the OLE naming object called a moniker, which implements the IMoniker interface. Monikers are used for the names of link objects that the system recognizes. They are more efficient at representing data than, for instance, filenames, although, for convenience, monikers can use the GetDisplayName
member function of IMoniker to generate a text-display name readable by humans. Human-readable names are stored locally to prevent problems with name collisions over a network.
The basic purpose of a moniker is to bind an object to a discrete piece of data. What's returned is an interface pointer to the linked object. When it's asked to render itself, the object can go through that interface pointer to ask for an updated presentation. A moniker, and thus its pointer, can be stored persistently; the object is activated and bound only when it's required. When activated, a moniker uses the ROT (Running Object Table), described later, to locate existing instances of the object. Indirectly, through the Service Control Manager, monikers may also use registry information to instantiate objects if they are not present in the system.
Distributed OLE offers three main types of monikers: file monikers, item monikers, and composite monikers. A file moniker can identify any object that is stored as an indivi
dual file and act as a wrapper for the path name that the native file system assigns to the file. For example, C:\DATA\BUDGET.XLS might be the file moniker for an Excel workbook object stored as a file on disk. Calling the BindToObject member function for this moniker would launch Excel (if it weren't already running), load this workbook, and return a pointer to it. Binding can have a significant impact on your system.
Item monikers identify an object contained within another object. The exact format varies by application and the corresponding nature of the application's data, but an Excel example might be Sheet1!A1:D20. A composite moniker is composed of two or more monikers, concatenated. For example, a composite moniker could be constructed from the above file and item monikers. You can see the human-readable version of a composite moniker such as this when you create a linked item (e.g., Copy...Paste Link); the moniker is embedded into the linked item. A composite moniker is bound in right-to-left
order, which avoids unnecessarily activating objects if a pointer to an intermediate-level object already exists. In contrast, activation--the act of running an object to perform an operation--generally occurs in left-to-right order.
To bind a moniker, the link source must be running. To handle this efficiently, OLE maintains yet another COM object, the ROT that implements the IRunningObjectTable interface. If an object doesn't register itself in the ROT when it starts running, extra copies of the object might be loaded if other objects try to bind to it. This would lead to consistency problems and, ultimately, to the loss of data. The ROT is local to a desktop and maintains a list of all objects running on that machine. In a Distributed OLE environment, which lets you bind objects on remote machines, the ROT becomes more of an abstraction.
Common Object Model
Microsoft and DEC have defined a specification, called the Common Object Model, for making the two company's object systems interop
erate (to avoid confusion with Component Object Model, whose acronym is also COM, I will spell out references to Common Object Model). In defining the specification, Microsoft contributes a subset of its OLE technology, and DEC supplies its ObjectBroker product for implementing UDT (uniform data transfer) by using minor extensions to the OSF-sponsored (Open Software Foundation) DCE (Distributed Computing Environment) RPC system. UDT uses the IDataObject interface, which encapsulates the various methods for exchanging data between applications. Current methods include using the Clipboard, drag and drop, and OLE Automation. This particular RPC implementation is called ORPC (Component Object RPC).
Prior to the creation of the Microsoft/DEC specification, Microsoft developed an equivalent RPC version for doing networked RPC (but not networked OLE RPC) under Windows NT. This implementation was called Microsoft RPC, and this name still appears in the Win32 SDK (Software Development Kit) and in Microsoft pres
entations at developer conferences.
Obviously, to take advantage of support for distributed OLE, a remote machine must support OLE. That support is already available in PCs running the 16- or 32-bit version of Windows and on the Macintosh (680x0 and Power Mac), and Microsoft is licensing its OLE source code to Unix vendors. When OLE support becomes available on Unix systems, the Microsoft/DEC Common Object Model will provide a means of fostering enterprise-wide cooperation--across networks and across platforms--between OLE applications and objects. Existing local-based OLE applications should get this capability without additional programming, because all objects appear local.
The system-level code that implements the Common Object Model functions is called the Common Object Model Library. It handles the creation of Common Object Model applications and the specialized objects required for distributed object support. The Common Object Model Library also encapsulates the channels over which the ne
twork RPC takes place. The system-level code that handles the actual transmission is the RPC run-time library, which runs in both the client and server processes (see the figure ``Architecture for RPC Under Distributed OLE'').
Each machine has an SCM (Service Control Manager). The SCM is an RPC server that acts as the central point for object activation. It ensures that a server is started in response to a client request. To do this, it must maintain the ROT and a local cache of system-registry class information for use by the Common Object Model Library.
The SCM controls the type of an object server: in-process, cross-process (local), and distributed cross-process. If the requested server is an in-process DLL, the SCM passes the request to the Common Object Model Library for loading. When a local (on the same machine) cross-process request arises, the SCM passes the request to the server if it's already running or creates the server process if it isn't. For a remote cross-process request, the S
CM forwards the request to the SCM on the server (see the figure ``SCM and Distributed OLE'').
Marshaling
Before you can make an RPC, you need one more fundamental piece of OLE technology: marshaling, a method for packaging the function calls and parameters, passing them across the process boundary, and unpackaging them at the other end. Marshaling takes care of details like how each of the possible parameter types is passed. Marshaling also converts data into a binary stream format and packages it for RPC transmission, using Network Data Representation to make differences such as byte ordering and character sets compatible.
Two types of marshaling for interface pointers exist: standard and custom. A server object has to support one or the other but may not support both. Standard marshaling support is provided for all the standard COM interfaces; the support proxies and stubs are loaded from OLEPRX32.DLL, and the server does not implement the IMarshal interface. Custom marshaling handles
a particular set of circumstances. Monikers, for example, require marshaling by value, so a copy of the server object is created in the client process and changes made to it are not reflected in the server. Custom marshaling is also required when memory is shared--when the name of the memory segment is passed to the client. Compound files are marshaled in this way. Custom marshaling requires implementing custom proxies and stubs for the server object (see the figure ``Distributed OLE Architecture'').
Proxy and Stub
Crossing a process boundary or machine boundary for distributed-object RPCs involves a process called interface remoting. To permit you to cross boundaries transparently, proxy and stub objects translate local procedure calls into remote procedure calls.
The proxy runs in the client process, between the client and the server object. It supports identical interfaces, called interface proxies--one proxy per interface--as the server object, though their implementation differs. As i
ts name suggests, a proxy's function is to marshal (package) the interface parameters for its server interfaces and pass that package via an RPC (using the RPC run-time libraries) across the network to the server object. There, the package is unmarshaled.
These steps are transparent to the client. The stub, the counterpart of the proxy on the server, unmarshals the server interface calls. It runs in the server process and is similar to the proxy in that it provides an encapsulation of the server's interfaces (as with a proxy, each interface is allocated one stub).
MIDL
Because C data types may be different sizes on different systems, a special-purpose C-like language and compiler are required to generate the data types and declare statements used in an RPC. The DCE calls this the IDL (Interface Definition Language), and Microsoft's particular implementation is called, not surprisingly, MIDL.
Microsoft-specific changes to standard IDL support custom Common Object Model interfaces to
handle object references, string bindings, reference counting, path resolution, new object creation, and object activation. The MIDL compiler creates code for talking to the RPC run-time library for each interface definition: proxy/stub code, header files, and an interface identifier file. The proxy/stub DLLs, which must be installed in the system registry, are built from these files.
Distributed Security
The security of objects and the data they encapsulate is a matter of concern in any object system. In distributed systems, security is more important than it is for local systems, where it is often taken for granted. OLE offers relatively limited security; when multiple clients are accessing one server, a separate instance is run for each client. So, each client/server connection, and thus the data being transmitted, is isolated from that of other client/server connections.
Distributed OLE will provide improved security through the connection ORPC offers to DCE. These services are accesse
d by applications through the Common Object Model Library, which checks flags in the system registry to control where a server can be run. Object servers may run where the client is running, where the data is stored, or elsewhere on the network.
In distributed object systems built on DCE (e.g., ORPC), authenticated RPC and DCE Security Services provide security. Under authenticated RPC, DCE automatically contacts the Security Server to obtain authentication for the client in the form of a Privilege Attribute Certificate, which contains identity and group membership information. The protocol for authentication is based on the industry standard Kerberos 5 authentication system developed at MIT.
Open Tools
To alleviate concerns about OLE being too proprietary, Microsoft has made it part of WOSA (Windows Open Services Architecture), whose stated goal is providing ``an open environment for the development and use of Windows-based applications.'' WOSA components include common application servic
es (Open Database Connectivity, MAPI, the Telephony API, and Licensing Service API); communication services (Systems Network Architecture, Windows Sockets, and Microsoft RPC); and WOSA extensions for vertical markets (Financial Services and Real-Time Market Data). Microsoft has also licensed OLE source code to several vendors, including Locus Computing (Inglewood, CA), MainSoft (Sunnyvale, CA), and Insignia Solutions (Mountain View, CA). These companies will provide OLE capabilities on diverse Unix platforms.
Ultimately, however, the success of OLE--distributed or not--depends on more than Microsoft's willingness to maintain an open-door policy. One important factor is the quality of the tools available for creating new applications. (Distributed OLE promises to eliminate the need for changing existing OLE applications.) After all, applications are only as good as the tools used to create the objects. Right now, your choices in tools for creating server applications boil down to just one product: Micro
soft Visual C++ 2.0.
Despite its advertised openness and language independence, for most developers OLE will be approachable only if it's encapsulated in a framework like Microsoft Foundation Classes. Implementing this encapsulation is such an enormous and expanding undertaking--volumes 1 and 2 of the OLE2 Programmer's Reference total more than 1200 pages and don't even include OLE Controls--that eventually all C++ tool vendors will probably license the code from Microsoft. As extensions are added to OLE, though, it's a safe bet that Microsoft tools will be the first to provide access to those services.
In the component software world that is just emerging, high-level integration languages play an important role, too. To create and use OLE objects, a programming language must create structures of pointers and explicitly or implicitly call functions through those pointers. Microsoft's Visual Basic, for instance, can do this. It manages the pointers internally and provides high-level mapping betwe
en language objects and OLE objects.
However, just as using a framework today is no substitute for understanding the Windows API, no encapsulation will completely eliminate the need to understand the OLE equivalent: the assorted OLE interfaces. Developers investing in OLE development today will be well positioned for the ``OLE Everywhere'' of tomorrow's distributed OLE environment.
Figure: Architecture for RPC Under Distributed OLE
This diagram gives an overview of the system architecture of the RPC portion of Distributed OLE. Note that CLIENT.EXE talks only to the proxy; it is unaware that the server functions are being handled remotely by another machine. All components other than the client and server executables are based on OSF's DCE RPC.
Figure: SCM and Distributed OLE
The SCM plays an important role in the Distributed Object RPC architecture. Note that each machine has an SCM, which manages that machine's ROT (Running Object Table) and a local cache of system-reg
istry class information for use by the Common Object Model Library.
Figure: Distributed OLE Architecture
This diagram shows where OLE integrates with Distributed Object RPC. OLE is isolated from network operations.
Keith Pleas is a developer and consultant living in Bellevue, Washington. You can reach him on the Internet or BIX c/o
editors@bix.com
.