Sie sind auf Seite 1von 32

COM in VB6

The COM Course - Part 1

Introduction
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...
Introducing COM
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.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


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,
doesn'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.

Building Classes
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.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


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 CDog


Set MyDog = New CDog

MyDog.Name = "Billy Moore"


MsgBox MyDog.Name

Set 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 CDog
Set MyDog = New CDog

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


Dim MyDog2 As CDog
Set MyDog2 = New CDog

MyDog.Name = "Billy Moore"


MsgBox MyDog.Name

MyDog2.Name = "Sadie Moore"


MsgBox MyDog2.Name

Set MyDog = Nothing


Set 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 CDog


Set MyDog2 = New CDog

MyDog.Name = "Billy Moore"


MyDog.Age = 4
MsgBox MyDog.Name & " is " & MyDog.Age & " years old"

MyDog2.Name = "Sadie Moore"


MyDog2.Age = 7
MsgBox MyDog2.Name & " is " & MyDog2.Age & " years old"

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


Set MyDog = Nothing
Set 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
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 Integer

Public Property Get Age() As Integer


Age = intAge
End Property

Public Property Let Age(ByVal vNewValue As Integer)


intAge = vNewValue
End 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 = intAge
End Property

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


Public Property Let Age(ByVal vNewValue As Integer)
If vNewValue <= 50 Then
intAge = vNewValue
End If
End 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!
Bettering Properties
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 = 4
End 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

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


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 Variant

End Property

Public 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 CDog
Set MyDog = New CDog
MyDog.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 Then

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


MsgBox "You have a big, bouncy, bushy pup!"
ElseIf MyDog.Coat = PoodleStyleAfro Then
MsgBox "Your pooch is pretty, petit and pooch-like!"
ElseIf MyDog.Coat = ShortCrewCut Then
MsgBox "Your dog is full of oomph, oomph and more oomph!"
ElseIf MyDog.Coat = Unknown Then
MsgBox "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.
Subs, Functions, Parameters, Oh My!
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 CDog
Set MyDog = New CDog
MyDog.Name = "Billy"
MyDog.Bark
Set 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.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


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
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 Long

For i = 1 To 1000000
DoEvents: DoEvents: DoEvents
Next i

RaiseEvent Awake

End 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:

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


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 CDog
MyDog.Name = "Billy"
MyDog.Bark
MyDog.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!

Conclusion

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!

The COM Course - Part 2

Introduction
Welcome to the second part of our introductory COM course, hosted exclusively here on VB-World.
As ever, I'm your host Karl Moore and if you missed part one, be sure to check it out here
</activex/comcourse/>.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


Last week, we worked exceptionally hard to grasp the basics of COM and figure out class programming.
In our instalment this week, we'll be putting all the theory you've gained so far into practical use, with the
creation of a real-life, database-powered COM object. And this one widget will make your future
programming so easy, even David Beckham could do it.
So without further ado, let's grab the steering wheel, put our chick mobile into top gear and speed off into
the unCOMplicated <groan> world of COM...
Going It Alone
Remember how last week we threw a class into a standard Visual Basic project?
Well, one of the main points in the elegant COM philosophy is that code can be reused.
In other words, if you create an Accounting class in Visual Basic, you shouldn't only be
able to access that from your application – but perhaps also from another VB program
your colleague is working on. And maybe an Excel spreadsheet that needs such data. You
might even have a C++ programmer that needs to grab certain information for his latest
project.
So what do you do? At the moment, you've worked with classes residing inside a standard
Visual Basic application. And even if you give them a copy of your final .EXE program,
they still won't be able to access the classes or properties within it.
The solution is to throw all the classes into a program of their own. Then they're "COM-
enabled".
<Karl: Corr, I just invented that buzzword! COM-enabled. Let me call my trademark
people...>
In other words, say your class has an AnnualProfitsToDate property. When this property
is retrieved, your class dips into the company database, performs half-a-dozen
calculations, then returns a value in pounds. Or dollars. Or Yen. Or green bananas. Or
whatever.
Now instead of physically giving the Excel user a chunk of code to access the database,
simply give him your 'class program'. This program 'exposes' your class and the
AnnualProfitsToDate property, allowing other users to plug into its functionality. And
instead of telling the C++ programmer how to manually perform the calculation so he can
access the statistic himself, you could also give him this program, saving you both a lot of
work.
So let's review this... in addition to throwing classes into Visual Basic projects, you can
throw them into programs of their own, called ActiveX components, which say to other
programs "Hey, I can do this – provide an AnnualProfitsToDate property, update the
Customers database, etc!".
And all the functionality of your ActiveX program can then be accessed from within any
ActiveX-aware programming language. In other words, the AnnualProfitsToDate
property can be retrieved from within Excel, C++, Access – and more!
So how do you create an ActiveX program to hold your classes?
Choices, Choices
Let's dive straight into the deep end and start creating our first real COM object, neatly sitting inside one
of those ActiveX programs. Here goes:
• Launch Visual Basic
Observe the icons currently on that 'New Project' screen. You should have a few that begin with ActiveX.
Let's explain each of those now:
• ActiveX DLL – A .DLL program that contains classes. This is our stop!

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


