http://www.developer.com/

Back to article

The COM Course - Part 1


November 19, 2002

Welcome to our three-part introduction to the wonderful world of COM!

There comes a time in every programmer's life when a project consisting of mere forms and modules just ain't enough. Sure, you know the API, you know databases... but in the world of the enterprise, employers want that something extra.

And that something is called COM. It's a way of organising your code so it can be used over and over again. It's a method of helping create a bug-free development environment. It's a system that, just after making your life a little harder, makes it one heckuva lot easier.

Basically, it's a completely wizzy way of working.

Today, we're going to figure out exactly what classes are, and how they fit into the big picture of cosmic COM. We'll even be creating our own classes based loosely around a dog (yes, a dog) to demonstrate the theory.

Ready to dive feet first into the chaotic cavern of COM, my cute curious cherubs? Step this way...

You wanna know something that's gonna make your day?

Here goes: you're already a COM programmer.

Yup, that's right. I may have never met you, but I'll bet my brother's bottom dollar that you are.

Every time you set the Text property of a Text Box, you're using COM. Every time you run the MoveNext method on the DAO data control, you're using COM. Every time you control Word from within Visual Basic, you're using COM.

So what exactly is COM?

  • COM is a method of communication

Imagine a television remote control. You press button one and the television tunes into BBC 1. Or CNN. Or whatever. You press the power button and the television turns itself off. You press a brightness button and suddenly your screen looks like a close-up of the infamous 'White Cat Drinking Milk on a Snowy Day' masterpiece.

Unless you're a television repair geezer which I'm kinda hoping you're not you don't know how this all works. You just press the button and it jumps into action.

That also applies to the world of programming. After all, you don't really know what happens when you change the Text property of your Text Box. Under the covers, it's probably making two-dozen API calls but to the end user, it just displays a certain piece of text in the box.

  • COM is a way of reusing code

The good thing about COM is that once you create things that talk the COM-way, that use the COM method of communication, you can use them again and again anywhere.

For example, you could create a COM widget that displays the current date and time. You could then utilise that widget from any program at any time. Your accounts package programmed in Visual Basic could access it. Your order forms in Excel could access it. Your proprietary customer management program written in C++ could access it.

So COM is all about creating 'widgets' that can be reused.

  • COM is based around real-life objects

Most widgets created in COM are based around real-life objects. That means after they've been made, they're really easy to use.

Let's imagine you want to add a customer to your computer system. Instead of adding a barrage of data access code, validation algorithms, and weighty database DLLs to your application wouldn't it be easier to run something like Customer.Add?

It sure would. And COM gives you that power.

So COM is a method of communication, a way of reusing code and usually based around real-life objects.

For the rest of this instalment, we'll be taking a lightning tour of COM and Visual Basic. All of our work will be surrounding the creation of a class which could later be turned into a real life COM object all based on a Dog. That's right, a Dog. Makes sense, don't it?

Sure, at times this first instalment might seem a little surreal but it'll teach you the foundations for all future COM coding.

Hey, trust me... I'm a programmer.

In this section, we'll dive straight into the practical. We'll be creating our first COM object, using it, then considering how we can improve it.

So let's get started:

  • Launch Visual Basic
  • Create a new 'Standard EXE'

Now COM objects are always based on classes. And classes are just chunks of code, a lot like the code in a module, except it's used in a different way.

  • Click 'Project', 'Add Class Module'
  • In the prompt that appears, select 'Class Module' and click 'Open'

The Project Explorer should now show that in addition to Form1, your Project1 also contains Class1. Whoah, too many 1s, dude.

Next, let's be all neat and tidy and change the name of our class:

  • In the Properties window, change the Name property of Class1 to: CDog

Top Tip: Just as you use certain prefixes for certain objects ie, 'txt' for a Text Box and 'frm' for a Form classes are usually prefixed with a capital 'C' or lower case 'cls'. I prefer the former.

Now that big blank bit of white in front of you is going to be your home for the next few minutes. This is where you write your class code, the stuff that COM objects are driven by.

Let's test it out:

  • Declare the following variable in your CDog class:
Public Name As String

Erm, well maybe that didn't take a few minutes but you've done all necessary to take your first step onto becoming a real COM programmer.

Vot haff ve crrreated? Good question. Let's find out:

  • Open Form1
  • Add a Command Button to your Form
  • Insert the following code behind your button:
Dim MyDog As CDogSet MyDog = New CDogMyDog.Name = "Billy Moore"MsgBox MyDog.NameSet MyDog = Nothing

Let me explain what's happening here.

Dim MyDog As CDog

This line of code is telling Visual Basic to set aside a bit of space for the grand entry of CDog. We can't use this object yet though - that comes with the next line of code.

Set MyDog = New CDog

