VB6 Programmer's Introduction to COM

by James Limm

VB6 Programmer's Introduction to COM Check out the latest essential read from Thomas Lewis and Wrox Press! This top tome teaches you the ins and outs of the Microsoft Component Object Model, and explains the part it plays in all of today's technologies, including ActiveX and OLE.

The Microsoft Component Object Model, lovingly referred to as COM, is probably the most mysterious acronym yet to come from our friends in Redmond. Speak with any Visual Basic programmer and ask them a very simple question: What is COM?

  • "It is the glue for Microsoft applications."
  • "It lets you create components."
  • "It allows software objects to talk to other software objects."
  • "It is a standard for components."
  • "I don't know, I just work here."

You will find that almost everyone you speak to will have a different view of what COM is, but it would be unfair to lay the blame for this confusion at the door of the programmer. The standard marketing definitions are not well known because COM is not a product you can go down to the store and purchase. In addition, Microsoft has not made things any easier, since it seems to change the definition each time a new set of PowerPoint slides are shown to the public.

When I decided that I wanted to know what this "COM" thing was and what it meant to me as a Visual Basic programmer, I knew I was on a journey. You can think of this book as the field notes I made on that trip. Luckily, I found that with Visual Basic as my guide, I was able to take quite a few shortcuts, so put your hiking boots on and let's hit the trail!

From this point forward, I will refer to the Component Object Model as COM.

In this section, I'm going to attempt to define COM in a piece-by-piece fashion. Let's start with the basics and cover what the letters C-O-M stand for.

Components and Objects

Components and objects are key concepts in COM, but like "COM" itself, the words are often misused and can mean different things to different people. This is because the terms are tricky first to define and then to distinguish, and for that reason I intend to leave doing so until a more rigorous discussion in the next chapter. I want to keep this introduction at a higher level, and so I shall begin by explaining some of the concepts of component-oriented design without going too deeply into what actually makes a component.

Traditionally, applications were distributed in single, large executable files, which are now known as monolithic applications. These had many inherent problems, paramount of which was that if one line of code needed to be changed, then the entire application needed to be rebuilt. This made the development and maintenance of such applications problematic at best.

Component-oriented design circumvents these problems by breaking applications down into components that can be distributed in separate binary files - either dynamic-link libraries (DLLs) or executables (EXEs). In this context, components are pre-compiled, interacting pieces of software that can act as 'building blocks' for creating applications. In some ways, these components can be thought of as raw elements: in the same way that chemical elements can be combined in a multitude of ways to create different compounds, components can be combined to create different applications. Although COM is not essential for component-oriented design, it does make the entire process considerably easier to implement.

The idea is that a given component can be re-used in different applications that require similar functionality. So, for example, you could construct an invoicing component for one application that could then be reused in other applications that also require an invoicing tool.

Another advantage of this mode of design is that it allows the individual components of an application to be updated easily. Only one of the comparatively small binary files needs to be replaced, unlike in the old monolithic case where the entire application had to be recompiled in order to reflect changes in the source code.

Interfaces are really what COM is all about. I shall cover them in far greater detail in the next chapter (and indeed throughout the rest of the book). Basically, the interfaces of a component are the mechanism by which its functionality can be used by another component. The precise structure of an interface is defined by COM, but in essence it's just a list of functions implemented by the component that can be called by other pieces of code.

At this point, a brief discussion of clients and servers would probably be beneficial, as we'll be talking about them a lot throughout the book.

Clients and Servers

The term 'client/server' encapsulates two separate, discrete entities. These entities could simply be two components, two applications or even two computers. The client requires some service, and requests a server to perform this service on its behalf. The server performs the service and, if required, returns a result to the client.

For example, a client may need some data from a database. In this case, the server could simply be the database, or there could be some additional objects between client and database. In the latter case, these objects would be the 'server' from the client's point of view. From the database's angle, however, the objects form the client and the database is the server. In other words, the client/server distinction merely refers to a request for a service or services. The client does the requesting, and the server performs the request.

