The term COM means many different things to many different people. On the one hand, the Component Object Model is a specification for writing reusable software that runs in component-based systems. On the other hand, COM can be thought of as a sophisticated infrastructure that allows clients and objects to communicate across process and host computer boundaries. Many developers who are already COM-savvy see it as a new programming style and a set of disciplines required to work in a Microsoft-centric environment. Business managers and system designers see COM as technology that's solving many of the problems the industry has experienced in maintaining and extending large information systems. COM is all of these things and more.
COM is a model based on binary reuse. This means that software (components) adhering to COM can be reused without any dependencies on source code. Developers can ship their work as binary files without revealing their proprietary algorithms. The reuse of code in a binary form also eliminates many compile-time problems that occur when systems are assembled according to a development style based on source code reuse. Binary reuse makes it far easier to incorporate small changes into a system. For instance, a minor bug fix or a performance modification can be made to a dynamic link library (DLL). The DLL can then be recompiled and replaced in the field without adversely affecting any of the client applications that use it. Systems based on source code reuse must typically recompile every line of code in the entire application. This requirement makes maintaining and extending software cumbersome and expensive.
The principles of binary reuse allow you to construct COM-based applications using language-independent components. When several teams are building components for a single system, each team can choose its programming language independently. Today's list of COM-enabled languages includes C++, Visual Basic, Java, Delphi, and even COBOL. Each team can select a language that matches its programming expertise and that gives it the best mix of flexibility, performance, and productivity. For instance, if one team requires low-level systems code, it can use C++ for the flexibility of the language. Another team writing and extending business logic for the same application can elect to use Visual Basic for its high levels of productivity. The ability to mix and match languages makes it easier for companies to make the best possible use of their existing pools of programming talent.
COM is based on object-oriented programming (OOP). This means that COM is a story about clients communicating with objects. COM exploits the OOP paradigm to achieve higher levels of reuse than is possible with other models of binary reuse. COM clients and COM classes typically live in separate binary files, as shown in Figure 1-1. COM specifies an infrastructure that enables clients to bind to objects at run time.
Figure 1-1. Object-oriented binary code reuse is one of COM's primary reasons for being.
COM is interprocess-capable. This means that clients can create objects in separate processes and on remote computers. Thus COM serves as core technology in Microsoft's strategy for distributed computing. While both OOP and distributed programming have existed for well over a decade, the synergy of the two has produced a powerful new programming paradigm. It has never been easier to write a distributed application.
Of all the COM-enabled development tools on the market, Visual Basic offers the highest levels of productivity. Visual Basic 3 and Visual Basic 4 both offered modest advancements in the product's COM-awareness, but Visual Basic 5 really opened the door to make this development tool a viable option for building components for use in COM-based systems. Visual Basic 6 continues to add to the COM capabilities of this development tool.
Take a moment to consider the following questions. What is your perception of Visual Basic? Does it provide a viable option for writing the code to be used in a large information system? Why are you reading this book? Respond to the following questions by choosing Visual Basic, C++, or Structured Query Language (SQL):
Many designers and project leads answer these questions quickly by saying, "Visual Basic." Visual Basic is in no way a cure-all language. In many cases, C++ or some other language would be a better choice for a specific component. For instance, many system-level COM interfaces can be readily accessed only through C++, which means that some components should be written with C++. However, companies have many opportunities to use Visual Basic in a distributed application. One of the greatest opportunities for Visual Basic today is writing business logic and data access code for distributed objects in the middle tier of a large information system.
Before component-based technologies such as COM were available, large applications were built by sending hundreds or possibly thousands of source files together to a compiler in a single batch job to build one executable file. This development style, with its production of monolithic applications, poses many problems. It requires huge executables and long build times. Furthermore, to take advantage of a modification to a single line of source code, the entire application must be rebuilt. This makes it increasingly difficult to coordinate the various programming teams working together on a large application. Maintaining and enhancing a monolithic application is awkward at best.
Component-based development solves many of the problems associated with monolithic applications. It allows development teams to ship binary files as opposed to source code. Binary components can be updated independently and replaced in the field, making it much easier to maintain and extend an application after it's been put into production. Most people agree that using COM or some other component-based technology is an absolute requirement in the development of a large information system.
Software development for the Windows operating system has always been based on binary reuse. DLLs such as the Win32 API allow a Windows programmer to reuse functions through a C-style call-level interface. Many companies and third-party vendors have also written reusable DLLs for Windows applications using the same technique. However, these C-style DLLs typically don't offer any object-oriented extensions. Standard Windows DLLs are also very difficult to use from higher-level languages such as Visual Basic. Developers at Microsoft knew they needed a technique to facilitate binary reuse with an object-oriented paradigm.
COM was built from the ground up to be object-oriented. It's based on clients, classes, and objects. Classes are defined in binary files called servers. These servers make it possible for clients to create and connect to objects whose code lives in a separate binary file. Figure 1-1 shows the basic relationship between a client and an object served up from a DLL. The beauty of COM is that this model makes it possible for a client to use a class that's defined inside a separate binary file. This, as you will see, is no simple undertaking.
After a client connects to an object, it simply invokes method calls as in any other OOP environment. COM fully supports the object-oriented concepts of encapsulation and polymorphism as means to achieve code reuse. COM, however, doesn't support a form of inheritance known as implementation inheritance. In later chapters, I describe exactly what you lose and what you don't lose with the omission from COM technology of this popular OOP feature.
If code reuse in COM were limited to in-process DLLs, clients would have no way to communicate with objects running in another process or running on another machine. Out-of-process communications would require programmers to use some interprocess communications mechanism such as dynamic data exchange (DDE) or named pipes. Fortunately, COM supports remote method calls across process boundaries. Figure 1-2 shows the relationship between a client and an out-of-process server.
Figure 1-2. COM has the ability to extend client-object communications across process and host boundaries.
Notice that the client code and the object code are actually running in different processes on different machines. COM takes care of establishing an efficient and reliable communications channel between these two parties.
As you'll see, COM not only takes care of many grungy plumbing details in an efficient and reliable manner but does so in a way that's transparent to programmers. COM programming for both clients and objects is the same whether you're dealing with an in-process server or an out-of-process server. This incredibly powerful feature of COM is known as location transparency. All the complicated work of preparing, sending, and receiving network packets is taken care of by the distributed infrastructure of COM. The more you learn about COM, the more you will appreciate this fact.
Today COM is language independent, but many of the original COM design decisions were made to achieve object-oriented binary reuse in a C++ environment. The most profound decision made by Microsoft engineers is that COM needed to formalize the separation of interface from implementation. This means that COM is founded on the idea of interface-based programming.
The concept of interface-based programming wasn't a clever new idea thought of by Microsoft engineers. Instead, it was a programming style that had already been recognized by the academic community of computer science and by organizations that needed to build large, extensible information systems. Interface-based programming was pioneered in languages such as C++ and Smalltalk that have no formal support for the concept of a distinct, stand-alone interface. Today languages and tools such as Java and Visual Basic have built-in support for this style of programming. So while Microsoft can't be given credit for the idea, it should definitely be given credit for seeing the elegance of interface-based programming and using it as the cornerstone of COM.
An interface, like a class, is a distinct data type. It defines a set of public methods without including any implementation. In another sense, an interface defines a very specific protocol for the communications that occur between a client and an object. The act of decoupling the interface from the class or classes that implement it gives COM developers the freedom to do many things that would otherwise be impossible. A developer designing a client application against an interface can avoid creating dependencies on class definitions. This allows for an environment in which several different types of compatible objects can be used in a plug-compatible way. This promotes what is arguably the most powerful feature of OOP: polymorphism.
Interfaces are also the key to COM's ability to send remote method calls across host boundaries. Programmers never need to worry about which platforms or network protocols are involved. It's all taken care of behind the scenes. This condition points to one of the most enlightened observations about COM: Interfaces are the key to seamless object distribution.
The first time COM showed up in a released product was with OLE2 in 1993. OLE1 was based on DDE and was generally unusable in production code for a variety of reasons. Microsoft decided to redesign OLE using an internally-developed protocol for interprocess communications. This new component technology was devised by a group of engineers that had been assembled from various internal development teams at Microsoft.
Today it's safe to say that COM is more significant than OLE, although it's equally safe to say that it's hard to define what OLE and ActiveX really mean. They are umbrella terms for a set of technologies that are based on COM. All these acronyms are confusing because people often say "OLE" or "ActiveX" when they really mean "COM." Much of the early documentation was too relaxed when it used these acronyms. Moreover, the marketing people at Microsoft made things more confusing when they attempted to change OLE from an acronym into a word. After that didn't catch on, they decided to come up with ActiveX, a new, sexier term for the Internet.
It's not just the marketing people who have contributed to the confusion in the terminology. It goes right to the heart of COM itself. For example, the main DLL that exposes COM's core library of functions is named OLE32.dll. Even in the Visual Basic integrated development environment (IDE), when you want to create a new COM DLL or a COM EXE you must select ActiveX DLL or ActiveX EXE as your project type. In the early days, Microsoft was slow to bring the term COM out of the closet. Things have changed. Now people are beginning to use COM correctly in more writings and product documentation, but you still expect some degree of confusion. This book will use the term COM correctly and use those other terms only when absolutely necessary.
From the beginning, COM was designed to extend process boundaries. The earlier releases of COM made this possible only when the client process and the server process were running on a single computer. With the release of Microsoft Windows NT 4, support was added to COM that allowed this interprocess communication to extend computer boundaries. This new wire protocol made it possible to deploy distributed objects in a networked environment as depicted in Figure 1-2. This was a significant milestone in Microsoft's strategy for enterprise computing.
At first, Microsoft struggled to get a marketing term to signify that COM could finally be used in a distributed system. DCOM won out over Network OLE when Windows NT 4 was first shipped in August 1995. Today, however, neither of these terms is in style. Distributed COM is currently the proper term to use when talking about the remoting facilities of COM, although some COM developers think that COM itself is a distributed technology and that the word Distributed in front of COM is redundant.
COM's distributed capabilities are based on an interprocess mechanism known as Remote Procedure Call (RPC). RPC is an industry standard that has matured on many different platforms. Microsoft's implementation is known as MS-RPC. Together COM and RPC have a symbiotic relationship. COM offers RPC an object-oriented feel. RPC offers COM the ability to serve up distributed objects. I'll explain in later chapters how COM leverages RPC to transparently send request and response packets between clients and objects. All the while, clients still invoke methods as usual, as if the objects were very close at hand.
Distributed COM introduces several new requirements that aren't issues when a client and an object run on the same computer. First, Distributed COM must provide an infrastructure for remote object creation and activation. A client must be able to create and use objects that run on computers down the hall or across the country. And with these distributed objects also comes a pressing need for security. COM and Windows NT must provide a robust security layer so that all access to a remote server process is authenticated and authorized. Chapter 8 addresses how these two important requirements are met.