• ActiveX EXE – A .EXE program that contains classes. This will be our stop later!
• ActiveX Control – A project that allows you to create controls, those widgets in your toolbox.
Not our stop. To find out more, click here </activex/controls/> for our ActiveX Control
tutorial.
• ActiveX Document EXE – A program that runs on a Web page, in .EXE format. Certainly not
our stop.
• ActiveX Document DLL – As above, but .DLL format. Not even remotely near our stop.
Incidentally, if you don't have all of these items in your list, don't worry. You've probably just got a cheap,
substandard version of Visual Basic. Ho-humm.
Anyway, we're really only interested in those first two options – the ActiveX DLLs and Active EXEs.
We'll come back to the latter later but deal with the former foremost.
• Click 'ActiveX DLL'
• Hit OK
Great! Now let me briefly explain what this project I fancy knocking up is all about. I want to create an
ActiveX DLL that serves as a front-end to the Customers table in the Northwind database (ships with
Visual Basic, usually found in the VB98 folder).
This will mean that in future when I want to access Customers information, I'll only need to use my class
– and not mess around with tonnes of sticky data access code.
Heck, you've still gotta create the darn class – but as I said earlier, COM makes your life a lil' bit more
difficult – just before making it one heckuva lot easier.
Before dipping into database whatnots, let's first christen our ActiveX program:
• Change the Name property of your class to 'Customers'
• Click 'Project', 'Project Properties' and change the Project Name to 'Northwind'
Brilliant! Now let's get our class connected to that database:
• Click 'Project', 'References'
• Select 'Microsoft ActiveX Data Objects 2.1 Library'
This reference will allow us to access a database. And in the real world, that's all most COM objects do all
day – sit around opening recordsets. It's an exciting life.
• Add the following code to your class:
Dim rs As Recordset
This is the recordset object that will access our database.
Now, when someone starts the class, we want to kick start that recordset object and open a connection to
the database. And when they stop using it, we want to close that connection. Let's code this now:
• In the 'Object' combo, change the current '(General)' to 'Class'
• Ensure 'Initialize' is selected in the adjacent combo
Your code window should currently say something like:
Private Sub Class_Initialize()

End Sub
Any code you enter here fires up when the class first starts. It's a lot like the Form_Load event.
• Enter the following code in the 'Initialize' event:
Set rs = New Recordset

rs.ActiveConnection = "Provider=Microsoft." & _


"Jet.OLEDB.4.0;Data Source=C:\Program Files\" & _
"Microsoft Visual Studio\VB98\Nwind.mdb;" & _
"Persist Security Info=False"

rs.Open "select * from customers", , adOpenKeyset, adLockOptimistic

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


It's worth noting here that this isn't special class code. It's just regular ADO database access code that you
could use anywhere in Visual Basic. We're just using it here to demonstrate how to open a database
connection inside a class.
Top Tip: If your Northwind database isn't in C:\Program Files\Microsoft Visual Studio\VB98\Nwind.mdb
– you'll have to change the above ActiveConnection string!
So, when this class fires up, the rs object will have a link to the database. Now when the class object ends
due to the program using it closing or whatever, we want to close that connection.
We code this in the Terminate event, which is pretty similar to Form_Unload. For a start, they both have
an 'n' in their names. But more relevantly, both events fire when that particular object closes.
Let's enter our database close code now:
• Select 'Class' from the Object combo and 'Terminate' from the Procedure combo
• In the 'Terminate' event, enter the following code:
rs.Close

Set rs = Nothing
Once again, this is just regular stuff. Here we're simply closing the database, then being all good and
setting rs to nothing, which calls in the heavies to effectively erase the fact that rs ever existed.
Great! Let's continue on the next page, where we'll be entering code to access records in our database!
Adding Properties and Methods
Next, I'd like to add a property that allows our user to retrieve the Customer ID. Here's a piece of sample
code I created earlier:
Public Property Get CustomerID() As String

CustomerID = rs("CustomerID")

End Property

Public Property Let CustomerID(NewValue As String)

rs("CustomerID") = NewValue

End Property
Do you understand what's happening here? The Property Get simply 'returns' whatever is in the
'CustomerID' field. This allows our end user to retrieve the property. The Property Let accepts a new value
and sets the 'CustomerID' field to that value.
In other words, there are two parts to a property. The 'getting' and the 'letting'. In fact, there's also another
one - 'setting' – but that's for a different day. Missing either the Get or the Let out will make the property
either write- or read-only.
The power here is that we can check for certain things in these property procedures. For example, to call
the Property Let here, the user could do something like:
ObjectName.CustomerID = "HALFI"
When this runs, it calls the Property Let, passing 'HALFI' as the NewValue string. I then set the
'CustomerID' field equal to NewValue. But looking at the Northwind database, I can see that the
'CustomerID' field is limited to just five characters. So if someone did something like this:
ObjectName.CustomerID = "HALFISTORE"
... then we'd get database errors. We could deal with this via database error handling, yes. But we could
also check the length of NewValue in code. If it's longer than five characters, you could either just snip the
first five letters, ignore the new value altogether - or 'raise' an error. We're going to check for the length
and if it's too long, I'll be all-cruel and raise an error. Hehe! <Evil grin goes here>
• Add this code to your class:
Public Property Get CustomerID() As String

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


CustomerID = rs("CustomerID")

End Property
Public Property Let CustomerID(NewValue As String) ' If the length of NewValue is greater than five If
Len(NewValue) > 5 Then ' ... then raise an error to the program ' using this class! Err.Raise
vbObjectError + 1, "CustomerID", _ "Customer ID can only be up to five " & _ "characters long!" Else ' ...
otherwise, change the field value rs("CustomerID") = NewValue End If End Property
Brilliant! We've just got time for one more method before finishing this section:
• Add the following code to your class:
Public Sub Update()