This creates a new instance of CDog. This means the previously 'empty' MyDog template is now a CDog object we can work from. Think of it as creating a new cookie based on the CDog cookie cutter.

MyDog.Name = "Billy Moore"MsgBox MyDog.Name

The first line here sets the Name variable of MyDog, whilst the second displays it in a message box. And finally:

Set MyDog = Nothing

This code simply sets MyDog equal to Nothing. That means the cookie you originally created is eat up by some greedy overweight teenager and completely disappears from your computer. It's called being neat.

* Press F5 to run and test your application

Did it work? Jolly good fun. But at the moment, it's probably a little difficult to tell the difference between, say, a standard module and a class module. Well, the next sample will show us:

  • Change the code behind your Command Button to:
Dim MyDog As CDogSet MyDog = New CDogDim MyDog2 As CDogSet MyDog2 = New CDogMyDog.Name = "Billy Moore"MsgBox MyDog.NameMyDog2.Name = "Sadie Moore"MsgBox MyDog2.NameSet MyDog = NothingSet MyDog2 = Nothing

Here, we see exactly the same as our last chunk of code except we're using two different things, MyDog and MyDog2. Both of these objects are based on our CDog class yet are completely independent of one another.

That goes hand in hand with our cookie cutter analogy. Our code is the cookie cutter and you can make as many independent cookies as you want from it, all based on that one cutter.

Let's test our application:

  • Press F5 and test your application

See what happens? This time, you get two message boxes appearing one saying Billy Moore, the other Sadie Moore both exceptionally cute Boxer dogs, I might add.

Now it's worth noting that most classes are built around real life objects. So, each dog already has a Name. What other properties could we add?

  • Open up Class1
  • Declare the following public variable:
Public Age As Integer
  • Open up Form1
  • Change the code behind your Command Button to:
Dim MyDog As CDog

Set MyDog = New CDog Dim MyDog2 As CDogSet MyDog2 = New CDog MyDog.Name = "Billy Moore"MyDog.Age = 4MsgBox MyDog.Name & " is " & MyDog.Age & " years old"MyDog2.Name = "Sadie Moore"MyDog2.Age = 7MsgBox MyDog2.Name & " is " & MyDog2.Age & " years old"Set MyDog = NothingSet MyDog2 = Nothing

This code is exceptionally similar to the last lot, except here we're using the new Age variable.

  • Press F5 and test your application

You should receive a message box displaying both the name and age of each lovable pooch.

Now try to set the age of one of the dogs to 1,000. Or perhaps 30,000.