In terms of COM components, each component can act as both client and server. A server is a component that exposes interfaces and therefore a list of functions that a client can call. It follows that the client is a component that uses that interface.

COM enforces a strict separation of the client and server such that they only know of each other's presence by the existence of their interfaces. To a COM client, the server is really just a set of interfaces, and I'll have more to say on this subject in the next chapter.

Throughout the rest of the book, I'll be developing this definition of a component and its interfaces.

A Quick Aside

Again, don't worry about the definitions of components and interfaces; for now I just want to draw your attention to how they are drawn in these COM diagrams. The large box represents a component or an object, while the "blobs on sticks" represent the interfaces exposed by that object. For obvious reasons, COM diagrams like this one are sometimes called lollipop diagrams.

If we follow the COM model we will create components described in such a way that they can interact with one another at runtime. The COM model specifies what the interfaces of a component must look like at the binary level, which means that provided your programming language can produce code that obeys the specification, it doesn't actually matter which one you use. This is how COM's much-vaunted language independence is achieved.

Defining COM in a few words is not the easiest thing to do because it comprises several things. Let's expand on the explanations I've given so far by examining exactly what it is that COM provides.

COM is a framework for creating and using components

Because COM is a language-independent standard, it's possible to build and subsequently use components with different languages such as Visual Basic, Visual C++, Delphi or Visual J++. A COM client (sometimes also called a container) is an application whose architecture supports the use of these software components.

COM provides a mechanism for components to communicate with each other

COM achieves the communication promised by the title of this section by the combination of two things. First, there is the binary standard it imposes, which means that your components not only provide a mechanism to communicate, but also know how to speak to other COM-enabled components or applications.

Second, there is the set of services provided by the COM runtime (also called the COM library) that is required to be present on a computer before communication between the components can occur. These services, which are available to all components, come in the form of a set of API functions.

COM promotes the use of component-based development

Before the advent of component-based development, the predominant technique was procedure-based development. This style is linear in nature, and programs written using it start at the first line of code, and finish either when the last line is executed, or an Exit statement is reached. Applications written in this fashion tended not to be very adaptive to what was happening around them.

In Visual Basic today, it is quite easy to reference (that is, to plug in) a library of functionality. Where we used to have to write complex API calls to talk to a database, we now simply have to set a reference to the appropriate library of functionality (as in the following figure) to be able to use it in our own programs. In this particular instance, we're creating a reference in our Visual Basic project to a COM-based library that will allow us to communicate with a database:

Component-based development also allows the programmer to take advantage of using pre-packaged components or tools. An example would be if you were writing a communications program that dealt with receiving and sending information over a modem. You could go out and buy (fairly inexpensively) a package that would handle the communications functionality for you, ridding yourself of the need to write large amounts of code to see if a port was open. You would just have to reference the library, and write a small amount of your own code. These libraries may be thought of as black boxes: you don't need to concern yourself with how they work; you just know that they do work.

COM promotes object-oriented programming

COM (and component-oriented design in general) was created with object-oriented programming in mind. This is a methodology that promotes thinking about software 'objects' and the way those objects interact with each other, rather than their implementation. Although this isn't a book on OOP, it is very difficult to discuss COM programming without covering many aspects of object-oriented programming. Therefore, from time to time we will be discussing further some of the aspects of object-oriented programming.

In order better to understand what COM is useful for, and why it works the way it does, it's revealing to delve into the genesis of COM and trace how it has evolved into its present form. There are two technologies that we can identify as the springboard for COM: OLE and DDE. OLE (later called OLE 1.0) is short for Object Linking and Embedding, which in its original form was a technology that tried to solve the problem of compound documents.

