The Benefits of COM

 < Free Open Study > 



As noted, a COM-compliant object has a number of appealing traits. The following is a brief description of numerous COM benefits, which will be fully discussed throughout this book. Hopefully after reading this section, you will agree that COM is a very good thing indeed.

COM is Language Independent

COM is not a programming language. In fact, COM components may be written in any number of them. Although this book focuses on the use of C++ and ATL (a C++ COM template library), developers can create COM objects in C, Visual Basic, Delphi, Java, Visual FoxPro, COBOL, and so on. The only true requirement a language must satisfy in order to build COM-based solutions is that it is able to generate the binary layout (vTable) of a COM object.

Not only can developers build COM objects in any language, but the objects themselves may be accessed from any COM-enabled language. For example, you may have a team of hotshot C++ developers accessing COM objects written with Java. Web developers may use VBScript to access COM objects written in Delphi. COM encapsulates the inner implementation details of an object, including which language it was written in. All the COM object user sees is a set of well-defined interfaces supported by the object.

COM Provides Location Transparency

Before we can understand location transparency, we need to add three key concepts to our COM lexicon. COM objects and COM object users may be physically arranged in one of three ways. The "distance" between the two can be determined with help from the following terms:

  • Process: In Win32 programming, a process can be defined as a partition of memory containing a running application (i.e., an active main thread) along with any necessary system resources or external binaries required by the application.

  • Client:  In COM, we define a client to be any piece of software using a COM object. In previous chapters of this book, we referred to the client as the "object user." From here on out, let's stick to the term "client."

  • Server:  In COM, we define the server to be a binary package (DLL or EXE) containing any number of COM objects. Typically, a single server is the home to many related COM objects, each one supporting any number of interfaces.

Keep in mind that the distinction between a client and server can become blurred just a bit. It is very possible (and quite common) for a client to use a server, which is itself a client to another server! Consider an application composed of a Visual Basic (VB) client making use of a COM-based DLL. Here, the VB front end is the client, while the DLL is playing the role of the server. Now, what if this DLL COM server makes use of another COM-based DLL to help get its work done? In this case the original DLL is a client to the second DLL, as illustrated in Figure 3-1:

click to expand
Figure 3-1: Client and server relationships.

With these key terms in place (process, client, and server), we are now able to distinguish between the three possible relationships a client and server may have:

  • An in-process relationship.

  • An out-of-process relationship.

  • A remote relationship.

Understanding the In-Process Relationship

This relationship is also abbreviated in-proc. In-proc servers are loaded into the same memory partition (process) as the client they are servicing. The key benefit of in-process relationships is speed. Clients may access the functionality of an in-proc server just about as quickly as making a local function call, as the client and object are communicating directly through interface pointers.

The biggest drawback of in-proc servers is their low level of fault tolerance (robustness). If a bug exists in the server, and that bug is hit, the entire process is taken down—client and all. Another potential problem with in-process servers is they always take on the security context of the client they are loaded into.

Figure 3-2 illustrates the in-process relationship:

click to expand
Figure 3-2: The in-process relationship.

Note 

If a client and in-proc server reside in different threading models, a direct interface connection is not achieved (more on this in Chapter 7).

Understanding the Out-of-Process Relationship

This relationship is also termed the local relationship. Here, the client and server are on the same physical machine but are loaded into two distinct memory partitions (processes), each with their own security context. One benefit of this relationship is a higher level of robustness. This time, if a bug shows up in the server, and this crashes the server's process, the client is still up and running. As long as that client has intelligent error handling on its end, its process is safe.

The down side of local servers is speed, as information from one process must be packaged, sent, and unpackaged between process boundaries. While COM will generally take care of this on your behalf (through a technique called universal marshaling), this process is time consuming.

Here is a representation of a local client/server relationship:

As shown in Figure 3-3, COM uses Lightweight Remote Procedure Calls (LRPC) to send information between COM components on the same machine but in different processes. LRPC is a proprietary communication protocol used under the hood by the COM runtime. In the local relationship, the client and server do not communicate directly with each other, but instead transmit data between stubs and proxies. As far as the client is concerned, the proxy is the COM object and can program against it as if it was in-process.

click to expand
Figure 3-3: The local (out-of-process) relationship.

We will examine the inner workings of stubs and proxies later in Chapter 5. For the time being, just make a mental note that stubs and proxies are used whenever there is a local COM relationship.

Understanding the Remote Relationship

A remote server physically resides on a separate machine from the client. This is a core requirement of any enterprise-based solution, where user services, business rules, and data retrieval objects may be placed on any number of networked machines. Remote servers are the slowest of all possible COM client/server relationships, as not only do we need to marshal data between processes through stubs and proxies, but we must be aware of bandwidth and latency issues as well (sorry, COM cannot encapsulate you from the laws of physics). Remote communication is established through the Distributed COM (DCOM) protocol, which uses Remote Procedure Calls (RPCs) to forward information between machines.

The remote relationship may be diagrammed as such:

click to expand
Figure 3-4: The remote relationship.