rs.Update

End Sub
When somebody runs the Update method, it simply fires the Update method of our recordset object.
Simple.
Next up, we're going to test both this property and method with a mini sample application, plus use a
special trick to follow what happens between both your class and test program.
Testing your Class
Let's get your class up-and-running:
• Press F5 to run your program
• If prompted for further information, select 'Wait for Components to Start', then click OK
Your class is now 'alive' but waiting for other programs to use its functionality.
• Launch another instance of Visual Basic
• Create a new 'Standard EXE' project
• Click 'Project', 'References'
Have a scroll around the list. These are all extra widgets you can add to your project.
• Check 'Northwind' in the list
Northwind is your ActiveX project!
• Click OK
Now let's add a little code to activate your project:
• Add a Command Button to Form1
• Type in the following:
Dim Test As Customers
Set Test = New Customers
MsgBox Test.CustomerID
Set Test = Nothing
This code creates a new Customers object. Then the CustomerID is displayed in a message box. Finally,
the Test object is set to Nothing, closing it down.
• Hit F5 to run your test application
Top Tip: If you're getting 'invalid reference' error messages when running your application, something
definitely boobed. Follow these steps to 'reset' – (1) remove the Northwind reference in your test project,
(2) restart your Northwind project, (3) add the reference to Northwind back to your test project, then try
again.
• Click your Command Button
It may take a few seconds to start-up – after all, it's opening a database connection and so on – but after
that initial delay, all calls will perform at lightening speed. You should get a message box displayed
containing the name 'ALFKI'.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


• Stop your test application
Now, let's figure out exactly what's happening behind the scenes.
• Move your cursor to the line of code starting MsgBox Test.CustomerID
• Press F9
A red line will mark the code. When this code runs, it will stop here, at the 'breakpoint'. Pressing F8 will
run that line of code and move onto the next.
• Press F5 to run your test application (again)
• Click your Command Button
The code should stop on your MsgBox command.
• Press F8 and slowly step through each line of code
You should be automatically switched backwards and forwards between both instances of Visual Basic.
This shows you exactly what happens when you access the various properties.
Notice anything interesting?
• When finished, stop your test application
Let's continue testing your program. This time, we'll set the CustomerID instead of merely retrieving the
value.
• Change the Command Button code to:
Dim Test As Customers
Set Test = New Customers
Test.CustomerID = "KARLY"
Test.Update
MsgBox Test.CustomerID
Set Test = Nothing
This code sets the 'CustomerID' field, then Updates the recordset. Finally, it displays the CustomerID
property, which should be set to 'KARLY'.
• If you wish, press F9 to highlight the "Test.CustomerID =" line of code – then step through once
more with the F8 button to see how it all works
And that's it! Congratulations on successfully creating and testing your raw database class!
As an experiment, why not try setting the customer ID property to a string greater than five characters in
length? You should get back an error message. Try adding regular error handling code to deal with this.
See what happens!
Next up, let's take your current database class – and improve it.
### Completing our Class ###
Now we want to add even more features to our class – extra properties, a few methods and perhaps even
an event or two.
I'm not going to walk you through every part of this code, you should be able to figure it out. So just take a
look, read the comments, copy-and-paste and let's continue:
• Replace your class code with this updated code:
Dim WithEvents rs As Recordset

Public Event RecordsetMove()

Private Sub Class_Initialize()

Set rs = New Recordset

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


rs.ActiveConnection = "Provider=Microsoft." & _
"Jet.OLEDB.4.0;Data Source=C:\Program Files\" & _
"Microsoft Visual Studio\VB98\Nwind.mdb;" & _
"Persist Security Info=False"

rs.Open "select * from customers", , adOpenKeyset, adLockOptimistic

End Sub

Private Sub Class_Terminate()

rs.Close

Set rs = Nothing

End Sub

Public Property Get CustomerID() As String

CustomerID = rs("CustomerID")

End Property

Public Property Let CustomerID(NewValue As String)

'If the length of NewValue is greater than five

If Len(NewValue) > 5 Then

'... then raise an error to the program


'using this class, by running
'Err.Raise vbObjectError + OurErrorNumber

Err.Raise vbObjectError + 1, "CustomerID", _


"Customer ID can only be up to five " & _
"characters long!"

Else

'... otherwise, change the field value

rs("CustomerID") = NewValue

End If

End Property

Public Property Get CompanyName() As Variant


CompanyName = rs("CompanyName")
End Property

Public Property Let CompanyName(ByVal NewValue As Variant)


rs("CompanyName") = NewValue

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


End Property

Public Property Get ContactName() As Variant


ContactName = rs("ContactName")
End Property

Public Property Let ContactName(ByVal NewValue As Variant)


rs("ContactName") = NewValue
End Property

Public Property Get ContactTitle() As Variant


ContactTitle = rs("ContactTitle")
End Property

Public Property Let ContactTitle(ByVal NewValue As Variant)


rs("ContactTitle") = NewValue
End Property

Public Property Get Address() As Variant


Address = rs("Address")
End Property

Public Property Let Address(ByVal NewValue As Variant)


rs("Address") = NewValue
End Property

Public Property Get City() As Variant


City = rs("City")
End Property