A compound document contains data of several different formats. To help you picture what I mean, think about a word processing document such as a status report. It's probable that you would want to include some calculations from a spreadsheet in a document like this, and maybe a pie chart as well. Before OLE, even if you were somehow able to put the information into the document, there was no standard technique for automatically updating the document when figures in the spreadsheet changed, or for changing the pie chart to a bar chart, for example.

OLE 1.0 provided a solution for this problem by enabling you to take your spreadsheet and place it directly into a word processor document, as in the figure below. Changes to the spreadsheet are automatically and immediately reflected in the document, edits to the embedded spreadsheet can be made through the document simply by double clicking on it, and all the data in the document can be stored together in a single file.

This was a great piece of technology, but it was rather ahead of its time in terms of the hardware that was available to support it. Working with OLE 1.0 required quite a bit of memory and CPU time, but it did get the minds at Microsoft thinking about the best way of getting software components to interact with one another, and in as efficient a manner as possible.

Before even OLE 1.0, a little gremlin called Dynamic Data Exchange (DDE) was being used to allow pieces of software to interact with each other. It allowed data to be transferred between two applications, and also made it possible for one application to be notified when data in another changed. However, DDE didn't catch on - not only did it suffer from poor performance, but also it was difficult to use, and quite easy for the link between the two applications to break. Even today though, you can still find information about DDE in the Visual Basic help files.

Microsoft decided to make a second stab at component interaction in the early part of 1993, at which time OLE 2.0 came into existence. COM was a core component of OLE 2.0, and so the latter can be used as a way of explaining the features we know COM to have today. By providing COM as a means for components to communicate with one another, OLE 2.0 went well beyond the linking and embedding used to create compound documents. In response, Microsoft's marketing department came to the decision to drop the name "Object Linking and Embedding" and simple call it "OLE" (most people pronounce it "oh-lay"). OLE was the rubber stamp applied to anything that dealt with COM technologies.

One of the products of this expansion was OLE Automation. Put simply, OLE Automation (which today is just called Automation) allows a client to call the services exposed by a suitably endowed server, which is usually a major application. For example, it's possible using this technology to create an instance of Microsoft Excel, put numbers into a new workbook, crunch the numbers and then close the application again all from a Visual Basic program, without a single line of Microsoft Excel VBA code! Indeed, many software companies make their living from programming Automation clients that work with the Microsoft Office suite of applications.

If you've come across VBXs in your Visual Basic career, you're probably thinking that they must fit in to the story at around this point - aren't they reusable software components that you can use in Visual Basic? Well, you're on the right road, but you're headed in the wrong direction! VBXs were pre-packaged components written to tie into Visual Basic specifically, providing services such as list boxes or communication controls. These VBXs were great at the time because they provided support for the development methodology called Rapid Application Development (RAD). Just like the example in the last section, if you needed to have communication functionality in your program, it was as simple as dragging a control from the toolbox onto a Visual Basic form.

Although VBXs had the achievement of spawning a third-party industry that provided pre-packaged developer tools for the Visual Basic programmer, they also had three significant problems. First, they were not COM-based and were therefore a proprietary technology for Visual Basic - there was no way to use them from other programming languages. Second, you couldn't actually build a VBX using Visual Basic - instead you had to use something like C++, and even then they were difficult to write. Third, VBXs were limited to a 16-bit architecture.

According to Microsoft's web site, "COM supports the only currently viable component marketplace. The market for third-party components based on COM has been estimated at US$670 million in 1998, with a projected 65 percent compound annual growth rate, growing to approximately US$3 billion by 2001. (Source: Giga Information Group)"

It's great to know there are thousands of companies out there right now building components to make our lives easier!

In response to the Internet storming the beaches of computing, Microsoft marketing went into an elevated state of naming in the early part 1996 and decided that their Internet technologies would fall under the name ActiveX. At the same time, Microsoft came out with a new specification for OLE controls, otherwise known as OCXs (because the files containing them have the extension .ocx). These replaced VBXs: they were based upon COM technology, and they were easier to create, too. In fact, creating them was made even easier when Microsoft allowed Visual Basic developers to create their own controls with Visual Basic 5. A final name change gave OLE controls the title by which we know them today: ActiveX controls.