It is interesting to note that remote (or local) COM objects may be housed in either DLL or EXE servers. Legacy COM-based DLLs may be remoted using a special DLL surrogate utility named dllhost.exe (provided with NT SP 2.0 and greater). EXE server types were the "classic" way to remote a server, and at times this might still prove a decent solution, especially where small in-house LANs are involved.

Note 

Of course, the new contender in the world of enterprise COM development is Microsoft Transaction Server (MTS). MTS is a "super surrogate," which will host (only) COM-based DLLs, and take care of the gory details of threading concurrency, atomic transactions, and so on.

Now then, back to location transparency! This benefit of COM states that the client-side code used to access the interfaces of a COM object need not change based on the server's physical location. Stubs and proxies provide a level of encapsulation, as the client is able to treat the proxy object as the "real object" and program against it as if the object itself were in its own process. Likewise, the COM object believes the stub is the "real client," leaving the server code unaltered.

The promise of location transparency does not mean your code could never change. The COM library does provide a number of methods and data structures to help optimize remote access. But these are optional. Using configuration utilities such as dcomcnfg.exe, you may redirect your client to access a server on any machine on the network without altering a single line of code.

These utilities and library extensions provide a far cleaner approach than we had before location transparency. At that time, developers needed to use different (and unrelated) APIs to move information between in-proc, local, and remote servers. As a COM developer, you do not write different code bases for client access to remote objects, local objects, or in-proc objects. Clients just see interfaces, and location transparency allows that client to be blissfully unaware of the exact location of the server.

COM is Object Oriented

OK now, relax. I am sure many of you have been told that COM is not as object oriented as it "could be." Recall from our review of OOP that every OO-based language must contend with encapsulation, polymorphism, and inheritance. Let's see how COM itself deals with these pillars of object technology:

  • Encapsulation: COM provides very deep encapsulation of implementation details. First off, the only way a client may access a COM object's functionality is through an interface pointer. Given your knowledge of interfaces thus far, I think you see why this already provides encapsulation services. Now, on top of that, COM clients are working with the objects contained in the server at a binary level. Unless you want to disassemble the server and read some hex, you are really encapsulated from the details.

  • Polymorphism:  Again, as we have seen from our examination of interface-based programming, the interface allows any number of objects to implement the same interface in its own unique way (as we saw in the Shapes lab of Chapter 2). COM provides ad hoc polymorphism via the interface.

  • Inheritance:  If you read the above section on polymorphism carefully, you should guess by now that COM does not support classical inheritance of binary objects. In other words, you cannot say that "COM object A derives from COM object B." Now be careful here. We most certainly can use interface inheritance when we are creating the objects in a server (for example, C3DRect used interface inheritance to bring in the definitions of IDraw and IShapeEdit). What we cannot do with COM is something along the lines of the following:

    // This is not possible in COM. // Assume BLOB is a new keyword that defines a new binary COM object. BLOB MyServer.NewBlob.EXE : public MyOtherServer.OldBlob.DLL {      ... };

COM Containment and Aggregation

We can, however, reuse behaviors (a.k.a. interfaces) across binary COM objects via containment and aggregation. The key reason COM does not support classical inheritance is to allow objects to be as self-sufficient as possible. When using classical inheritance, if anything changes in a base class, the subclass has the potential of breaking. Given that a base class in COM would be a binary server containing any number of COM objects, how would we understand what to change in our derived class? COM sidesteps these complexities altogether by avoiding classical inheritance.

We do, however, have binary reuse in COM, using containment and delegation. A COM object may create and use other COM objects, allowing access to the inner object's interfaces via delegation. Clients are unaware that the outer object is composed of other inner objects. This is very much like the code-based containment we saw in our OO review; however, this time the outer class builds any inner objects with the COM library. Figure 3-5 illustrates the notion of containment and delegation. Notice that CoHotRod is an "outer class" that creates and maintains an "inner class" named CoCar. CoHotRod supports the IDrive interface, which has methods that forward calls to the inner object.

click to expand
Figure 3-5: CoCar is contained by CoHotRod.

COM does offer another form of binary reuse, called aggregation. Here a COM object creates inner COM objects (just like the containment/delegation model). This time, however, the outer object directly extends its own set of interfaces with the interfaces of the inner objects. This gives clients the illusion that the object they are working with is composed of more interfaces than it really is, as shown in Figure 3-6.

click to expand
Figure 3-6: CoHotRod exposing the inner object’s interfaces as its own.

In aggregation, the outer object does not "forward" calls via delegation, as the inner object's interfaces are directly exposed as part of the outer object. We will detail the implementation of COM containment and aggregation later in Chapter 8, so we will hold off on the specifics for now.

COM Provides Clean Versioning of Components

We have seen that interfaces may be safely versioned by using interface inheritance. COM uses these same versioning techniques. As we have already seen, when an object implements a given interface, it may not alter that interface in any way or else it risks breaking clients. The COM interface is the key to robust versioning.



 < Free Open Study > 



Developer's Workshop to COM and ATL 3.0
Developers Workshop to COM and ATL 3.0
ISBN: 1556227043
EAN: 2147483647
Year: 2000
Pages: 171

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net