Public Property Let City(ByVal NewValue As Variant)


rs("City") = NewValue
End Property

Public Property Get Region() As Variant


Region = rs("Region")
End Property

Public Property Let Region(ByVal NewValue As Variant)


rs("Region") = NewValue
End Property

Public Property Get PostalCode() As Variant


PostalCode = rs("PostalCode")
End Property

Public Property Let PostalCode(ByVal NewValue As Variant)


rs("PostalCode") = NewValue
End Property

Public Property Get Country() As Variant


Country = rs("Country")
End Property

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


Public Property Let Country(ByVal NewValue As Variant)
rs("Country") = NewValue
End Property

Public Property Get Phone() As Variant


Phone = rs("Phone")
End Property

Public Property Let Phone(ByVal NewValue As Variant)


rs("Phone") = NewValue
End Property

Public Property Get Fax() As Variant


Fax = rs("Fax")
End Property

Public Property Let Fax(ByVal NewValue As Variant)


rs("Fax") = NewValue
End Property

Public Sub AddNew()

rs.AddNew

End Sub

Public Sub Update()

rs.Update

End Sub

Public Sub CancelUpdate()

If rs.EditMode = adEditInProgress Or _
rs.EditMode = adEditAdd Then
rs.CancelUpdate
End If

End Sub

Public Sub MoveNext()

rs.MoveNext

End Sub

Public Sub MovePrevious()

rs.MovePrevious

End Sub

Public Sub MoveFirst()

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


rs.MoveFirst

End Sub

Public Sub MoveLast()

rs.MoveLast

End Sub

Public Function FindByCustomerID(CustomerID As String) As Boolean

'Uses the Find method to locate customers


'with a matching CustomerID.
'Returns True value is customer(s) found

Dim varBookmark As Variant

rs.MoveFirst
rs.Find ("CustomerID='" & CustomerID & "'")

If rs.EOF = True Then


FindByCustomerID = False
rs.Bookmark = varBookmark
Else
FindByCustomerID = True
End If

End Function

Public Property Get EOF() As Boolean

'Example of a read-only property


'No Property Lets here

EOF = rs.EOF

End Property

Public Property Get BOF() As Boolean

'Another example of a read-only property

BOF = rs.BOF

End Property

Private Sub rs_MoveComplete(ByVal adReason As ADODB.EventReasonEnum, _


ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset)

'Reacts to the recordset MoveComplete


'method - raises event with each move

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


RaiseEvent RecordsetMove

End Sub
Top Tip: So far in this tutorial, we've only added code to one class. However you can easily add more
classes to your projects, by clicking 'Project', 'Add Class'. You can even make these classes work together
by utilising 'collections'. In a situation like ours however, you may want to consider using one class per
table.
Compiling your Program
And now, it's time to compile your class program.
When you do this, all the classes in your ActiveX project will magically turn into one
.DLL file. After this, most tools on your computer will be able to see and use them. So
after compiling, you'll be able to use your DLL from within VB, Excel or even C++!
So let's compile it:
• Click 'File', 'Make Northwind.dll'
• Choose a location then click 'OK'
And would you believe... that's it! You've just created and 'registered' your first real COM
component!
Building your Test Program
So, we've created our COM component and now we need to test it. Let's shoot:
• Close your Northwind project
• Create a new 'Standard EXE'
This program will access our class.
• Add a Label and List Box to Form1, like this:

That List Box will hold a list of our customers and their IDs. Here, I want the user to be able to click the
Find Customer button and have another screen popup with the editable customer details. Let's design that
screen now:
• Click 'Project', 'Add Form'
• Add seven Labels, seven Text Boxes and a Command Button to your Form
• Organise your controls like this:

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


Brilliant! That's our application designed. Now let's get coding.
Before working with our Northwind project, we need to add a reference to it:
• Click 'Project', 'References'
Have a quick scroll up-and-down the list. This is where you find other COM components such as the ADO
library and Excel automation widgets.
• Find and check 'Northwind', then click 'OK'
Adding this reference means your application can now use the power of Northwind, the program you
created just a few minutes ago.
• Add the following code behind Form1:
Private Sub Form_Load()

Dim Cust As Customer


Set Cust = New Customer

Do Until Cust.EOF = True


List1.AddItem (Cust.CustomerID & " " & _
Cust.CompanyName)
Cust.MoveNext
Loop

Set Cust = Nothing

End Sub

Private Sub lstCustomers_Click()

Dim strCustomerID As String

'Grab the CustomerID from the List Box entry


strCustomerID = Mid(lstCustomers.Text, 1, 5)

'Load the Customer


Form2.LoadCustomer (strCustomerID)

End Sub

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


Hopefully you should find this code amazingly easy to follow. During Form_Load, the program creates a
new instance of our Customer object. It then loops round, adding customer IDs and company names to our
List Box, until the EOF property is True.
Top Tip: EOF stands for End Of File. The EOF property of a recordset is equal to True when it has
reached the 'end' of the records. For more information, take our database tutorial here.
Finally, the code sets our Customer object equal to nothing.
The code behind our List Box simply shows Form2 then runs the LoadCustomer method. The
LoadCustomer method? Oh yes... we've not programmed that one yet. We'll get round to it in just a few
minutes, but all it will do is accept the Customer ID and look up our customer. And that's as easy as your
local 80s music station thanks to your new COM component.
Our code here actually chops the first five characters from the item selected in our List Box, then passes it
to the LoadCustomer method. And coincidentally enough, those first five characters are the customers ID.
Let's add the code for Form2 now:
• Add the following code behind Form2:
Dim Cust As Customer