The reason for "ActiveX" being added to the name harks back to the first part of the previous paragraph. Microsoft enabled Internet surfers who were using their Internet Explorer browser to view web pages that had OLE controls embedded in them, but because OLE controls had suddenly become a part of the Internet strategy, their name had to change! ActiveX controls were designed to be very functional and fast, as well as lightweight in terms of size compared to their VBX precursors, since (as now) bandwidth was at a premium.

With Visual Basic, it's now possible to create ActiveX controls, ActiveX DLLs and ActiveX EXEs. ActiveX DLLs and ActiveX EXEs are similar to ActiveX controls, but they do not have the user interface attached to them that one would normally associate with ActiveX controls. In fact, the DLLs and EXEs are more typical of the COM-enabled software components that we will be writing in this book, and we will of course be discussing them further in forthcoming chapters.

COM technologies allow developers to deal with a myriad of problems that traditional software development simply could not handle. In this section, we'll address these issues and talk about the real-world problems that can be solved with COM-enabled technologies.

The Problem with Software

Software reuse is the goal that everyone's trying to reach, but no one ever seems quite able to get to. Much software development, especially that of a few years ago, does not support effective code reuse. You may have your routines sitting around in .bas files or text files somewhere on the hard drive or the network, but even finding them can be difficult if you don't have a centralized location for them, and they usually contain code that is specific to the last project you worked on. In response to this, most developers resign themselves to the cut-and-paste method of development: find the pieces you want, paste them into the program, and debug them.

Another software development problem pertains to dynamic-link libraries. These are usually files with a .dll extension that hold pieces of code that can be accessed by another program dynamically, at runtime. Unfortunately, it's not always easy to make calls to the library, and plenty of time can be wasted just in debugging your application's connection to it. (What? It wanted a string instead of an integer? Oh, that's why I'm getting the blue screen of death!) Also, if and when the library is updated, it's all too easy to break the compatibility between the new library and applications written to use the old version. If it turns out that you need two versions of the library on the same system, this can cause significant problems for your applications.

Software components written for one language do not always work within another language. Could I take my .cls files, stick them into a Visual C++ project and expect them to work? Of course not - a .cls file would just look like a bunch of text. What's needed is a solution that will allow you to create software components in one language that can be used in multiple languages. Wouldn't it be great to be able to create a component in Visual Basic that could be used in Visual C++, Visual InterDev, Delphi, and Internet Explorer?

In general, legacy applications do not expose a way to allow developers to use their resources programmatically from another application. For example, let us say that we have an application that is good at presenting data and another that is good at creating graphs. It would be nice for the presentation application developer to be able to use the resources of the graph application for their own application rather than have to develop their own graph engine.

Lastly, traditional applications are unable to exploit components that are located on another networked machine. You may have a component that is good at crunching numbers or can provide database services better on a separate machine than putting all the libraries onto the client machine. If only there were a way of creating applications whose separate pieces run on different machines, so that the most appropriate set of resources could be chosen for each part. How good would that be?

It's about time we began to consider how COM solves these issues and provides this kind of functionality for us. The beauty of using Visual Basic and COM together is the combination of the two makes it quite easy to address the problems without too much effort on the part of the developer - Visual Basic does most of the hard work for you!

COM-based components promote software reuse. COM components are usually written to be generic, which allows them to be used in a multitude of ways by different pieces of software. A graphing component, for example, could be COM-enabled so that you could use it in whatever container you choose. You may want to put a graph in your Microsoft Word document, or you might want to put it on a Microsoft Access form. The great thing is that you can use it in either application, and it will work the same way in one as it does in the other.

Looking at the pair of screenshots below, you can see that the Microsoft Chart Component looks and acts the same in both applications. This is very productive because if a developer knows how the chart control works for one application, they are likely to know how to make it work in another application.