See what happens? Bugger all. That's because an integer variable can store any value up to 32,767. But it doesn't make sense for a dog to be 30,000 years old (unless it's an exceptionally well-kept one).

So how do you handle situations like this?

Properties work in much the same way as public variables, except they allow you a lot more control.

Regular properties consist of two property 'routines', a Get and a Let. Both of these work together to provide one main property. Let's look at a chunk of sample code:

Private intAge As IntegerPublic Property Get Age() As Integer    Age = intAgeEnd PropertyPublic Property Let Age(ByVal vNewValue As Integer)    intAge = vNewValueEnd Property

The above chunk of code works much like the Age variable. When someone does something like:

MyDog.Age = 4

... the Let property runs and the number four is passed as vNewValue. This is then stored in the private intAge variable. When someone does something like:

MsgBox MyDog.Age

... to retrieve the property, the Get property is run and the value of intAge is returned. So let's think about that:

  • Get Property Runs when someone wants to "get" the value
  • Let Property Runs when someone wants to "let" your property equal a value

So far, I've only demonstrated these properties working exactly like standard variables (except with a lot more code). However they also allow you to have more control over what goes into your property and what does not.

Let's edit our class:

  • Remove the Age variable from your CDog class
  • Insert the following code:
FACE="Courier" SIZE=2>

Private intAge As Integer

Public Property Get Age() As Integer    Age = intAgeEnd PropertyPublic Property Let Age(ByVal vNewValue As Integer)    If vNewValue <= 50 Then        intAge = vNewValue    End IfEnd Property

The only real change here to our original chunk of example code is the Property Let routine. Here, we've done a little checking. So imagine our user attempts to do a:

MyDog.Age=30

... our Property Let routine runs, passing thirty as vNewValue. In code, we than evaluate vNewValue to check whether it is less than or equal to fifty. Our thirty figure is, so in this instance intAge would be set to thirty. And that's that.

If it was over fifty, nothing would happen. The property would just exit and no values would be set. Naturally, you could decide to raise an error or display an exclamatory message box, but I'm feeling all kind today.

  • Switch back to the code window behind Form1
  • Click onto the first line of code where we set the Age property, and press F9:
MyDog.Age = 4
  • Click onto the first line of code where we get the Age property, and press F9:
MsgBox MyDog.Name & " is " & MyDog.Age & " years old"

Now let's test our application:

  • Press F5 to run your program
  • Hit your Command Button

The code should pause on the lines of code on which you pressed F9 and added a 'break point'.

  • When the code pauses, slowly observe and step through each line by pressing F8

Do you see how it all works? Notice how the Age property goes through the 'get' and 'let' routines? That's properties in a nutshell for ya.

And in the next section, we're going to learn not only a way of making properties more user friendly, but also how you can create them in no time!

Sometimes you have certain properties in a class that could be dealt with better.

Say you have four fixed types of customer Enterprise, Medium, Small and New. Or three different types of searching methods in your Search class FloppyDisks, HardDisks and Network. Wouldn't it be nice to pick one of these options from a list, rather than setting your property to some obscure number or string of text?

You can with crazy lil' things called enumerations.

Let's add a little code to our class:

  • Insert the following into your CDog class:
Public Enum CoatType    BigAndShaggy = 1    ShortCrewCut = 2    PoodleStyleAfro = 3    Unknown = 4End Enum

This 'enum' is an enumeration. In other words, it's a list of possible options. The numbers next to these possible options don't have to be there they just say that BigAndShaggy is represented by the number one; ShortCrewCut equals number two, etc.

Top Tip: The numbers next to an enumeration are useful if you want to put information into a database. As 'BigAndShaggy' really translates into the number 1, you could insert it direct into a database number field. That means you have the power of using string options in code yet can still maintain a great database design.

So, we've created a list of Dog coat types. Now let's add another property to our class to use these types:

  • Declare the following variable in your class:
Private udtCoat As CoatType

This is the private variable that will hold the Coat information on behalf of our soon-to-be-added property. Notice how the variable is declared not as a string or integer but as the CoatType enumeration we created, our own 'user-defined data type'.

  • With your CDog class open, click 'Tools', 'Add Procedure'

I'm now going to show you a great way of creating your property procedures superfast.

  • In the 'Name' box, type Coat
  • Select the 'Property' option button, then click OK

The following skeletal code should be automatically generated for you:

Public Property Get Coat() As VariantEnd PropertyPublic Property Let Coat(ByVal vNewValue As Variant)End Property

Great! But this isn't exactly what we need. Right now, this code accepts and passes back 'variants', which can be just about anything. If you remember, our last property Age accepted integers. This one wants to accept anything in the CoatType list.

  • Change everything that says 'Variant' in the generated code to 'CoatType'

Now let's add a little code to actually handle the property:

  • In the Property Get procedure, add the following code:
Coat = udtCoat
  • In the Property Let procedure, add the following code:
udtCoat = vNewValue
  • Flick back to Form1
  • Change the code behind your Command Button to:
Dim MyDog As CDogSet MyDog = New CDogMyDog.Name = "Billy"
  • Now start to type in: MyDog.Coat =

Do you see what happens? As you press the 'equals' key, a list of possible options appears. You can select any of these. Except the Afro one. Billy certainly doesn't have Afro hair. Nor Big and Shaggy come to think of it. In fact, just select the short crew cut option.

  • Finish typing the code: MyDog.Coat = ShortCrewCut

Next up, let's retrieve the value of the Coat property. Now, if we simply display the value in a message box, we'll only get back the number of the option we selected. In other words, if you selected ShortCrewCut, the property will return a 2. Try it!

But there's another way of doing it by comparing the Coat with an If-Then:

  • Append the following code to the existing behind your Command Button. Make sure you type this out yourself to see the full effect:
If MyDog.Coat = BigAndShaggy ThenMsgBox "You have a big, bouncy, bushy pup!"ElseIf MyDog.Coat = PoodleStyleAfro ThenMsgBox "Your pooch is pretty, petit and pooch-like!"ElseIf MyDog.Coat = ShortCrewCut ThenMsgBox "Your dog is full of oomph, oomph and more oomph!"ElseIf MyDog.Coat = Unknown ThenMsgBox "I have no idea about your dog. I don't think " & _"you do either!"End If

Here, our code simply evaluates what the Coat property is equal to. It then displays a relevant message box.

Top Tip: You could also do a 'Select Case' here but I'm trying to keep the code simple. Oh yeah, and I'm an idle sloth.

And finally, to be all nice and tidy let's add that one final line of code to free up computer memory:

  • Append the following code to the existing behind your Command Button:
Set MyDog = Nothing
  • Test your application by pressing F5, then hitting your button

See what happens? That's enumerations for ya.

So, we've already added variables, properties and enumerations to our classes. What else can you do with 'em?

Well, for a start, you can add Subs. That's right, bog standard ol' Subs, as regularly used in most Visual Basic programs. Let's add one now to demonstrate their power:

  • Insert the following into your CDog class:
Public Sub Bark()    MsgBox "Woof! Woof!"End Sub

And that's it! Here we have a regular sub inside our class that you can run quite simply with a command like: MyDog.Bark.

Let's try it out:

  • Replace the code behind your Form1 Command Button with:
Dim MyDog As CDogSet MyDog = New CDogMyDog.Name = "Billy"MyDog.BarkSet MyDog = Nothing

Notice how after you press the period following MyDog, the Bark Sub is yellow, whilst the properties are blue and white? That's to help you distinguish Bark as a method of your MyDog object.

  • Press F5 and test your code

In addition to subs, you can also add functions to your code. I'm not going to demonstrate it here, but why not have a go yourself? They work just the same as regular functions, except they're inside a class. Don't forget that all Subs and Functions can also have their own parameters.

Now let's imagine I wanted my class to have a Sleep method. I'd call this Sub each time I wanted my pup to take a cat- or rather, a dog-nap.

But how would I know when my little bundle of joy has woken up? Well, that's a good question. And the answer is events.

How do you know when someone types into your Text box? There's the Change event. How do you know when someone clicks on your Command Button? There's the Click event. How do you know when your pooch wakes up? Enter centre stage: the Awake event.

Events are relatively simple to use.

First off, you have to define an event. This means you tell Visual Basic what the event will be called, plus any parameters it may have. As an example, a Command Button has the Click event, no parameters. On the other hand, the Text Box has the KeyPress event, which also passes something called a 'KeyAscii' value.

So to define an event, you put something like this in the General Declarations section (the top bit) of your class:

Public Event MyEventName(PossArguments As String, Etc As Variant)

And then to 'raise' an event in code, you use the RaiseEvent method in your code. Say you have an OnAdd event that fires off each time you add a new customer to your database. Just before you fire update the database, you might want to 'raise' the event. You could do that like this:

RaiseEvent MyEventName("PossArgs", "Etc")

So let's spend a final few minutes adding and raising our own events. First off, let's define our event:

  • Add the following code to the General Declarations section of your class:
Public Event Awake()

Now we need to add the Sleep event. In this event, I could be doing anything adding customer information to a database, cycling through the long process of creating management reports, anything!

But all I am going to do is add a jabberwocking loop that wastes a bit of time, then raises the Awake event. Let's code that, erm, code now:

  • Add the following Sub to your CDog class:
Public Sub Sleep()Dim i As LongFor i = 1 To 1000000DoEvents: DoEvents: DoEventsNext iRaiseEvent AwakeEnd Sub

This code simply loops around a million times, doing essentially nothing. On my computer, this loop lasts around a minute or so. Yours may be slower. Or it may be faster. It all depends on gravitational pull. Or processor speed. I forget. But after that short time delay, our Sleep Sub raises the Awake event.

So how can our test application respond to this Awake event? With Command Buttons, it's darn simple. You just enter the code window, select your Command Button from the drop-down list and Bob's Your Uncle.

But in that instance, you're working with a control, something you can see on a Form. Here we're working with pure code, nothing visible.

So if we want to receive events from our code, we need to do something a little special.

  • In the General Declarations (top) of your Form code window, declare the following:
Dim WithEvents MyDog As CDog

This code is no different from our previous MyDog declaration, except (a) it has the WithEvents keyword to tell Visual Basic it wants to 'receive' any events, and (b) it is in the General Declarations section, which it must be in order to receive events.

Now let's add a little code to test our new object:

  • Delete all code behind the Command Button on Form1
  • Insert the following code behind Command1:
Set MyDog = New CDogMyDog.Name = "Billy"MyDog.BarkMyDog.Sleep

This code simply sets the MyDog object to a new instance of your CDog class. It then sets the dog Name, followed by a standard Bark and finishes off by running the Sleep Sub.

Now let's add a little code to respond when your pup has awoken.

  • In the code window behind Form1, select 'MyDog' from the 'Object' drop-down list
  • In the 'Awake' event of 'MyDog', enter the following code:
Private Sub MyDog_Awake()    MsgBox "Your pooch has awoken!"End Sub

Excellent!! Now let's test our application:

  • Press F5 to run your application
  • Hit your Command Button

After a quick bark, your pup will take a nap, then give you a call when it has finished! Wizard!

In this tutorial, we took an absolute lightning tour of COM and classes.

We started out with an all-official look at exactly what COM is, then got working on classes, which are the actual things behind Visual Basic COM 'objects'.

We looked at properties, subs, enumerations and even events, plus built test applications to see how it all worked.

In the next instalment, we'll be using the knowledge we've gained today to create a real-life COM object based on a database. We'll also be creating a client package to access your object and will see just how much COM code can simplify your programming. We'll even be having a lil' chat about something they call compatibility plus how you can break it! Hehe... <mischievous grin>

So until the next time, this is Karl Moore signing off for tonight wishing you an incredibly pleasant evening. Goodnight!

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date