Public Sub LoadCustomer(CustomerID As String)

Set Cust = New Customer

Cust.FindByCustomerID (CustomerID)

With Cust
Text1.Text = .CustomerID
Text2.Text = .CompanyName
Text3.Text = .ContactName
Text4.Text = .Address
Text5.Text = .City
Text6.Text = .Country
Text7.Text = .Phone
End With

End Sub

Private Sub Command1_Click()

With Cust
.CustomerID = Text1.Text
.CompanyName = Text2.Text
.ContactName = Text3.Text
.Address = Text4.Text
.City = Text5.Text
.Country = Text6.Text
.Phone = Text7.Text
.Update
End With

Unload Me

End Sub
Here, we have a Customer object declared as Cust right at the top of the code.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


Top Tip: If you declare an object behind, say, a Command Button – as in Form1 – only the code behind
that Command Button can see and use it. But if you declare an object at the top of your code – in General
Declarations – any chunk of code in your Form will be able to access it.
First off, our LoadCustomer method. This starts off by creating a new Customer object, then runs the
FindCustomerByID method to locate the customer. Once located, various Customer properties are then
dumped straight into our seven Text Boxes.
After any editing, our user will then click the 'Save + Close' Command Button. Here, our code simply
takes the information from the Text Boxes and slots it straight back into the Customer object. Finally, our
code runs an Update then unloads our Form.
Testing It All
Instead of testing our application within Visual Basic this time, I'd like you to compile it.
• Click 'File', 'Make Project1.exe'
• Choose a memorable directory and click 'OK'
• Close Visual Basic
• Run the .EXE file you just compiled
In the Form that appears, try opening a customer, changing the details, then clicking OK.
Next, try reopening that customer. Are the details you entered still there? They should be
– because your ActiveX DLL saved them to the database.
Now sit back for a few moments and think about what you've just done. You've created
your very own database application with update facilities... all in just a few simple lines of
code. The COM bit took a little more effort, but your final using-application was a doddle.
And that's the power of COM. It's make your life harder before making it one heckuva lot
easier.
• When you've finished testing your application, close it
If you thought things were running too sweetly, I've got news for you – they were. So
here I am with a great big spanner to throw into the works:
• Open your Northwind project
Now just pretend you've made a few changes and need to recompile. Righto, let's do that
now:
• Click 'File, 'Compile Northwind.dll'
• Choose the same directory as your last Northwind.dll (one will overwrite the
other), then click OK
Top Tip: If you get errors compiling, it's probable that something else is accessing your
program. Attempt to close all running applications then try again.
• After compiling, close Visual Basic
• Attempt to run your 'Project1.exe' again
What's that? You got an error message? Class doesn't support expected interface or
something like that? Oh dear.
Well, that's my great big spanner. When you recompiled your ActiveX project, the
program that used it just fell to pieces.
How can you fix this? Well, one way is to reopen your Project1 files and do a recompile.
But just imagine all two hundred people in your office use Project1. That means you have
to completely recompile the project and roll both it and the new DLL out smoothly to
over two hundred people with minimum disruption.
Can you spell impossible?

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


No, what we need to do is find out why this error has occurred. Why can't your project
see and work with your newly-compiled DLL? The answer is compatibility – and we'll be
dealing with this and more next time on the COM Course!
Conclusion
This week, we built on our class skills to create our first real COM component.
We programmed a real-life Customer object that accessed the Northwind database, then
went on to create a test application to sample just a few of its features. We also
discovered that after creating the initial COM component, programming becomes much
easier.
In the next instalment, we'll look at how to fix the incompatibility problem we've
uncovered – plus, we'll be taking a sneak peak at the other ActiveX widgets available,
figure out some weird thing called Instancing and finally, learn where you can go to take
your COM skills to the next level.
So until then, this is Karl Moore wishing you all an exceptional evening. So it's goodnight
from me... oh, and it's goodnight from me. Goodnight!
The COM Course - Part 3
Introduction
Welcome to the third and final instalment of our COM Course!
I'm your host Karl Moore and if you haven't yet sat the previous two sessions, be sure to check out part
one here </activex/comcourse/> and part two here </activex/comcourse2/>.
This week, we'll be looking in more detail at the nitty-bitty settings available when building your COM
applications in Visual Basic. We'll be explaining away that compatibility problem you uncovered last
week, take a peek at ActiveX EXE projects and how they differ from DLLs, plus we'll be looking at what
you need to do next to take your knowledge onto the next level.
And all that within the next hour. So why waiteth thee? Click onward, fair knave!
Compatibility
At the end of last week, we stumbled across a small problem. Well, rather a big problem
actually.
In fact, if you've got time, it was a whopping great huge problem wearing high heels, a
frilly skirt and holding a massive sign stating "I am a BIG problem!".
You see - we compiled our ActiveX DLL, then compiled a test program that used our
DLL. Then we recompiled our DLL – something you usually do after you make changes.
Suddenly, our test program no longer worked. Damn.
If we had then recompiled our test program, it would've worked. But let's say your VB
program, an Excel spreadsheet and one C++ accounts package all use your DLL. Do they
all need to be 'recompiled' every time you make a small change to your ActiveX DLL?
The answer is, thankfully, no.
The reason we experienced problems last week was due to an issue known as
compatibility. Or rather, a lack of it.
• Open up your Northwind project in Visual Basic
• Click 'Project', 'Northwind Properties'
• Click the 'Component' tab

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