As to the problem of being able to find your components after you've written them, COM has a solution that deals with this and more. Every time that you create a COM component with Visual Basic, an entry is placed in the system registry that indicates exactly where on the computer is the file containing your component. In fact, COM goes further than this: it requires that in order for a component to be used, an entry for it must exist in the registry. Without such an entry, the COM runtime will be unable to find the component when it is asked to do so.

This theme will be developed in the next chapter, along with a more complete description of how the registry works.

COM components are language independent. COM components can not only be used in Visual Basic, but also written in Visual Basic. More importantly, you can take a COM component you created in Visual Basic and integrate it into your Visual C++ or Visual J++ project. Although you can't create COM components in Visual InterDev, you can certainly use them by calling them from Active Server Pages. At the moment, language independence is typically limited to the programming languages Microsoft supports, but this is changing as the momentum for COM continues to grow.

COM objects have object-oriented features: obeying the strictures of encapsulation, they are accessed using only public methods and properties, so that any data they contain is hidden from public consumption. However, object-oriented programming is a tool of this book rather than its subject matter, so I'll limit any further discussion of it until it is relevant to the matter at hand. I suggest reading Beginning Visual Basic 6 Objects by Peter Wright (Wrox Press) as a good primer in creating and using software objects.

Time for me to get on my soapbox. If you haven't been to a Usenet newsgroup with "oop" (short for Object-Oriented Programming) in its name, you may not know that there seems to be something of a Jihad over OOP. The purists will tell you that all the software you write must adhere to the concepts of object-oriented programming.

For my part, I like to invoke the old saying, "When your only tool is a hammer, everything looks like a nail." I am not against OOP; indeed, I am quite happy that Visual Basic uses classes and encapsulation - it has made it simpler to develop applications, and it makes debugging much easier. I do think, though, that Microsoft is beginning to push the envelope (yet again) and reappraise the argument that says you should use object-oriented development just because you are supposed to. I am sure to get flame mail on this one, but I think it is better for the developer to decide how they want to design their programs based on what their users require, rather than on an ideological point.

Another great feature of COM is called DCOM, or Distributed COM. This was first shipped with Windows NT4, and was released as an add-on for Windows 95 in late 1996. It also ships as standard with Windows 98. DCOM allows your applications to call upon components that may not even be on the same machine as they are. DCOM takes the notion of location independence that's supported by COM's use of the registry to store the locations of components (provided that there's an entry, it doesn't matter exactly where the component is) and extends it to the network. Furthermore, it provides security for components that are distributed in this way. I will go into more detail on this subject in the DCOM chapter.

You should be able to see from this discussion that there are a number of advantages to using COM and DCOM as platforms for building and using components. COM goes out of its way to provide a robust and powerful environment for your software development needs.

To reinforce the point, let's take a look at a problem for which COM could provide a viable solution. Phil is the project leader of a new application for his company Frogs & Turtles, a retail chain that sells garden plants and accessories. Currently, they are using proprietary software that runs at each retail chain and on each order taker's system at the catalog telephone center. This application batches all orders into a text file and uses a modem to transfer the orders for the next day overnight, where they are then updated to the main database. If there are orders for something that's not in stock, a fax is sent to the representative that took the order the next morning. Unfortunately, there are some problems with the current system.

The first problem is that the software is proprietary, so Phil and his group of developers are unable to add any features to it or debug any of the problems they have found without having the code base. Second, customer satisfaction is low due to inventory control problems. Because they have grown so quickly, their technology has not kept up with their demand: they cannot tell what their inventory levels are until the nightly batches are through. In addition, when a customer puts in an order late in the day, they will not know until the representative calls the next morning that their order is on backorder. Third, when orders are filled out wrongly and entered into the system, it can mess up reporting, wreck the order, or even crash the system the order took place on.

