,

Links

Introduction

Recently, I have had a need to write components with similar interfaces and plug one of them into my application at a given time. While there are many ways of doing this, I wanted to use a standard method that was fairly straight forward and easy for me to write. Since, the fundamental concepts behind it fill both of those needs, and it is well-accepted around the industry, I chose COM. I began looking through all my books, and browsing the internet, but I could not find a guide for what I wanted to do. Thanks go to Len Holgate. His two articles (links above) helped me get started.

This is part 1 of this series. In this part, I will demonstrate a very simple interface that is implemented differently in two different COM objects.

Background

I do not have enough time or space to give a complete overview of COM and/or ATL, so I will assume that you are at least familiar with the concepts. This article will focus on what a reusable interface is, what component categories are, and how to use them in your applications.

What is a reusable interface? Well, the idea behind it is that it is an interface that is used by several objects that may implement it in different ways.

This particular example is derived directly from IUnknown; however, you can derive your interfaces from anything that is indirectly derived from IUnknown (e.g. IDispatch). This is a very simple interface that has only one method (Draw). We will look at more complex interfaces in part 2. This interface will be the the base interface for our components.

Now, we have a common interface to use. That's great, but now how do we use it? Well, first we need to create a simple COM object and derive its interface from our common interface. I used the ALT COM AppWizard to do this (although, you can do it by hand if you really want to). Here is the derived interface for the blue component:

Notice the changes. Also, we don't need to declare the Draw method in the IComCatDrawBlue interface since it is declared in the base class. We can't compile the project at this point because we have not implemented this function (you will get a linker error if you try). To fix this, you need to add the following to the implementation class:

We can now successfully compile this project; however, it won't do us much good. All we can do is bind directly to the object, which is what we were trying to get away from. To do this, we need to use GUIDGEN to define a new guid for us.

ComCatDrawCategory.h

This alone doesn't do anything for us. But if we create a category map in the implementation class's header file, the object will be registered as implementing the stated category. This does not necessarily mean anything if used the wrong way. The category registry keys ("Required Categories" and "Implemented Categories") are nothing more than a promise. They state that a particular component either needs an object that implements another category interface, or is implementing a particular category interface. To make this promise, we must add the following code

That is all there is to it. The Red component was created the exact same way.

Using the code

Now that we have our components, we want to test them. The test application is very simple. It displays a dialog when it starts that shows every object that implements the IComCatDraw interface that is currently registered on the computer. The user selects one and when the View's OnDraw function is called, it calls the objects Draw function. The trick here is to get a list of the components and to get their respective CLSIDs. This is done in the Config Dialog's OnInitDialog function.

NOTE: Make sure you include the component category header file (the one that defines the CATID for the category) as well as the header file for the idl file (see the project settings for the ComCatDraw.idl file for details).

Points of Interest

This is a very simple example of how to design and implement component categories to create pluggable objects and use them in an application. In Part 2, we will look at objects that implement connection points.

Also, I only adjusted the configuration settings for the debug configuration. Thus, the Release builds will not work unless you change them to match (specifically, the include files, midl includes, and the build options for the ComCatDraw.idl file).

History

First revision: June 17th, 2003.

Second revision: September 15th, 2003.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

I started programming at 15 with a TI-82 calclator in Z80 assembly (oh, those were the days . . .) I am pretty much a self taught programmer. I've taught myself Visual Basic, C/C++, Java, and am currently working on C#. I also like to experiment with system administration and security issues, and occassionally I work on web design. For the last 4 years, I have worked for Leitch, Inc. as a Software Engineer and graduated from Old Dominion University with bachelor's degrees in Computer Science, Mathematics, and Business Management in December of 2004.

Comments and Discussions

Just wanted to comment on your article. I am doing the exact same thing right now.

It is great to see some validation on the topic. People at work thought I was crazy.
Now I know that I am at least partially sane. Your article gives a good implementation
example of how to put the book theory to work.

For other readers there is more theoretical info on the topic in Richard Grimes
book, "Professional ATL COM Programming". Once you put the theory together with
this article the ideas will be limitless.

Sorry for the delay in releasing Part 2. Lately I have been swamped at work and haven't had as much time as I would like to write up the article. The good news is that I do have all the example code done. I am hoping to submit the second part within the next couple weeks.