Take a peek at the 'Version Compatibility' frame in front of you. Here we have three
options. Let's explain these now:
• No Compatibility – With every compile, your COM component gets assigned a
new 'signature'. This means programs looking for older 'signatures' (the previous
version of the DLL) – simply flop
• Project Compatibility – With every compile, your COM component is assigned a
new signature – and still, any using-applications still flop. The only change here is
that 'big' differences between your current project and a previous DLL project are
highlighted as you compile. Ohhh, whoop-de-doo
• Binary Compatibility – When compiled, your application attempts to keep the
signature of a previously compiled DLL, thus ensuring any applications using it
don't magically turn into the Blue Screen of Death. However if the differences
between your previously compiled DLL and your to-be-compiled DLL are too
great, a new signature must be assigned
So let's test our theory:
• Open last week's test application
• Recompile it
• Trial run your test application – it should work
• Open our ActiveX DLL project
• Set the Binary Compatibility option
• Recompile your DLL
• Attempt to run your test application – it should still work
Hurrah! It may sounds like complete hogwash, but when recompiling their DLLs, most
developers get themselves into an awfully incompatible situation.
But hopefully you won't – all thanks to this small aside.
Well, that's compatibility for you. About

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


ActiveX EXEs
So far on our journey, we've explored using classes in ActiveX DLLs. That's all fine and
dandy, but no COM course would be complete without a brief look at the naughty little
brother of DLLs – ActiveX EXEs.
Now when it comes down to actually coding an ActiveX EXE project, there's very little
difference between the two. Actually, there's no difference. You just fire up Visual Basic,
choose 'ActiveX EXE' instead of 'ActiveX DLL' - then start creating your classes as usual.
So why should I even bother mentioning it, I hear you ask? Well, even though you use
them in the same way, they work slightly differently.
The first difference involves something called 'process space'. When any Windows
program starts, be it Microsoft Word or Oliver Reed's Multimedia Guide to 20th Century
Beer, it has a process space. This is like desk space to your program. It's a chunk of
computer memory it uses to 'run' and 'work on' and stuff.
Now when you use ActiveX DLLs in your project, the DLL runs inside the process space
of the program using it – whereas an ActiveX EXE works outside of that space. In other
words, an ActiveX EXE has a 'desk' of its own. But what use is that? Let's ponder over
the advantages and disadvantages...
For a start, if your ActiveX DLL goes wild and crashes, the program using it is usually set
alight and dramatically burnt to smithereens, often complemented by the devilish Blue
Screen of Death. That doesn't happen with EXEs. They have their own 'process space' so
if they crash, only their own desk is burned. Of course, your program then has to
graciously recover having 'lost' that bit.
'Course, in the real world, nothing ever really crashes anyway (hah, who said technology
journalists were 'out of touch'?)
Another difference is the load speed. Because a DLL loads within the existing process
space, it's can nip up pretty quickly. On the other hand, EXEs take a few extra
nanoseconds due to them having to quickly knock up their own process space and so on.
But is there any real difference? Hmm, yes. Two 'real to life' differences.
First off, if you're using certain Windows tools to complement your ActiveX components,
you may be forced to use a particular type of project. For example, if you're using MTS,
you have to create DLLs. If you're using DCOM, you have to use EXEs. Don't worry if
you aren't sure about any of these acronyms right now – they're just tools for power users,
widgets to bring in when you want COM to work 'remotely'. We'll have tutorials on such
technologies coming later on VB-World.
And now enter stage the second real difference.
I once needed to create an application that continuously checked whether something had
happened in a database. I first tried doing this with some sort of 'timer' in my program.
Every ten minutes or so, everything fired up and the database would be checked. The
problem was that when this happened, all regular code in the same process space had to
stop and wait for my database check.
Now one really great thing about ActiveX EXEs is that they have their own process space.
So if you add a timer to do something there, it buzzes away in its own process space and
doesn't affect the program using it. That means I could add an ActiveX EXE to the above
project which, whilst checking the database, doesn't freeze the nuts off the program using

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