Phil's bosses asked him to develop a system that would solve their growing problems. As always, they gave him two months to complete a project that needed six. (Bosses putting ambiguous, over-ambitious deadlines on a developer? Never heard of that!) In addition, his bosses asked if the Internet could be used as the means of communication between the retail stores and the telephone center. In response, Phil decided to research COM and see how it could be used with Visual Basic (since most of his developers were Visual Basic programmers). He concluded that he would implement COM-based techniques to solve their problems. Throughout the rest of the book, I will demonstrate some of the techniques Phil used to develop his solutions.

By now, you should have an idea of what COM is and what it can do for you, so it's time to wheel out the big guns. Microsoft Visual Basic can make a developer very productive when it comes to creating and using COM components. In fact, Visual Basic itself relies very heavily on COM technologies.

One of the advantages of using Visual Basic to create COM components is the ease with which it can be done. Visual Basic hides a lot of the plumbing needed to implement COM components and lets you focus on developing what your components will do, or what business functionality they will address.

The Visual Basic COM Players

Microsoft Visual Basic allows you to create a number of different COM-enabled projects, three of which we will be concentrating on in this book. First, there are ActiveX controls, which have a user interface associated with them. As a Visual Basic developer, you are probably most familiar with the ActiveX controls that are available as tools in your toolbox.

Also, if you go to Visual Basic's Project menu and select Components... (or just use Ctrl-T), you can see all the ActiveX controls that are registered on your local machine (that is, those that have entries in the system registry):

ActiveX controls generally have a .ocx file extension, as you can see if you look at the Location field in the previous screenshot.

The second kind of project we'll be looking at is the ActiveX DLL. These are COM-enabled files with a .dll extension, and they contain the COM components that you will find yourself using most often. Unlike their ActiveX control counterparts, components in ActiveX DLLs typically do not have user interfaces. Generally, they are made up of a class or a set of classes that are blueprints for the COM objects that you will create.

Thirdly, ActiveX EXEs are very similar to the ActiveX DLLs, except they are out-of-process servers, which means that they don't run in the same memory space as the application that calls them. By the same reasoning, ActiveX DLLs are often called in-process servers, because they do run in the same memory space as the application that calls them. Don't worry if some of these terms are unfamiliar to you at the moment; just understand that there is a difference, and I will have plenty to say about the advantages and disadvantages of in- and out-of-process servers later in the book.

Individually and collectively, these three different project types allow us to easily create reusable components with Visual Basic. Moreover, because these ActiveX components are built on COM we can use them with COM components irrelevant of language or container.

In Chapter 5, we'll create a simple ActiveX control consisting of two text boxes that our developer, Phil, might want use in his application. In Chapter 6, we'll look at how he can distribute COM objects across a network and we'll see the importance of ActiveX EXEs in achieving this. Finally, in Chapter 7 we'll see how Phil can easily provide multi-user support for his ActiveX DLLs.

You will notice that this chapter is short relative to the rest of the chapters in the book. This is because I wanted to provide you a quick primer of what COM is. If you stopped reading this book right now (which you shouldn't), you would at least know what COM is and what it can do for your development.

Specifically, we discussed the concepts behind COM and how we could define it. There are many parts to COM, and it provides us with many services and considerable functionality to solve software problems.

Next, we delved into the history of COM, from its humble roots in OLE 1.0 to its role in Microsoft's Internet strategy. This history helps us to establish how COM came into being and developed into what it is today.

Lastly, we discussed the problems with typical software development and how COM actually helps us to solve these problems. Also, I explained a real-world programming scenario in which the use of COM might be helpful, and we will spend some time in future chapters using COM technologies to solve the not-so-unique problems we uncovered.

At the beginning of the chapter, I mentioned that we were on a journey. At this point, we have made a few steps down the path. Strap your boots on, because we are now heading up the mountain!

This article was originally published on Wednesday Nov 20th 2002
Mobile Site | Full Site