it. Then if a message needs to be returned to the using program, it can be sent back by
raising an event.
Top Tip: This method of running code 'away from' the regular program and raising
events to talk to the using application is called asynchronous processing. You can use
asynchronous processing when you need to either perform periodic e-mail or database
checks, or perhaps when you need to run a long report or calculate big time statistics.
Surprisingly enough, everything we've covered on this page can be summarised in just one
sentence. And here it is:
• ActiveX DLLs run 'in-process' and ActiveX EXEs run 'out-of-process'
Dazzling, isn't it?
Top Tip: For more information on which type of ActiveX project is best suited to your
project, check out this Microsoft document
<http://msdn.microsoft.com/library/devprods/vs6/vbasic/vbcon98/vbconolecomponentsyo
ucancreatewithvisualbasic.htm>
In the next section, we'll knock up our very own ActiveX EXE and acquire the little-
known skill of 'asynchronous processing'. After that, we'll uncover a wonderful little thing
called instancing (which I accidentally-on-purpose forgot to tell you about earlier), plus
find out how you can take your mega COM knowledge to the next level.
So izzy wizzy, let's get busy!
<Reader: Groan >
Creating a Test ActiveX EXE
In this section, we're going to knock together our own ActiveX EXE.
Our component will essentially be a file monitorerer. Every sixty seconds or so, it will fire off and check
for the existence of a particular file. If found, our component will attempt to raise an event to the calling
application. If not, our component will attempt to raise the Spanish Armada from the shores of Cornwall.
Now, if we were to stick all our code into a regular ActiveX DLL project, our normal program code would
have to pause and hang about until this file checking code had finished. Because an ActiveX EXE project
has its own process space, this code runs of its own accord – asynchronously – without delaying our
normal program code.
So let's get started:
• Create a new 'ActiveX EXE' project
• Name the Project: File
• Name your Class: FileCheck
First off, we're going to need to create something that checks for our file every minute or so. Here, we're
just going to slot a Form with a Timer inside our ActiveX EXE (yes, you can have Forms inside your
ActiveX EXE/DLL projects!). We won't be showing the Form, but every minute or so will use the Timer
control on it to check for a specified file. If found, the Timer will 'tell' our class by raising an event. Let's
get coding:
• Click 'Project', 'Add Form'
• Add a Timer to Form1
• Declare the following variable behind your Form:
Public Filename As String
This will hold the name of the file we wish to monitor.
• Declare the following event behind your Form:
Public Event FileFound()
This even will be raised by our Timer code if the above file is found.
• Insert the following code behind Timer1:
Private Sub Timer1_Timer()

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


If Dir(Filename) <> "" Then

RaiseEvent FileFound
Timer1.Interval = 0

End If

End Sub
Here, our code simply checks for the file. If found, it raises the FileFound event, then sets the Timer1
Interval property to zero, stopping all future timer checks.
• Open your FileCheck class
• Declare the following object in General Declarations:
Dim WithEvents objFileCheck As Form1
This is your Form1. You're telling Visual Basic this is a space to hold your Form. The WithEvents
keyword means your class can receive the events it transmits, such as our coded FileFound.
• Select 'Class' from the 'Object' drop-down list
• Choose 'Initialize' from the 'Procedure' drop-down list
• Slap the following code behind the Class_Initialize event:
Private Sub Class_Initialize()

Set objFileCheck = New Form1

End Sub
This code simply sets our objFileCheck to equal a new instance of Form1. Following this, we can use all
the functionality we programmed into Form1. Next up, let's write a Sub that the program using our
application will use to monitor a file.
• Throw the following code into your FileCheck class:
Public Sub MonitorFile(Filename As String)

objFileCheck.Filename = Filename
objFileCheck.Timer1.Interval = 60000

End Sub
When our user calls this, passing a filename, the Filename variable of our Form is set to the passed
filename. Then, the Timer is 'started' by setting the Interval property to 60,000 milliseconds (or a minute
to the rest of us).
So, we've created all the jazz to monitor our file. But when it is actually 'found', we need to tell the
program using our ActiveX EXE by raising the FileFound event.
• Add the following event declaration to the General Declarations section:
Public Event FileFound(Filename As String)
This code simply 'defines' our FileFound event. Next, we'll add code to fire off this event when
appropriate.
• Select 'objFileCheck' from the 'Object' drop-down list
• Choose 'FileFound' from the 'Procedure' drop-down list

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


You're currently looking in the event our Form will raise when it 'finds' the file. This is where we need to
raise our own FileFound event to the program using our EXE.
• Add the following code to the objFileCheck_FileFound event:
RaiseEvent FileFound(objFileCheck.Filename)
And that's our class complete!
When a programmer uses our class, he (or rather more unusually, she) can run the MonitorFile method,
passing a filename. That starts off the Form Timer. When the Timer code finds the file, checking every
sixty seconds, it raises an event in our FileCheck class. This raises another event to the program using our
program, telling the programmer their file has been found.
Clear as mud? Let's test it!
Instancing
Before we can test our File component, we need to compile it. But just before we do that,
let's take a sneak peek at a few extra options given to us by Visual Basic.
Whilst in your FileCheck code window, take a look at the Properties window.

Here we have the Name, DataBindingBehaviour (for 'binding' the class to a data source)
and Persistable (used in controls, allows certain class properties to be saved). You should
also have Instancing.
Now after you've set the class name, you probably won't need to worry about the first
three. But what about Instancing?
The Instancing property determines whether or not your class can be 'seen' by the
application using your ActiveX component – and if it can, whether more than one
'instance' should be started at any one time.
Let's take a look at the options, in order of popularity:
• MultiUse – This is perhaps the most used option. This uses one 'instance' of your
component (one 'process space') to serve all the programs using it. Here, all
objects are served by one instance of your component. This saves memory space
and can allow you to "share global variables" - but has few other real-life
advantages
• Private – No-one except other objects in your component can see this class. This
is generally used when you need to create a class that will solely be used by the
other objects in your class
• GlobalMultiUse – Allows you to call the various methods and properties of your
class as if they were global functions. In other words, in VB, you don't have to
explicitly create a new object, then run that method – it's all done automatically.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


You just call it! Every method or property called runs from one single instance of
your component
• PublicNotCreatable – This means your class is viewable by all, but only your own
classes can create an instance of it. In other words, your end user cannot use the
New keyword to create one of these – your class must do that and pass it back.
This is a little like when you open a recordset in DAO – you never create a new
recordset, but simply get one back from the OpenRecordset method
• SingleUse – This means that every time a new instance of a component is started
in code, it fires up another 'instance' of your ActiveX component. In other words,
each instance gets its own 'process space'. This does have some limited use, but
nothing to worry about. Unsurprisingly, this is the opposite of MultiUse
• GlobalSingleUse – As in GlobalMultiUse, except for each object created in code,
a new instance of your component is fired up
Now you'll rarely use all of these. Undoubtedly the most popular is MultiUse. Private is
sometimes used and GlobalMultiUse can be pretty neat, but the rest are kinda unpopular.
Knoooow the feeling. You'll also find most of these options available when creating
ActiveX DLLs – and they work in just the same way.
Well, my profuse apologies for such a boring interlude, but I'd get a scalding from all the
COM whizz-kids if I didn't mention incredulous Instancing.
Anyway, let's fire ahead and compile then test our ActiveX EXE component!
• Click 'File', 'Make File.exe'
• Choose a filename then click OK
Now let's create our test application!
Creating a Test Application
Let's dive straight into creating an application to test our ActiveX EXE file-monitoring component:
• Create a new 'Standard EXE' project
Now let's add a reference to our new File component, then throw in a little testing code for good taste:
• Click 'Project', 'References'
• Check the 'File' component, then click OK
• In the General Declarations section behind your Form, add the code:
Dim WithEvents MyFileObject As FileCheck
• Select 'MyFileObject' from the 'Object' drop-down list
• Ensure you're in the FileFound event
• Tap in the following code:
MsgBox "Found: " & Filename
• Add a Command Button to Form1
• Behind your Command Button, type:
Set MyFileObject = New FileCheck
MyFileObject.MonitorFile ("c:\test.txt")
Here, we're setting MyFileObject to a new instance of FileCheck, then we're running the MonitorFile
method passing c:\test.txt as an argument. Now behind the scenes this will fire off the Timer and every
sixty seconds will check for the file.
Now, that test.txt probably doesn't exist on your computer yet. Wait a few minutes. Nothing should
happen. Then create a new file in Notepad, calling it c:\test.txt
Within sixty seconds, a message box should pop up stating it has found your file! Well done, you've just
created your own ActiveX EXE!

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


It's worth noting that this particular component uses asynchronous processing. As we discussed earlier, an
ActiveX EXE has its own process space. So when your Timer fires up to check for the existence of a file,
it doesn't delay the program using it. If you were using a DLL, it would have done.
And you could put anything behind that Timer – code to create a whopping great huge report, a mega
calculation, anything!
So far in this course, we've created a couple of real groovy components. But we've not talked about
distributing them yet. Let's have a quick natter...
Distributing Components
So you've created the world's sexiest ActiveX component and need to get it out to the
masses. What do you do?
Well thankfully, distributing your COM components is exceptionally easy. Just as you
would use the Package & Deployment Wizard to get your regular Visual Basic project on
other computers – you can do the same with your ActiveX projects!
You can send out your ActiveX component either on its own – whereby you run the
wizard and create a setup program purely for your ActiveX project – or you can distribute
it alongside any applications that use it – simply create a setup for your regular project and
your component will be bundled automatically.
Corr, simple eh?
Where to Go from Here
So you've had a little taste of the COM life and feel it's the route for you?
Well, although we've touched on the most important points – there's plenty more for you
to go at. Most importantly, I'd like you to find out about Collections and how they let
your classes to work together, allowing you to build better, more solid ActiveX
components based on real-life objects.
So where can you go from here?
• Guide to Objects <http://www.vbsquare.com/articles/begobjects/> - Online
Tutorial - Great multi-part guide on how to design and create your own objects in
Visual Basic. By Sam Huggill, VBSquare
• VB COM <http://www.vb-world.net/books/vbcom/> - Book – Neat 350-page
guide to COM. Covers everything from classes through to MTS. Well-written,
fairly compact but a little skimpy in parts. By Thomas Lewis
• Paul Sheriff Videos <http://www.vb-world.net/reviews/sqlvids.html> - Videos
– If you prefer to learn by watching, you might be interested in X video from
Keystone Learning. Nice guide, not thorough but helps clear the mist.
Supplementary manual costs a few dollars extra. By Paul Sheriff, Keystone
Learning
• Professional VB6 Databases <http://www.vb-world.net/books/provb6db/> -
Book - Covers creating professional objects based around a database design. Also
covers lots of database-related whatnots. Excellent mix of content, great for
enterprise work. By Charles Williams
• Murach's Visual Basic 6 <http://www.vb-world.net/books/murach/> -
Beginner's guide to Visual Basic, but rapidly moves onto classes and the like.
Covers a lot in a little, meaning some parts are scantily clad – but on the whole, a
good read.
Well that's about all for this mini-series – so I guess that means it's time to get all
conclusional.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html


Conclusion
Congratulations on completing the COM course!
In this three-part series, we've discovered what COM is, found out how to implement it
with classes and ActiveX components, put together our own database class, uncovered
that mysterious little thing they call asynchronous processing, plus found out where we
can go to take our COM skills even further.
When you get started, you'll find COM to be a great little tool to simplify your
programming. Sure, it might make your life a little more difficult at first – but then it
becomes one heckuva lot easier.
So get using COM in your next application and the best of luck with it!
Until the next time, this is Karl Moore signing off, wishing you all an absolutely supercool
evening and the best programming career a developer could ever hope for. So from me -
Goodnight!

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Das könnte Ihnen auch gefallen